diff --git a/Android.mk b/Android.mk index 9b875d9701dd..581dc1746909 100644 --- a/Android.mk +++ b/Android.mk @@ -3,7 +3,7 @@ MY_LOCAL_PATH := $(call my-dir) UAPI_OUT := $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/include -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660),true) +ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937),true) $(shell mkdir -p $(UAPI_OUT)/linux;) $(shell mkdir -p $(UAPI_OUT)/sound;) $(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/ipc/Module.symvers) @@ -12,6 +12,9 @@ $(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/dsp/codecs $(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/soc/Module.symvers) $(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/Module.symvers) $(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/Module.symvers) +ifeq ($(call is-board-platform-in-list, msm8953 msm8937),true) +$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/Module.symvers) +endif include $(MY_LOCAL_PATH)/include/uapi/Android.mk include $(MY_LOCAL_PATH)/ipc/Android.mk @@ -71,7 +74,7 @@ $(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codec include $(MY_LOCAL_PATH)/asoc/codecs/wsa883x/Android.mk endif -ifeq ($(call is-board-platform-in-list, sdm660),true) +ifeq ($(call is-board-platform-in-list, sdm660 msm8953 msm8937),true) $(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/sdm660_cdc/Module.symvers) $(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/msm_sdw/Module.symvers) include $(MY_LOCAL_PATH)/asoc/codecs/sdm660_cdc/Android.mk diff --git a/Makefile.am b/Makefile.am index b5f37d28bf74..3a7125e90f05 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,6 +20,9 @@ endif ifeq ($(TARGET_SUPPORT),sdm660) KBUILD_OPTIONS += CONFIG_ARCH_SDM660=y endif +ifeq ($(TARGET_SUPPORT),apq8053 msm8953 msm8937) +KBUILD_OPTIONS += CONFIG_ARCH_SDM450=y +endif obj-m := ipc/ obj-m += dsp/ @@ -45,7 +48,7 @@ obj-m += asoc/codecs/bolero/ obj-m += asoc/codecs/wcd938x/ endif -ifeq ($(TARGET_SUPPORT), $(filter $(TARGET_SUPPORT), sdm660)) +ifeq ($(TARGET_SUPPORT), $(filter $(TARGET_SUPPORT), apq8053 sdm660 msm8953 msm8937)) obj-m += asoc/codecs/sdm660_cdc/ endif diff --git a/asoc/Android.mk b/asoc/Android.mk index c6e5a354f0ca..17ca6a7a8950 100644 --- a/asoc/Android.mk +++ b/asoc/Android.mk @@ -46,9 +46,15 @@ TARGET := sdm660 AUDIO_SELECT := CONFIG_SND_SOC_SDM660=m endif +ifeq ($(call is-board-platform-in-list,msm8953 msm8937),true) +TARGET := sdm450 +AUDIO_SELECT += CONFIG_SND_SOC_SDM450=m +AUDIO_SELECT += CONFIG_SND_SOC_EXT_CODEC_SDM450=m +endif + AUDIO_CHIPSET := audio # Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660),true) +ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937),true) LOCAL_PATH := $(call my-dir) @@ -83,7 +89,7 @@ LOCAL_MODULE_DEBUG_ENABLE := true LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) include $(DLKM_DIR)/AndroidKernelModule.mk ########################################################### -ifeq ($(call is-board-platform-in-list, ),true) +ifeq ($(call is-board-platform-in-list, msm8953 msm8937),true) include $(CLEAR_VARS) LOCAL_MODULE := $(AUDIO_CHIPSET)_cpe_lsm.ko LOCAL_MODULE_KBUILD_NAME := cpe_lsm_dlkm.ko @@ -101,6 +107,16 @@ LOCAL_MODULE_DEBUG_ENABLE := true LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) include $(DLKM_DIR)/AndroidKernelModule.mk ########################################################### +ifeq ($(call is-board-platform-in-list,msm8953 msm8937),true) +include $(CLEAR_VARS) +LOCAL_MODULE := $(AUDIO_CHIPSET)_machine_ext_$(TARGET).ko +LOCAL_MODULE_KBUILD_NAME := machine_ext_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/AndroidKernelModule.mk +endif +########################################################### endif # DLKM check endif # supported target check diff --git a/asoc/Kbuild b/asoc/Kbuild index a0d8de1f66e7..e718931c1e8f 100644 --- a/asoc/Kbuild +++ b/asoc/Kbuild @@ -81,6 +81,21 @@ ifeq ($(KERNEL_BUILD), 0) export INCS += -include $(AUDIO_ROOT)/config/sdm660autoconf.h endif + ifeq ($(CONFIG_ARCH_SDM450), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif + ifeq ($(CONFIG_ARCH_SDM439), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif + ifeq ($(CONFIG_ARCH_MSM8917), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif endif # As per target team, build is done as follows: @@ -170,6 +185,17 @@ ifdef CONFIG_SND_SOC_CPE CPE_LSM_OBJS += msm-cpe-lsm.o endif +# for SDM450 internal codec sound card driver +ifdef CONFIG_SND_SOC_SDM450 + MACHINE_OBJS += msm8952.o +endif + +# for SDM450 external codec sound card driver +ifdef CONFIG_SND_SOC_EXT_CODEC_SDM450 + MACHINE_EXT_OBJS += msm8952-slimbus.o + MACHINE_EXT_OBJS += msm8952-dai-links.o +endif + ifdef CONFIG_SND_SOC_QDSP6V2 PLATFORM_OBJS += msm-audio-effects-q6-v2.o PLATFORM_OBJS += msm-compress-q6-v2.o @@ -254,6 +280,12 @@ endif obj-$(CONFIG_SND_SOC_QDSP6V2) += platform_dlkm.o platform_dlkm-y := $(PLATFORM_OBJS) +obj-$(CONFIG_SND_SOC_SDM450) += machine_dlkm.o +machine_dlkm-y := $(MACHINE_OBJS) + +obj-$(CONFIG_SND_SOC_EXT_CODEC_SDM450) += machine_ext_dlkm.o +machine_ext_dlkm-y := $(MACHINE_EXT_OBJS) + obj-$(CONFIG_SND_SOC_SM8150) += machine_dlkm.o machine_dlkm-y := $(MACHINE_OBJS) diff --git a/asoc/codecs/Android.mk b/asoc/codecs/Android.mk index 69200007d093..79e4d7111661 100644 --- a/asoc/codecs/Android.mk +++ b/asoc/codecs/Android.mk @@ -39,9 +39,14 @@ ifeq ($(call is-board-platform,sdm660),true) AUDIO_SELECT := CONFIG_SND_SOC_SDM660=m endif +ifeq ($(call is-board-platform-in-list,msm8953 msm8937),true) +AUDIO_SELECT += CONFIG_SND_SOC_SDM450=m +AUDIO_SELECT += CONFIG_SND_SOC_EXT_CODEC_SDM450=m +endif + AUDIO_CHIPSET := audio # Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660),true) +ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937),true) LOCAL_PATH := $(call my-dir) @@ -85,7 +90,7 @@ LOCAL_MODULE_DEBUG_ENABLE := true LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) include $(DLKM_DIR)/AndroidKernelModule.mk ########################################################### -ifeq ($(call is-board-platform-in-list, ),true) +ifeq ($(call is-board-platform-in-list,msm8953 msm8937),true) include $(CLEAR_VARS) LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd_cpe.ko LOCAL_MODULE_KBUILD_NAME := wcd_cpe_dlkm.ko @@ -105,7 +110,7 @@ LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) include $(DLKM_DIR)/AndroidKernelModule.mk endif ########################################################### -ifeq ($(call is-board-platform-in-list, sdm660),true) +ifeq ($(call is-board-platform-in-list, sdm660 msm8953 msm8937),true) include $(CLEAR_VARS) LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd9335.ko LOCAL_MODULE_KBUILD_NAME := wcd9335_dlkm.ko @@ -125,7 +130,7 @@ LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) include $(DLKM_DIR)/AndroidKernelModule.mk endif ########################################################### -ifeq ($(call is-board-platform-in-list, bengal),true) +ifeq ($(call is-board-platform-in-list, bengal msm8953 msm8937),true) include $(CLEAR_VARS) LOCAL_MODULE := $(AUDIO_CHIPSET)_wsa881x_analog.ko LOCAL_MODULE_KBUILD_NAME := wsa881x_analog_dlkm.ko diff --git a/asoc/codecs/Kbuild b/asoc/codecs/Kbuild index 6dc444290245..9f9e260e19b2 100644 --- a/asoc/codecs/Kbuild +++ b/asoc/codecs/Kbuild @@ -75,6 +75,21 @@ ifeq ($(KERNEL_BUILD), 0) export INCS += -include $(AUDIO_ROOT)/config/sdm660autoconf.h endif + ifeq ($(CONFIG_ARCH_SDM450), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif + ifeq ($(CONFIG_ARCH_SDM439), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif + ifeq ($(CONFIG_ARCH_MSM8917), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif endif # As per target team, build is done as follows: diff --git a/asoc/codecs/msm_sdw/Kbuild b/asoc/codecs/msm_sdw/Kbuild index ccd515d085eb..ea2a9c459941 100644 --- a/asoc/codecs/msm_sdw/Kbuild +++ b/asoc/codecs/msm_sdw/Kbuild @@ -20,6 +20,21 @@ ifeq ($(KERNEL_BUILD), 0) export INCS += -include $(AUDIO_ROOT)/config/sdm660autoconf.h endif + ifeq ($(CONFIG_ARCH_SDM450), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif + ifeq ($(CONFIG_ARCH_SDM439), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif + ifeq ($(CONFIG_ARCH_MSM8917), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif endif # As per target team, build is done as follows: diff --git a/asoc/codecs/sdm660_cdc/Android.mk b/asoc/codecs/sdm660_cdc/Android.mk index ced40f4b3a8b..739ddfa5fc44 100644 --- a/asoc/codecs/sdm660_cdc/Android.mk +++ b/asoc/codecs/sdm660_cdc/Android.mk @@ -4,7 +4,7 @@ AUDIO_CHIPSET := audio # Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list, sdm660),true) +ifeq ($(call is-board-platform-in-list, sdm660 msm8953 msm8937),true) LOCAL_PATH := $(call my-dir) diff --git a/asoc/codecs/sdm660_cdc/Kbuild b/asoc/codecs/sdm660_cdc/Kbuild index c6cf4b705617..d18c01cc8dc1 100644 --- a/asoc/codecs/sdm660_cdc/Kbuild +++ b/asoc/codecs/sdm660_cdc/Kbuild @@ -20,6 +20,21 @@ ifeq ($(KERNEL_BUILD), 0) export INCS += -include $(AUDIO_ROOT)/config/sdm660autoconf.h endif + ifeq ($(CONFIG_ARCH_SDM450), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif + ifeq ($(CONFIG_ARCH_SDM439), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif + ifeq ($(CONFIG_ARCH_MSM8917), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif endif # As per target team, build is done as follows: @@ -58,6 +73,10 @@ ifdef CONFIG_SND_SOC_DIGITAL_CDC DIGITAL_CDC_OBJS += msm-digital-cdc.o DIGITAL_CDC_OBJS += msm-digital-cdc-regmap.o endif +ifdef CONFIG_SND_SOC_DIGITAL_CDC_LEGACY + DIGITAL_CDC_OBJS += msm-digital-cdc-legacy.o + DIGITAL_CDC_OBJS += msm-digital-cdc-legacy-regmap.o +endif LINUX_INC += -Iinclude/linux INCS += $(COMMON_INC) \ @@ -111,5 +130,8 @@ analog_cdc_dlkm-y := $(ANALOG_CDC_OBJS) obj-$(CONFIG_SND_SOC_DIGITAL_CDC) += digital_cdc_dlkm.o digital_cdc_dlkm-y := $(DIGITAL_CDC_OBJS) +obj-$(CONFIG_SND_SOC_DIGITAL_CDC_LEGACY) += digital_cdc_dlkm.o +digital_cdc_dlkm-y := $(DIGITAL_CDC_OBJS) + # inject some build related information DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/asoc/codecs/sdm660_cdc/msm-analog-cdc.h b/asoc/codecs/sdm660_cdc/msm-analog-cdc.h index dbeb76706e31..2f3c8e17fe93 100644 --- a/asoc/codecs/sdm660_cdc/msm-analog-cdc.h +++ b/asoc/codecs/sdm660_cdc/msm-analog-cdc.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2018, 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, 2020-2021, The Linux Foundation. All rights reserved. */ #ifndef MSM_ANALOG_CDC_H #define MSM_ANALOG_CDC_H @@ -227,7 +227,7 @@ extern int msm_anlg_cdc_mclk_enable(struct snd_soc_component *component, extern int msm_anlg_cdc_hs_detect(struct snd_soc_component *component, struct wcd_mbhc_config *mbhc_cfg); extern void msm_anlg_cdc_hs_detect_exit(struct snd_soc_component *component); -extern void sdm660_cdc_update_int_spk_boost(bool enable); +extern void msm_anlg_cdc_update_int_spk_boost(bool enable); extern void msm_anlg_cdc_spk_ext_pa_cb( int (*codec_spk_ext_pa)(struct snd_soc_component *component, int enable), struct snd_soc_component *component); @@ -249,7 +249,7 @@ static inline void msm_anlg_cdc_hs_detect_exit( { } -static inline void sdm660_cdc_update_int_spk_boost(bool enable) +static inline void msm_anlg_cdc_update_int_spk_boost(bool enable) { } diff --git a/asoc/codecs/sdm660_cdc/msm-cdc-common.h b/asoc/codecs/sdm660_cdc/msm-cdc-common.h index ca66de9821f0..6f57af4427ef 100644 --- a/asoc/codecs/sdm660_cdc/msm-cdc-common.h +++ b/asoc/codecs/sdm660_cdc/msm-cdc-common.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2017, 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, 2020-2021, The Linux Foundation. All rights reserved. */ #include @@ -56,5 +56,6 @@ enum dig_cdc_notify_event { DIG_CDC_EVENT_POST_RX2_INT_OFF, DIG_CDC_EVENT_SSR_DOWN, DIG_CDC_EVENT_SSR_UP, + DIG_CDC_EVENT_CAP_CONFIGURE, DIG_CDC_EVENT_LAST, }; diff --git a/asoc/codecs/sdm660_cdc/msm-digital-cdc-legacy-regmap.c b/asoc/codecs/sdm660_cdc/msm-digital-cdc-legacy-regmap.c new file mode 100644 index 000000000000..2a3fd873a131 --- /dev/null +++ b/asoc/codecs/sdm660_cdc/msm-digital-cdc-legacy-regmap.c @@ -0,0 +1,418 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2015-2018, 2021, The Linux Foundation. All rights reserved. + */ + +#include +#include "msm-cdc-common.h" +#include "sdm660-cdc-registers.h" + +/* + * Default register reset values that are common across different versions + * are defined here. If a register reset value is changed based on version + * then remove it from this structure and add it in version specific + * structures. + */ +struct reg_default + msm89xx_cdc_core_defaults[MSM89XX_CDC_CORE_CACHE_SIZE] = { + {MSM89XX_CDC_CORE_CLK_RX_RESET_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x13}, + {MSM89XX_CDC_CORE_CLK_TX_I2S_CTL, 0x13}, + {MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_OTHR_CTL, 0x04}, + {MSM89XX_CDC_CORE_CLK_RX_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_SD_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX1_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX2_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX3_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX1_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX2_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX3_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX1_B3_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX2_B3_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX3_B3_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX1_B4_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX2_B4_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX3_B4_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX1_B5_CTL, 0x68}, + {MSM89XX_CDC_CORE_RX2_B5_CTL, 0x68}, + {MSM89XX_CDC_CORE_RX3_B5_CTL, 0x68}, + {MSM89XX_CDC_CORE_RX1_B6_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX2_B6_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX3_B6_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_TOP_GAIN_UPDATE, 0x00}, + {MSM89XX_CDC_CORE_TOP_CTL, 0x01}, + {MSM89XX_CDC_CORE_COMP0_B1_CTL, 0x30}, + {MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xB5}, + {MSM89XX_CDC_CORE_COMP0_B3_CTL, 0x28}, + {MSM89XX_CDC_CORE_COMP0_B4_CTL, 0x37}, + {MSM89XX_CDC_CORE_COMP0_B5_CTL, 0x7F}, + {MSM89XX_CDC_CORE_COMP0_B6_CTL, 0x00}, + {MSM89XX_CDC_CORE_COMP0_SHUT_DOWN_STATUS, 0x03}, + {MSM89XX_CDC_CORE_COMP0_FS_CFG, 0x03}, + {MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL, 0x02}, + {MSM89XX_CDC_CORE_DEBUG_DESER1_CTL, 0x00}, + {MSM89XX_CDC_CORE_DEBUG_DESER2_CTL, 0x00}, + {MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG, 0x00}, + {MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG, 0x00}, + {MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG, 0x00}, + {MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_CTL, 0x40}, + {MSM89XX_CDC_CORE_IIR2_CTL, 0x40}, + {MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_RX1_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_RX1_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_RX1_B3_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_RX2_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_RX2_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_RX2_B3_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_RX3_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_RX3_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_TX_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_TX_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL, 0x00}, + {MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER, 0x00}, + {MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER, 0x00}, + {MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER, 0x00}, + {MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER, 0x00}, + {MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN, 0x00}, + {MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN, 0x00}, + {MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN, 0x00}, + {MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN, 0x00}, + {MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG, 0x00}, + {MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG, 0x00}, + {MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG, 0x00}, + {MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG, 0x00}, + {MSM89XX_CDC_CORE_TX1_MUX_CTL, 0x00}, + {MSM89XX_CDC_CORE_TX2_MUX_CTL, 0x00}, + {MSM89XX_CDC_CORE_TX3_MUX_CTL, 0x00}, + {MSM89XX_CDC_CORE_TX4_MUX_CTL, 0x00}, + {MSM89XX_CDC_CORE_TX1_CLK_FS_CTL, 0x03}, + {MSM89XX_CDC_CORE_TX2_CLK_FS_CTL, 0x03}, + {MSM89XX_CDC_CORE_TX3_CLK_FS_CTL, 0x03}, + {MSM89XX_CDC_CORE_TX4_CLK_FS_CTL, 0x03}, + {MSM89XX_CDC_CORE_TX1_DMIC_CTL, 0x00}, + {MSM89XX_CDC_CORE_TX2_DMIC_CTL, 0x00}, + {MSM89XX_CDC_CORE_TX3_DMIC_CTL, 0x00}, + {MSM89XX_CDC_CORE_TX4_DMIC_CTL, 0x00}, +}; + +static const u8 msm89xx_cdc_core_reg_readable[MSM89XX_CDC_CORE_CACHE_SIZE] = { + [MSM89XX_CDC_CORE_CLK_RX_RESET_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_RX_I2S_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_TX_I2S_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_OTHR_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_RX_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_MCLK_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_PDM_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_SD_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_RX_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B3_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B3_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B3_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B4_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B4_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B4_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B5_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B5_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B5_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B6_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B6_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B6_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL] = 1, + [MSM89XX_CDC_CORE_TOP_GAIN_UPDATE] = 1, + [MSM89XX_CDC_CORE_TOP_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_B1_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_B2_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_B3_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_B4_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_B5_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_B6_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_SHUT_DOWN_STATUS] = 1, + [MSM89XX_CDC_CORE_COMP0_FS_CFG] = 1, + [MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL] = 1, + [MSM89XX_CDC_CORE_DEBUG_DESER1_CTL] = 1, + [MSM89XX_CDC_CORE_DEBUG_DESER2_CTL] = 1, + [MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX1_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX1_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX1_B3_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX2_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX2_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX2_B3_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX3_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX3_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_TX_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_TX_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL] = 1, + [MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER] = 1, + [MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER] = 1, + [MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER] = 1, + [MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER] = 1, + [MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN] = 1, + [MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN] = 1, + [MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN] = 1, + [MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN] = 1, + [MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_TX1_MUX_CTL] = 1, + [MSM89XX_CDC_CORE_TX2_MUX_CTL] = 1, + [MSM89XX_CDC_CORE_TX3_MUX_CTL] = 1, + [MSM89XX_CDC_CORE_TX4_MUX_CTL] = 1, + [MSM89XX_CDC_CORE_TX1_CLK_FS_CTL] = 1, + [MSM89XX_CDC_CORE_TX2_CLK_FS_CTL] = 1, + [MSM89XX_CDC_CORE_TX3_CLK_FS_CTL] = 1, + [MSM89XX_CDC_CORE_TX4_CLK_FS_CTL] = 1, + [MSM89XX_CDC_CORE_TX1_DMIC_CTL] = 1, + [MSM89XX_CDC_CORE_TX2_DMIC_CTL] = 1, + [MSM89XX_CDC_CORE_TX3_DMIC_CTL] = 1, + [MSM89XX_CDC_CORE_TX4_DMIC_CTL] = 1, +}; + +static const u8 msm89xx_cdc_core_reg_writeable[MSM89XX_CDC_CORE_CACHE_SIZE] = { + [MSM89XX_CDC_CORE_CLK_RX_RESET_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_RX_I2S_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_TX_I2S_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_OTHR_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_RX_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_MCLK_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_PDM_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_SD_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_RX_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B3_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B3_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B3_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B4_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B4_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B4_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B5_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B5_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B5_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B6_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B6_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B6_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL] = 1, + [MSM89XX_CDC_CORE_TOP_GAIN_UPDATE] = 1, + [MSM89XX_CDC_CORE_TOP_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_B1_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_B2_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_B3_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_B4_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_B5_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_B6_CTL] = 1, + [MSM89XX_CDC_CORE_COMP0_FS_CFG] = 1, + [MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL] = 1, + [MSM89XX_CDC_CORE_DEBUG_DESER1_CTL] = 1, + [MSM89XX_CDC_CORE_DEBUG_DESER2_CTL] = 1, + [MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX1_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX1_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX1_B3_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX2_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX2_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX2_B3_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX3_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX3_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_TX_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_TX_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL] = 1, + [MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER] = 1, + [MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER] = 1, + [MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER] = 1, + [MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER] = 1, + [MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN] = 1, + [MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN] = 1, + [MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN] = 1, + [MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN] = 1, + [MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_TX1_MUX_CTL] = 1, + [MSM89XX_CDC_CORE_TX2_MUX_CTL] = 1, + [MSM89XX_CDC_CORE_TX3_MUX_CTL] = 1, + [MSM89XX_CDC_CORE_TX4_MUX_CTL] = 1, + [MSM89XX_CDC_CORE_TX1_CLK_FS_CTL] = 1, + [MSM89XX_CDC_CORE_TX2_CLK_FS_CTL] = 1, + [MSM89XX_CDC_CORE_TX3_CLK_FS_CTL] = 1, + [MSM89XX_CDC_CORE_TX4_CLK_FS_CTL] = 1, + [MSM89XX_CDC_CORE_TX1_DMIC_CTL] = 1, + [MSM89XX_CDC_CORE_TX2_DMIC_CTL] = 1, + [MSM89XX_CDC_CORE_TX3_DMIC_CTL] = 1, + [MSM89XX_CDC_CORE_TX4_DMIC_CTL] = 1, +}; + +bool msm89xx_cdc_core_readable_reg(struct device *dev, unsigned int reg) +{ + return msm89xx_cdc_core_reg_readable[reg]; +} + +bool msm89xx_cdc_core_writeable_reg(struct device *dev, unsigned int reg) +{ + return msm89xx_cdc_core_reg_writeable[reg]; +} + +bool msm89xx_cdc_core_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MSM89XX_CDC_CORE_RX1_B1_CTL: + case MSM89XX_CDC_CORE_RX2_B1_CTL: + case MSM89XX_CDC_CORE_RX3_B1_CTL: + case MSM89XX_CDC_CORE_RX1_B6_CTL: + case MSM89XX_CDC_CORE_RX2_B6_CTL: + case MSM89XX_CDC_CORE_RX3_B6_CTL: + case MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG: + case MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG: + case MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG: + case MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG: + case MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL: + case MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL: + case MSM89XX_CDC_CORE_CLK_MCLK_CTL: + case MSM89XX_CDC_CORE_CLK_PDM_CTL: + return true; + default: + return false; + } +} diff --git a/asoc/codecs/sdm660_cdc/msm-digital-cdc-legacy.c b/asoc/codecs/sdm660_cdc/msm-digital-cdc-legacy.c new file mode 100644 index 000000000000..4748fba075e5 --- /dev/null +++ b/asoc/codecs/sdm660_cdc/msm-digital-cdc-legacy.c @@ -0,0 +1,2633 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2018-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 "sdm660-cdc-registers.h" +#include "msm-digital-cdc.h" +#include "msm-cdc-common.h" +#include "../../msm8952.h" + +#define DRV_NAME "msm_digital_codec" +#define MCLK_RATE_9P6MHZ 9600000 +#define MCLK_RATE_12P288MHZ 12288000 +#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30 +#define CF_MIN_3DB_4HZ 0x0 +#define CF_MIN_3DB_75HZ 0x1 +#define CF_MIN_3DB_150HZ 0x2 + +#define MSM_DIG_CDC_VERSION_ENTRY_SIZE 32 +#define MAX_ON_DEMAND_DIG_SUPPLY_NAME_LENGTH 64 +#define CODEC_DT_MAX_PROP_SIZE 40 + +/* + * 200 Milliseconds sufficient for DSP bring up in the lpass + * after Sub System Restart + */ +#define ADSP_STATE_READY_TIMEOUT_MS 200 + +static unsigned long rx_digital_gain_reg[] = { + MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL, + MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL, + MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL, +}; + +static unsigned long tx_digital_gain_reg[] = { + MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN, + MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN, + MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN, + MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN, +}; + +#define SDM660_TX_UNMUTE_DELAY_MS 40 +static int tx_unmute_delay = SDM660_TX_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); + +struct snd_soc_component *registered_digcodec; +struct hpf_work tx_hpf_work[NUM_DECIMATORS]; + +static int msm_dig_cdc_enable_on_demand_supply( + struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event); +static char on_demand_supply_name[][MAX_ON_DEMAND_DIG_SUPPLY_NAME_LENGTH] = { + "cdc-vdd-digital", +}; +/* Codec supports 2 IIR filters */ +enum { + IIR1 = 0, + IIR2, + IIR_MAX, +}; + +/* + * msm_digcdc_mclk_enable - add mclk support in digital codec + * @codec: codec instance + * @mclk_enable: mclk enable/disable + * @dapm: check for dapm widget + */ +int msm_digcdc_mclk_enable(struct snd_soc_component *component, + int mclk_enable, bool dapm) +{ + dev_dbg(component->dev, "%s: mclk_enable = %u, dapm = %d\n", + __func__, mclk_enable, dapm); + if (mclk_enable) { + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x01, 0x01); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_TOP_CTL, 0x01, 0x01); + } else { + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_TOP_CTL, 0x01, 0x00); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x01, 0x00); + } + + return 0; +} +EXPORT_SYMBOL(msm_digcdc_mclk_enable); + +static int msm_digcdc_clock_control(bool flag) +{ + int ret = -EINVAL; + struct msm_asoc_mach_data *pdata = NULL; + struct msm_dig_priv *msm_dig_cdc = + snd_soc_component_get_drvdata(registered_digcodec); + + pdata = snd_soc_card_get_drvdata(registered_digcodec->card); + + if (flag) { + mutex_lock(&pdata->cdc_int_mclk0_mutex); + if (atomic_read(&pdata->int_mclk0_enabled) == false) { + if (msm_dig_cdc->regmap->cache_only == true) + return ret; + pdata->digital_cdc_core_clk.clk_freq_in_hz = + DEFAULT_MCLK_RATE; + pdata->digital_cdc_core_clk.enable = 1; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_PRIMARY_MI2S_RX, + &pdata->digital_cdc_core_clk); + if (ret < 0) { + pr_err("%s:failed to enable the MCLK\n", + __func__); + /* + * Avoid access to lpass register + * as clock enable failed during SSR. + */ + msm_dig_cdc->regmap->cache_only = true; + return ret; + } + pr_debug("enabled digital codec core clk\n"); + atomic_set(&pdata->int_mclk0_enabled, true); + schedule_delayed_work(&pdata->disable_int_mclk0_work, + 50); + } + } else { + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + dev_dbg(registered_digcodec->dev, + "disable MCLK, workq to disable set already\n"); + } + return 0; +} + +static void enable_digital_callback(void *flag) +{ + msm_digcdc_clock_control(true); +} + +static void disable_digital_callback(void *flag) +{ + msm_digcdc_clock_control(false); + pr_debug("disable mclk happens in workq\n"); +} + +static int msm_dig_cdc_put_dec_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int dec_mux, decimator; + char *dec_name = NULL; + char *widget_name = NULL; + char *temp; + u16 tx_mux_ctl_reg; + u8 adc_dmic_sel = 0x0; + int ret = 0; + char *dec_num; + + if (ucontrol->value.enumerated.item[0] > e->items) { + dev_err(component->dev, "%s: Invalid enum value: %d\n", + __func__, ucontrol->value.enumerated.item[0]); + return -EINVAL; + } + dec_mux = ucontrol->value.enumerated.item[0]; + + widget_name = kstrndup(w->name, 15, GFP_KERNEL); + if (!widget_name) { + dev_err(component->dev, "%s: failed to copy string\n", + __func__); + return -ENOMEM; + } + temp = widget_name; + + dec_name = strsep(&widget_name, " "); + widget_name = temp; + if (!dec_name) { + dev_err(component->dev, "%s: Invalid decimator = %s\n", + __func__, w->name); + ret = -EINVAL; + goto out; + } + + dec_num = strpbrk(dec_name, "12"); + if (dec_num == NULL) { + dev_err(component->dev, "%s: Invalid DEC selected\n", __func__); + ret = -EINVAL; + goto out; + } + + ret = kstrtouint(dec_num, 10, &decimator); + if (ret < 0) { + dev_err(component->dev, "%s: Invalid decimator = %s\n", + __func__, dec_name); + ret = -EINVAL; + goto out; + } + + dev_dbg(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n" + , __func__, w->name, decimator, dec_mux); + + switch (decimator) { + case 1: + case 2: + if ((dec_mux == 4) || (dec_mux == 5)) + adc_dmic_sel = 0x1; + else + adc_dmic_sel = 0x0; + break; + default: + dev_err(component->dev, "%s: Invalid Decimator = %u\n", + __func__, decimator); + ret = -EINVAL; + goto out; + } + + tx_mux_ctl_reg = + MSM89XX_CDC_CORE_TX1_MUX_CTL + 32 * (decimator - 1); + + snd_soc_component_update_bits(component, tx_mux_ctl_reg, 0x1, + adc_dmic_sel); + + ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); + +out: + kfree(widget_name); + return ret; +} + + +static int msm_dig_cdc_codec_config_compander( + struct snd_soc_component *component, + int interp_n, int event) +{ + struct msm_dig_priv *dig_cdc = snd_soc_component_get_drvdata(component); + int comp_ch_bits_set = 0x03; + int comp_ch_value; + + dev_dbg(component->dev, "%s: event %d shift %d, enabled %d\n", + __func__, event, interp_n, + dig_cdc->comp_enabled[interp_n]); + + /* compander is invalid */ + if (dig_cdc->comp_enabled[interp_n] != COMPANDER_1 && + dig_cdc->comp_enabled[interp_n]) { + dev_dbg(component->dev, "%s: Invalid compander %d\n", __func__, + dig_cdc->comp_enabled[interp_n]); + return 0; + } + + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* compander is not enabled */ + if (!dig_cdc->comp_enabled[interp_n]) { + dig_cdc->set_compander_mode(dig_cdc->handle, 0x00); + return 0; + }; + comp_ch_value = snd_soc_component_read32(component, + MSM89XX_CDC_CORE_COMP0_B1_CTL); + if (interp_n == 0) { + if (comp_ch_value & 0x02) { + dev_dbg(component->dev, + "%s comp ch 1 already enabled\n", + __func__); + return 0; + } + } + if (interp_n == 1) { + if (comp_ch_value & 0x01) { + dev_dbg(component->dev, + "%s comp ch 0 already enabled\n", + __func__); + return 0; + } + } + dig_cdc->set_compander_mode(dig_cdc->handle, 0x08); + /* Enable Compander Clock */ + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x09); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x01); + if (dig_cdc->comp_enabled[MSM89XX_RX1]) { + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_COMP0_B1_CTL, + 0x02, 0x02); + } + if (dig_cdc->comp_enabled[MSM89XX_RX2]) { + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_COMP0_B1_CTL, + 0x01, 0x01); + } + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x01); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0x50); + /* add sleep for compander to settle */ + usleep_range(1000, 1100); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x28); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0xB0); + + /* Enable Compander GPIO */ + if (dig_cdc->codec_hph_comp_gpio) + dig_cdc->codec_hph_comp_gpio(1, component); + } else if (SND_SOC_DAPM_EVENT_OFF(event)) { + /* Disable Compander GPIO */ + if (dig_cdc->codec_hph_comp_gpio) + dig_cdc->codec_hph_comp_gpio(0, component); + + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_COMP0_B1_CTL, + 1 << interp_n, 0); + comp_ch_bits_set = snd_soc_component_read32(component, + MSM89XX_CDC_CORE_COMP0_B1_CTL); + if ((comp_ch_bits_set & 0x03) == 0x00) { + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x05); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x00); + } + } + return 0; +} + +/** + * msm_dig_cdc_hph_comp_cb - registers callback to codec by machine driver. + * + * @codec_hph_comp_gpio: function pointer to set comp gpio at machine driver + * @codec: codec pointer + * + */ +void msm_dig_cdc_hph_comp_cb(int (*codec_hph_comp_gpio)(bool enable, + struct snd_soc_component *component), + struct snd_soc_component *component) +{ + struct msm_dig_priv *dig_cdc = snd_soc_component_get_drvdata(component); + + pr_debug("%s: Enter\n", __func__); + dig_cdc->codec_hph_comp_gpio = codec_hph_comp_gpio; +} +EXPORT_SYMBOL(msm_dig_cdc_hph_comp_cb); + +static int msm_dig_cdc_codec_enable_interpolator(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct msm_dig_priv *msm_dig_cdc = + snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name); + + if (w->shift >= MSM89XX_RX_MAX || w->shift < 0) { + dev_err(component->dev, "%s: wrong RX index: %d\n", + __func__, w->shift); + return -EINVAL; + } + switch (event) { + case SND_SOC_DAPM_POST_PMU: + msm_dig_cdc_codec_config_compander(component, w->shift, event); + /* apply the digital gain after the interpolator is enabled*/ + if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg)) + snd_soc_component_write(component, + rx_digital_gain_reg[w->shift], + snd_soc_component_read32(component, + rx_digital_gain_reg[w->shift]) + ); + break; + case SND_SOC_DAPM_POST_PMD: + msm_dig_cdc_codec_config_compander(component, w->shift, event); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_CLK_RX_RESET_CTL, + 1 << w->shift, 1 << w->shift); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_CLK_RX_RESET_CTL, + 1 << w->shift, 0x0); + /* + * disable the mute enabled during the PMD of this device + */ + if ((w->shift == 0) && + (msm_dig_cdc->mute_mask & HPHL_PA_DISABLE)) { + pr_debug("disabling HPHL mute\n"); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00); + msm_dig_cdc->mute_mask &= ~(HPHL_PA_DISABLE); + } else if ((w->shift == 1) && + (msm_dig_cdc->mute_mask & HPHR_PA_DISABLE)) { + pr_debug("disabling HPHR mute\n"); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x00); + msm_dig_cdc->mute_mask &= ~(HPHR_PA_DISABLE); + } else if ((w->shift == 2) && + (msm_dig_cdc->mute_mask & SPKR_PA_DISABLE)) { + pr_debug("disabling SPKR mute\n"); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00); + msm_dig_cdc->mute_mask &= ~(SPKR_PA_DISABLE); + } + } + return 0; +} + +static int msm_dig_cdc_get_iir_enable_audio_mixer( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_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] = + (snd_soc_component_read32(component, + (MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx)) & + (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 msm_dig_cdc_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; + int value = ucontrol->value.integer.value[0]; + + /* Mask first 5 bits, 6-8 are reserved */ + snd_soc_component_update_bits(component, + (MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx), + (1 << band_idx), (value << band_idx)); + + dev_dbg(component->dev, "%s: IIR #%d band #%d enable %d\n", __func__, + iir_idx, band_idx, + ((snd_soc_component_read32(component, + (MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx)) & + (1 << band_idx)) != 0)); + + 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, + (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t)) & 0x7F); + + value |= snd_soc_component_read32(component, + (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx)); + + snd_soc_component_write(component, + (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 1) & 0x7F); + + value |= (snd_soc_component_read32(component, + (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 8); + + snd_soc_component_write(component, + (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 2) & 0x7F); + + value |= (snd_soc_component_read32(component, + (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 16); + + snd_soc_component_write(component, + (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 3) & 0x7F); + + /* Mask bits top 2 bits since they are reserved */ + value |= ((snd_soc_component_read32(component, + (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx)) & 0x3f) + << 24); + + return value; + +} + +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, + (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx), + (value & 0xFF)); + + snd_soc_component_write(component, + (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx), + (value >> 8) & 0xFF); + + snd_soc_component_write(component, + (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx), + (value >> 16) & 0xFF); + + /* Mask top 2 bits, 7-8 are reserved */ + snd_soc_component_write(component, + (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx), + (value >> 24) & 0x3F); + +} + +static int msm_dig_cdc_get_iir_band_audio_mixer( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_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 int msm_dig_cdc_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, + (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * 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]); + + 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, + 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 void tx_hpf_corner_freq_callback(struct work_struct *work) +{ + struct delayed_work *hpf_delayed_work; + struct hpf_work *hpf_work; + struct snd_soc_component *component; + struct msm_dig_priv *msm_dig_cdc; + u16 tx_mux_ctl_reg; + u8 hpf_cut_of_freq; + + hpf_delayed_work = to_delayed_work(work); + hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork); + component = hpf_work->dig_cdc->component; + msm_dig_cdc = hpf_work->dig_cdc; + hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq; + + tx_mux_ctl_reg = MSM89XX_CDC_CORE_TX1_MUX_CTL + + (hpf_work->decimator - 1) * 32; + + dev_dbg(component->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n", + __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq); + if (msm_dig_cdc->update_clkdiv) + msm_dig_cdc->update_clkdiv(msm_dig_cdc->handle, 0x51); + + snd_soc_component_update_bits(component, + tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4); +} + +static int msm_dig_cdc_codec_set_iir_gain(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + int value = 0, reg; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (w->shift == 0) + reg = MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL; + else if (w->shift == 1) + reg = MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL; + else + goto ret; + value = snd_soc_component_read32(component, reg); + snd_soc_component_write(component, reg, value); + break; + default: + pr_err("%s: event = %d not expected\n", __func__, event); + } +ret: + return 0; +} + +static int msm_dig_cdc_compander_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct msm_dig_priv *dig_cdc = + snd_soc_component_get_drvdata(component); + int comp_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int rx_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + dev_dbg(component->dev, "%s: msm_dig_cdc->comp[%d]_enabled[%d] = %d\n", + __func__, comp_idx, rx_idx, + dig_cdc->comp_enabled[rx_idx]); + + ucontrol->value.integer.value[0] = dig_cdc->comp_enabled[rx_idx]; + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int msm_dig_cdc_compander_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct msm_dig_priv *dig_cdc = snd_soc_component_get_drvdata(component); + int comp_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int rx_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + if (dig_cdc->version >= DIANGU) { + if (!value) + dig_cdc->comp_enabled[rx_idx] = 0; + else + dig_cdc->comp_enabled[rx_idx] = comp_idx; + } + + dev_dbg(component->dev, "%s: msm_dig_cdc->comp[%d]_enabled[%d] = %d\n", + __func__, comp_idx, rx_idx, + dig_cdc->comp_enabled[rx_idx]); + + return 0; +} + +static const struct snd_kcontrol_new compander_kcontrols[] = { + SOC_SINGLE_EXT("COMP0 RX1", COMPANDER_1, MSM89XX_RX1, 1, 0, + msm_dig_cdc_compander_get, msm_dig_cdc_compander_set), + + SOC_SINGLE_EXT("COMP0 RX2", COMPANDER_1, MSM89XX_RX2, 1, 0, + msm_dig_cdc_compander_get, msm_dig_cdc_compander_set), + +}; + +static int msm_dig_cdc_set_interpolator_rate(struct snd_soc_dai *dai, + u8 rx_fs_rate_reg_val, + u32 sample_rate) +{ + snd_soc_component_update_bits(dai->component, + MSM89XX_CDC_CORE_RX1_B5_CTL, 0xF0, rx_fs_rate_reg_val); + snd_soc_component_update_bits(dai->component, + MSM89XX_CDC_CORE_RX2_B5_CTL, 0xF0, rx_fs_rate_reg_val); + return 0; +} + +static int msm_dig_cdc_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + u8 tx_fs_rate, rx_fs_rate, rx_clk_fs_rate; + int ret; + + dev_dbg(dai->component->dev, + "%s: dai_name = %s DAI-ID %x rate %d num_ch %d format %d\n", + __func__, dai->name, dai->id, params_rate(params), + params_channels(params), params_format(params)); + + switch (params_rate(params)) { + case 8000: + tx_fs_rate = 0x00; + rx_fs_rate = 0x00; + rx_clk_fs_rate = 0x00; + break; + case 16000: + tx_fs_rate = 0x20; + rx_fs_rate = 0x20; + rx_clk_fs_rate = 0x01; + break; + case 32000: + tx_fs_rate = 0x40; + rx_fs_rate = 0x40; + rx_clk_fs_rate = 0x02; + break; + case 44100: + case 48000: + tx_fs_rate = 0x60; + rx_fs_rate = 0x60; + rx_clk_fs_rate = 0x03; + break; + case 96000: + tx_fs_rate = 0x80; + rx_fs_rate = 0x80; + rx_clk_fs_rate = 0x04; + break; + case 192000: + tx_fs_rate = 0xA0; + rx_fs_rate = 0xA0; + rx_clk_fs_rate = 0x05; + break; + default: + dev_err(dai->component->dev, + "%s: Invalid sampling rate %d\n", __func__, + params_rate(params)); + return -EINVAL; + } + + snd_soc_component_update_bits(dai->component, + MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x0F, rx_clk_fs_rate); + + switch (substream->stream) { + case SNDRV_PCM_STREAM_CAPTURE: + break; + case SNDRV_PCM_STREAM_PLAYBACK: + ret = msm_dig_cdc_set_interpolator_rate(dai, rx_fs_rate, + params_rate(params)); + if (ret < 0) { + dev_err(dai->component->dev, + "%s: set decimator rate failed %d\n", __func__, + ret); + return ret; + } + break; + default: + dev_err(dai->component->dev, + "%s: Invalid stream type %d\n", __func__, + substream->stream); + return -EINVAL; + } + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + snd_soc_component_update_bits(dai->component, + MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x20, 0x20); + break; + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S24_3LE: + snd_soc_component_update_bits(dai->component, + MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x20, 0x00); + break; + default: + dev_err(dai->component->dev, "%s: wrong format selected\n", + __func__); + return -EINVAL; + } + return 0; +} + +static int msm_dig_cdc_codec_enable_dmic(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct msm_dig_priv *dig_cdc = snd_soc_component_get_drvdata(component); + u8 dmic_clk_en; + u16 dmic_clk_reg; + s32 *dmic_clk_cnt; + unsigned int dmic; + int ret; + char *dmic_num = strpbrk(w->name, "12"); + + if (dmic_num == NULL) { + dev_err(component->dev, "%s: Invalid DMIC\n", __func__); + return -EINVAL; + } + + ret = kstrtouint(dmic_num, 10, &dmic); + if (ret < 0) { + dev_err(component->dev, + "%s: Invalid DMIC line on the codec\n", __func__); + return -EINVAL; + } + + switch (dmic) { + case 1: + case 2: + dmic_clk_en = 0x01; + dmic_clk_cnt = &(dig_cdc->dmic_1_2_clk_cnt); + dmic_clk_reg = MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL; + dev_dbg(component->dev, + "%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n", + __func__, event, dmic, *dmic_clk_cnt); + break; + default: + dev_err(component->dev, + "%s: Invalid DMIC Selection\n", __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + (*dmic_clk_cnt)++; + if (*dmic_clk_cnt == 1) { + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x0E, 0x04); + snd_soc_component_update_bits(component, dmic_clk_reg, + dmic_clk_en, dmic_clk_en); + } + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_TX1_DMIC_CTL + (dmic - 1) * 0x20, + 0x07, 0x02); + break; + case SND_SOC_DAPM_POST_PMD: + (*dmic_clk_cnt)--; + if (*dmic_clk_cnt == 0) + snd_soc_component_update_bits(component, dmic_clk_reg, + dmic_clk_en, 0); + break; + } + return 0; +} + +static int msm_dig_cdc_codec_enable_dec(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct msm_asoc_mach_data *pdata = NULL; + unsigned int decimator; + struct msm_dig_priv *msm_dig_cdc = + snd_soc_component_get_drvdata(component); + char *dec_name = NULL; + char *widget_name = NULL; + char *temp; + int ret = 0, i; + u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg; + u8 dec_hpf_cut_of_freq; + int offset; + char *dec_num; + + pdata = snd_soc_card_get_drvdata(component->card); + dev_dbg(component->dev, "%s %d\n", __func__, event); + + widget_name = kstrndup(w->name, 15, GFP_KERNEL); + if (!widget_name) + return -ENOMEM; + temp = widget_name; + + dec_name = strsep(&widget_name, " "); + widget_name = temp; + if (!dec_name) { + dev_err(component->dev, + "%s: Invalid decimator = %s\n", __func__, w->name); + ret = -EINVAL; + goto out; + } + + dec_num = strpbrk(dec_name, "1234"); + if (dec_num == NULL) { + dev_err(component->dev, "%s: Invalid Decimator\n", __func__); + ret = -EINVAL; + goto out; + } + + ret = kstrtouint(dec_num, 10, &decimator); + if (ret < 0) { + dev_err(component->dev, + "%s: Invalid decimator = %s\n", __func__, dec_name); + ret = -EINVAL; + goto out; + } + + dev_dbg(component->dev, + "%s(): widget = %s dec_name = %s decimator = %u\n", __func__, + w->name, dec_name, decimator); + + if (w->reg == MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL) { + dec_reset_reg = MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL; + offset = 0; + } else { + dev_err(component->dev, "%s: Error, incorrect dec\n", __func__); + ret = -EINVAL; + goto out; + } + + tx_vol_ctl_reg = MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG + + 32 * (decimator - 1); + tx_mux_ctl_reg = MSM89XX_CDC_CORE_TX1_MUX_CTL + + 32 * (decimator - 1); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (decimator == 3 || decimator == 4) { + /* for WSA_VI */ + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL, + 0xFF, 0x5); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_TX1_DMIC_CTL + + (decimator - 1) * 0x20, 0x7, 0x2); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_TX1_DMIC_CTL + + (decimator - 1) * 0x20, 0x7, 0x2); + } + /* Enableable TX digital mute */ + snd_soc_component_update_bits(component, + tx_vol_ctl_reg, 0x01, 0x01); + for (i = 0; i < NUM_DECIMATORS; i++) { + if (decimator == i + 1) + msm_dig_cdc->dec_active[i] = true; + } + + dec_hpf_cut_of_freq = snd_soc_component_read32(component, + tx_mux_ctl_reg); + + dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4; + + tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq = + dec_hpf_cut_of_freq; + + if (dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ) { + + /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */ + snd_soc_component_update_bits(component, + tx_mux_ctl_reg, 0x30, CF_MIN_3DB_150HZ << 4); + } + if (msm_dig_cdc->update_clkdiv) + msm_dig_cdc->update_clkdiv(msm_dig_cdc->handle, 0x42); + break; + case SND_SOC_DAPM_POST_PMU: + /* enable HPF */ + snd_soc_component_update_bits(component, tx_mux_ctl_reg, + 0x08, 0x00); + + schedule_delayed_work( + &msm_dig_cdc->tx_mute_dwork[decimator - 1].dwork, + msecs_to_jiffies(tx_unmute_delay)); + if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq != + CF_MIN_3DB_150HZ) { + + schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork, + msecs_to_jiffies(300)); + } + /* apply the digital gain after the decimator is enabled*/ + if ((w->shift) < ARRAY_SIZE(tx_digital_gain_reg)) + snd_soc_component_write(component, + tx_digital_gain_reg[w->shift + offset], + snd_soc_component_read32(component, + tx_digital_gain_reg[w->shift + offset]) + ); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x01, 0x01); + msleep(20); + snd_soc_component_update_bits(component, tx_mux_ctl_reg, + 0x08, 0x08); + cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork); + cancel_delayed_work_sync( + &msm_dig_cdc->tx_mute_dwork[decimator - 1].dwork); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + dec_reset_reg, 1 << w->shift, 1 << w->shift); + snd_soc_component_update_bits(component, + dec_reset_reg, 1 << w->shift, 0x0); + snd_soc_component_update_bits(component, + tx_mux_ctl_reg, 0x08, 0x08); + snd_soc_component_update_bits(component, tx_mux_ctl_reg, 0x30, + (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4); + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x01, 0x00); + for (i = 0; i < NUM_DECIMATORS; i++) { + if (decimator == i + 1) + msm_dig_cdc->dec_active[i] = false; + } + if (decimator == 3 || decimator == 4) { + /* for WSA_VI */ + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL, + 0xFF, 0x0); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_TX1_DMIC_CTL + + (decimator - 1) * 0x20, 0x7, 0x0); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_TX1_DMIC_CTL + + (decimator - 1) * 0x20, 0x7, 0x0); + } + break; + } +out: + kfree(widget_name); + return ret; +} + +static int msm_dig_cdc_event_notify(struct notifier_block *block, + unsigned long val, + void *data) +{ + enum dig_cdc_notify_event event = (enum dig_cdc_notify_event)val; + struct snd_soc_component *component = registered_digcodec; + struct msm_dig_priv *msm_dig_cdc = + snd_soc_component_get_drvdata(component); + struct msm_asoc_mach_data *pdata = NULL; + int ret = -EINVAL; + struct msm_cap_mode *capmode = NULL; + + pdata = snd_soc_card_get_drvdata(component->card); + + switch (event) { + case DIG_CDC_EVENT_CLK_ON: + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x03, 0x03); + if (pdata->mclk_freq == MCLK_RATE_9P6MHZ) + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_TOP_CTL, 0x01, 0x01); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x01, 0x01); + break; + case DIG_CDC_EVENT_CLK_OFF: + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x03, 0x00); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x01, 0x00); + break; + case DIG_CDC_EVENT_RX1_MUTE_ON: + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x01); + msm_dig_cdc->mute_mask |= HPHL_PA_DISABLE; + break; + case DIG_CDC_EVENT_RX1_MUTE_OFF: + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00); + msm_dig_cdc->mute_mask &= (~HPHL_PA_DISABLE); + break; + case DIG_CDC_EVENT_RX2_MUTE_ON: + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x01); + msm_dig_cdc->mute_mask |= HPHR_PA_DISABLE; + break; + case DIG_CDC_EVENT_RX2_MUTE_OFF: + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x00); + msm_dig_cdc->mute_mask &= (~HPHR_PA_DISABLE); + break; + case DIG_CDC_EVENT_RX3_MUTE_ON: + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x01); + msm_dig_cdc->mute_mask |= SPKR_PA_DISABLE; + break; + case DIG_CDC_EVENT_RX3_MUTE_OFF: + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00); + msm_dig_cdc->mute_mask &= (~SPKR_PA_DISABLE); + break; + case DIG_CDC_EVENT_PRE_RX1_INT_ON: + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX1_B3_CTL, 0x3C, 0x28); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0x10); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX1_B3_CTL, 0x80, 0x80); + break; + case DIG_CDC_EVENT_PRE_RX2_INT_ON: + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX2_B3_CTL, 0x3C, 0x28); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0x10); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX2_B3_CTL, 0x80, 0x80); + break; + case DIG_CDC_EVENT_POST_RX1_INT_OFF: + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX1_B3_CTL, 0x3C, 0x00); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0xFF); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX1_B3_CTL, 0x80, 0x00); + break; + case DIG_CDC_EVENT_POST_RX2_INT_OFF: + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX2_B3_CTL, 0x3C, 0x00); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0xFF); + snd_soc_component_update_bits(component, + MSM89XX_CDC_CORE_RX2_B3_CTL, 0x80, 0x00); + break; + case DIG_CDC_EVENT_SSR_DOWN: + regcache_cache_only(msm_dig_cdc->regmap, true); + mutex_lock(&pdata->cdc_int_mclk0_mutex); + atomic_set(&pdata->int_mclk0_enabled, false); + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + break; + case DIG_CDC_EVENT_SSR_UP: + regcache_cache_only(msm_dig_cdc->regmap, false); + regcache_mark_dirty(msm_dig_cdc->regmap); + + mutex_lock(&pdata->cdc_int_mclk0_mutex); + pdata->digital_cdc_core_clk.enable = 1; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_PRIMARY_MI2S_RX, + &pdata->digital_cdc_core_clk); + if (ret < 0) { + pr_err("%s:failed to enable the MCLK\n", + __func__); + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + break; + } + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + + regcache_sync(msm_dig_cdc->regmap); + + mutex_lock(&pdata->cdc_int_mclk0_mutex); + pdata->digital_cdc_core_clk.enable = 0; + afe_set_lpass_clock_v2( + AFE_PORT_ID_PRIMARY_MI2S_RX, + &pdata->digital_cdc_core_clk); + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + break; + case DIG_CDC_EVENT_CAP_CONFIGURE: + capmode = (struct msm_cap_mode *)data; + capmode->micbias1_cap_mode = pdata->micbias1_cap_mode; + capmode->micbias2_cap_mode = pdata->micbias2_cap_mode; + break; + case DIG_CDC_EVENT_INVALID: + default: + break; + } + return 0; +} + +static ssize_t msm_dig_codec_version_read(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, + char __user *buf, size_t count, + loff_t pos) +{ + struct msm_dig_priv *msm_dig; + char buffer[MSM_DIG_CDC_VERSION_ENTRY_SIZE]; + int len = 0; + + msm_dig = (struct msm_dig_priv *) entry->private_data; + if (!msm_dig) { + pr_err("%s: msm_dig priv is null\n", __func__); + return -EINVAL; + } + + switch (msm_dig->version) { + case DRAX_CDC: + case DIANGU: + case CAJON_2_0: + case CAJON: + case CONGA: + case TOMBAK_2_0: + case TOMBAK_1_0: + len = snprintf(buffer, sizeof(buffer), "SDM660-CDC_1_0\n"); + break; + default: + len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n"); + } + + return simple_read_from_buffer(buf, count, &pos, buffer, len); +} + +static struct snd_info_entry_ops msm_dig_codec_info_ops = { + .read = msm_dig_codec_version_read, +}; + +static int digt_cdc_notifer_service_cb(struct notifier_block *nb, + unsigned long opcode, void *ptr) +{ + struct msm_dig_priv *dig_cdc_priv = container_of(nb, + struct msm_dig_priv, + service_nb); + struct snd_soc_component *component = dig_cdc_priv->component; + bool adsp_ready = false; + unsigned long timeout; + int ret; + static bool initial_boot = true; + struct msm_asoc_mach_data *pdata = NULL; + struct audio_notifier_cb_data *cb_data = ptr; + struct msm_dig_priv *msm_dig_cdc = + snd_soc_component_get_drvdata(component); + + pdata = snd_soc_card_get_drvdata(component->card); + pr_debug("%s: opcode 0x%lx, service=%d\n", __func__, opcode, + cb_data->service); + + switch (opcode) { + case AUDIO_NOTIFIER_SERVICE_DOWN: + if (initial_boot && + cb_data->service == AUDIO_NOTIFIER_PDR_SERVICE) { + initial_boot = false; + break; + } + dev_dbg(component->dev, + "ADSP is about to power down. teardown/reset codec\n"); + + regcache_cache_only(msm_dig_cdc->regmap, true); + mutex_lock(&pdata->cdc_int_mclk0_mutex); + atomic_set(&pdata->int_mclk0_enabled, false); + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + snd_soc_card_change_online_state(component->card, 0); + break; + + case AUDIO_NOTIFIER_SERVICE_UP: + if (initial_boot && + cb_data->service == AUDIO_NOTIFIER_PDR_SERVICE) + initial_boot = false; + dev_dbg(component->dev, + "ADSP is about to power up. bring up codec\n"); + + adsp_ready = q6core_is_adsp_ready(); + if (!adsp_ready) { + timeout = jiffies + + msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS); + do { + if (!q6core_is_adsp_ready()) + continue; + adsp_ready = true; + } while (!adsp_ready && time_after(timeout, jiffies)); + } + + if (!adsp_ready) { + dev_err(component->dev, + "%s: DSP isn't ready\n", __func__); + break; + } + + dev_dbg(component->dev, "%s: DSP is ready\n", __func__); + + regcache_cache_only(msm_dig_cdc->regmap, false); + regcache_mark_dirty(msm_dig_cdc->regmap); + + mutex_lock(&pdata->cdc_int_mclk0_mutex); + pdata->digital_cdc_core_clk.enable = 1; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_PRIMARY_MI2S_RX, + &pdata->digital_cdc_core_clk); + if (ret < 0) { + pr_err("%s: failed to enable the MCLK\n", + __func__); + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + break; + } + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + regcache_sync(msm_dig_cdc->regmap); + mutex_lock(&pdata->cdc_int_mclk0_mutex); + pdata->digital_cdc_core_clk.enable = 0; + afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX, + &pdata->digital_cdc_core_clk); + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + snd_soc_card_change_online_state(component->card, 1); + break; + + default: + break; + } + return NOTIFY_OK; +} + +/* + * msm_dig_codec_info_create_codec_entry - creates msm_dig module + * @codec_root: The parent directory + * @component: Component instance + * + * Creates msm_dig module and version entry under the given + * parent directory. + * + * Return: 0 on success or negative error code on failure. + */ +int msm_dig_codec_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + struct snd_info_entry *version_entry; + struct msm_dig_priv *msm_dig; + struct snd_soc_card *card; + + if (!codec_root || !component) + return -EINVAL; + + msm_dig = snd_soc_component_get_drvdata(component); + card = component->card; + msm_dig->entry = snd_info_create_subdir(codec_root->module, + "msm_digital_codec", + codec_root); + if (!msm_dig->entry) { + dev_dbg(component->dev, "%s: failed to create msm_digital entry\n", + __func__); + return -ENOMEM; + } + + version_entry = snd_info_create_card_entry(card->snd_card, + "version", + msm_dig->entry); + if (!version_entry) { + dev_dbg(component->dev, "%s: failed to create msm_digital version entry\n", + __func__); + return -ENOMEM; + } + + version_entry->private_data = msm_dig; + version_entry->size = MSM_DIG_CDC_VERSION_ENTRY_SIZE; + version_entry->content = SNDRV_INFO_CONTENT_DATA; + version_entry->c.ops = &msm_dig_codec_info_ops; + + if (snd_info_register(version_entry) < 0) { + snd_info_free_entry(version_entry); + return -ENOMEM; + } + msm_dig->version_entry = version_entry; + if (msm_dig->get_cdc_version) + msm_dig->version = msm_dig->get_cdc_version(msm_dig->handle); + else + msm_dig->version = DRAX_CDC; + + return 0; +} +EXPORT_SYMBOL(msm_dig_codec_info_create_codec_entry); + +static void msm_dig_cdc_update_micbias_regulator( + const struct msm_dig_priv *dig_cdc, + const char *name, + struct on_demand_dig_supply *micbias_supply) +{ + int i; + + for (i = 0; i < dig_cdc->num_of_supplies; i++) { + if (dig_cdc->supplies[i].supply && + !strcmp(dig_cdc->supplies[i].supply, name)) { + micbias_supply->supply = + dig_cdc->supplies[i].consumer; + micbias_supply->min_uv = dig_cdc->regulator[i].min_uv; + micbias_supply->max_uv = dig_cdc->regulator[i].max_uv; + micbias_supply->optimum_ua = + dig_cdc->regulator[i].optimum_ua; + return; + } + } + + dev_dbg(dig_cdc->dev, "Error: regulator not found:%s\n", name); +} + +static void sdm660_tx_mute_update_callback(struct work_struct *work) +{ + struct tx_mute_work *tx_mute_dwork; + struct snd_soc_component *component = NULL; + struct msm_dig_priv *dig_cdc; + struct delayed_work *delayed_work; + u16 tx_vol_ctl_reg = 0; + u8 decimator = 0, i; + + delayed_work = to_delayed_work(work); + tx_mute_dwork = container_of(delayed_work, struct tx_mute_work, dwork); + dig_cdc = tx_mute_dwork->dig_cdc; + component = dig_cdc->component; + + for (i = 0; i < (NUM_DECIMATORS - 1); i++) { + if (dig_cdc->dec_active[i]) + decimator = i + 1; + if (decimator && decimator < NUM_DECIMATORS) { + /* unmute decimators corresponding to Tx DAI's*/ + tx_vol_ctl_reg = + MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG + + 32 * (decimator - 1); + snd_soc_component_update_bits(component, + tx_vol_ctl_reg, 0x01, 0x00); + } + decimator = 0; + } +} + +static int msm_dig_cdc_soc_probe(struct snd_soc_component *component) +{ + struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(component->dev); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + int i, ret; + + msm_dig_cdc->component = component; + snd_soc_add_component_controls(component, compander_kcontrols, + ARRAY_SIZE(compander_kcontrols)); + + for (i = 0; i < NUM_DECIMATORS; i++) { + tx_hpf_work[i].dig_cdc = msm_dig_cdc; + tx_hpf_work[i].decimator = i + 1; + INIT_DELAYED_WORK(&tx_hpf_work[i].dwork, + tx_hpf_corner_freq_callback); + msm_dig_cdc->tx_mute_dwork[i].dig_cdc = msm_dig_cdc; + msm_dig_cdc->tx_mute_dwork[i].decimator = i + 1; + INIT_DELAYED_WORK(&msm_dig_cdc->tx_mute_dwork[i].dwork, + sdm660_tx_mute_update_callback); + } + + for (i = 0; i < MSM89XX_RX_MAX; i++) + msm_dig_cdc->comp_enabled[i] = COMPANDER_NONE; + + /* Register event notifier */ + msm_dig_cdc->nblock.notifier_call = msm_dig_cdc_event_notify; + if (msm_dig_cdc->register_notifier) { + ret = msm_dig_cdc->register_notifier(msm_dig_cdc->handle, + &msm_dig_cdc->nblock, + true); + if (ret) { + pr_err("%s: Failed to register notifier %d\n", + __func__, ret); + return ret; + } + } + + /* no_analog_codec, i.e, only digital codec is enabled, need to + * register notifier to monitor the adsp status + */ + if (msm_dig_cdc->no_analog_codec) { + msm_dig_cdc->service_nb.notifier_call = + digt_cdc_notifer_service_cb; + ret = audio_notifier_register("msm_digit_cdc", + AUDIO_NOTIFIER_ADSP_DOMAIN, + &msm_dig_cdc->service_nb); + if (ret < 0) { + pr_err("%s: Audio notifier register failed ret = %d\n", + __func__, ret); + return ret; + } + } + + msm_dig_cdc_update_micbias_regulator( + msm_dig_cdc, + on_demand_supply_name[ON_DEMAND_DIGITAL], + &msm_dig_cdc->on_demand_list[ON_DEMAND_DIGITAL]); + atomic_set(&msm_dig_cdc->on_demand_list[ON_DEMAND_DIGITAL].ref, 0); + registered_digcodec = component; + + snd_soc_dapm_ignore_suspend(dapm, "AIF1 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "AIF1 Capture"); + snd_soc_dapm_ignore_suspend(dapm, "ADC1_IN"); + snd_soc_dapm_ignore_suspend(dapm, "ADC2_IN"); + snd_soc_dapm_ignore_suspend(dapm, "ADC3_IN"); + snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX1"); + snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX2"); + snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX3"); + + snd_soc_dapm_sync(dapm); + + return 0; +} + +static void msm_dig_cdc_soc_remove(struct snd_soc_component *component) +{ + struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(component->dev); + + if (msm_dig_cdc->register_notifier) + msm_dig_cdc->register_notifier(msm_dig_cdc->handle, + &msm_dig_cdc->nblock, + false); + iounmap(msm_dig_cdc->dig_base); +} + +static const struct snd_soc_dapm_route audio_dig_map[] = { + {"RX_I2S_CLK", NULL, "CDC_CONN"}, + {"I2S RX1", NULL, "RX_I2S_CLK"}, + {"I2S RX2", NULL, "RX_I2S_CLK"}, + {"I2S RX3", NULL, "RX_I2S_CLK"}, + + {"I2S TX1", NULL, "TX_I2S_CLK"}, + {"I2S TX2", NULL, "TX_I2S_CLK"}, + {"AIF2 VI", NULL, "TX_I2S_CLK"}, + + {"I2S TX1", NULL, "DEC1 MUX"}, + {"I2S TX2", NULL, "DEC2 MUX"}, + {"AIF2 VI", NULL, "DEC3 MUX"}, + {"AIF2 VI", NULL, "DEC4 MUX"}, + + {"PDM_OUT_RX1", NULL, "RX1 CHAIN"}, + {"PDM_OUT_RX2", NULL, "RX2 CHAIN"}, + {"PDM_OUT_RX3", NULL, "RX3 CHAIN"}, + + {"RX1 CHAIN", NULL, "RX1 MIX2"}, + {"RX2 CHAIN", NULL, "RX2 MIX2"}, + {"RX3 CHAIN", NULL, "RX3 MIX1"}, + + {"RX1 MIX1", NULL, "RX1 MIX1 INP1"}, + {"RX1 MIX1", NULL, "RX1 MIX1 INP2"}, + {"RX1 MIX1", NULL, "RX1 MIX1 INP3"}, + {"RX2 MIX1", NULL, "RX2 MIX1 INP1"}, + {"RX2 MIX1", NULL, "RX2 MIX1 INP2"}, + {"RX3 MIX1", NULL, "RX3 MIX1 INP1"}, + {"RX3 MIX1", NULL, "RX3 MIX1 INP2"}, + {"RX1 MIX2", NULL, "RX1 MIX1"}, + {"RX1 MIX2", NULL, "RX1 MIX2 INP1"}, + {"RX2 MIX2", NULL, "RX2 MIX1"}, + {"RX2 MIX2", NULL, "RX2 MIX2 INP1"}, + + {"RX1 MIX1 INP1", "RX1", "I2S RX1"}, + {"RX1 MIX1 INP1", "RX2", "I2S RX2"}, + {"RX1 MIX1 INP1", "RX3", "I2S RX3"}, + {"RX1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX1 MIX1 INP1", "IIR2", "IIR2"}, + {"RX1 MIX1 INP2", "RX1", "I2S RX1"}, + {"RX1 MIX1 INP2", "RX2", "I2S RX2"}, + {"RX1 MIX1 INP2", "RX3", "I2S RX3"}, + {"RX1 MIX1 INP2", "IIR1", "IIR1"}, + {"RX1 MIX1 INP2", "IIR2", "IIR2"}, + {"RX1 MIX1 INP3", "RX1", "I2S RX1"}, + {"RX1 MIX1 INP3", "RX2", "I2S RX2"}, + {"RX1 MIX1 INP3", "RX3", "I2S RX3"}, + + {"RX2 MIX1 INP1", "RX1", "I2S RX1"}, + {"RX2 MIX1 INP1", "RX2", "I2S RX2"}, + {"RX2 MIX1 INP1", "RX3", "I2S RX3"}, + {"RX2 MIX1 INP1", "IIR1", "IIR1"}, + {"RX2 MIX1 INP1", "IIR2", "IIR2"}, + {"RX2 MIX1 INP2", "RX1", "I2S RX1"}, + {"RX2 MIX1 INP2", "RX2", "I2S RX2"}, + {"RX2 MIX1 INP2", "RX3", "I2S RX3"}, + {"RX2 MIX1 INP2", "IIR1", "IIR1"}, + {"RX2 MIX1 INP2", "IIR2", "IIR2"}, + {"RX2 MIX1 INP3", "RX1", "I2S RX1"}, + {"RX2 MIX1 INP3", "RX2", "I2S RX2"}, + {"RX2 MIX1 INP3", "RX3", "I2S RX3"}, + + {"RX3 MIX1 INP1", "RX1", "I2S RX1"}, + {"RX3 MIX1 INP1", "RX2", "I2S RX2"}, + {"RX3 MIX1 INP1", "RX3", "I2S RX3"}, + {"RX3 MIX1 INP1", "IIR1", "IIR1"}, + {"RX3 MIX1 INP1", "IIR2", "IIR2"}, + {"RX3 MIX1 INP2", "RX1", "I2S RX1"}, + {"RX3 MIX1 INP2", "RX2", "I2S RX2"}, + {"RX3 MIX1 INP2", "RX3", "I2S RX3"}, + {"RX3 MIX1 INP2", "IIR1", "IIR1"}, + {"RX3 MIX1 INP2", "IIR2", "IIR2"}, + {"RX3 MIX1 INP3", "RX1", "I2S RX1"}, + {"RX3 MIX1 INP3", "RX2", "I2S RX2"}, + {"RX3 MIX1 INP3", "RX3", "I2S RX3"}, + + {"RX1 MIX2 INP1", "IIR1", "IIR1"}, + {"RX2 MIX2 INP1", "IIR1", "IIR1"}, + {"RX1 MIX2 INP1", "IIR2", "IIR2"}, + {"RX2 MIX2 INP1", "IIR2", "IIR2"}, + + /* Decimator Inputs */ + {"DEC1 MUX", "DMIC1", "DMIC1"}, + {"DEC1 MUX", "DMIC2", "DMIC2"}, + {"DEC1 MUX", "ADC1", "ADC1_IN"}, + {"DEC1 MUX", "ADC2", "ADC2_IN"}, + {"DEC1 MUX", "ADC3", "ADC3_IN"}, + {"DEC1 MUX", NULL, "CDC_CONN"}, + + {"DEC2 MUX", "DMIC1", "DMIC1"}, + {"DEC2 MUX", "DMIC2", "DMIC2"}, + {"DEC2 MUX", "ADC1", "ADC1_IN"}, + {"DEC2 MUX", "ADC2", "ADC2_IN"}, + {"DEC2 MUX", "ADC3", "ADC3_IN"}, + {"DEC2 MUX", NULL, "CDC_CONN"}, + + {"DEC3 MUX", "DMIC3", "DMIC3"}, + {"DEC4 MUX", "DMIC4", "DMIC4"}, + {"DEC3 MUX", NULL, "CDC_CONN"}, + {"DEC4 MUX", NULL, "CDC_CONN"}, + + {"IIR1", NULL, "IIR1 INP1 MUX"}, + {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"}, + {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"}, + {"IIR2", NULL, "IIR2 INP1 MUX"}, + {"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"}, + {"IIR2 INP1 MUX", "DEC2", "DEC2 MUX"}, +}; + +static const char * const rx_mix1_text[] = { + "ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3" +}; + +static const char * const rx_mix2_text[] = { + "ZERO", "IIR1", "IIR2" +}; + +static const char * const dec_mux_text[] = { + "ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2" +}; + +static const char * const dec3_mux_text[] = { + "ZERO", "DMIC3" +}; + +static const char * const dec4_mux_text[] = { + "ZERO", "DMIC4" +}; + +static const char * const iir_inp1_text[] = { + "ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3" +}; + +/* RX1 MIX1 */ +static const struct soc_enum rx_mix1_inp1_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B1_CTL, + 0, 6, rx_mix1_text); + +static const struct soc_enum rx_mix1_inp2_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B1_CTL, + 3, 6, rx_mix1_text); + +static const struct soc_enum rx_mix1_inp3_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B2_CTL, + 0, 6, rx_mix1_text); + +/* RX1 MIX2 */ +static const struct soc_enum rx_mix2_inp1_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B3_CTL, + 0, 3, rx_mix2_text); + +/* RX2 MIX1 */ +static const struct soc_enum rx2_mix1_inp1_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL, + 0, 6, rx_mix1_text); + +static const struct soc_enum rx2_mix1_inp2_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL, + 3, 6, rx_mix1_text); + +static const struct soc_enum rx2_mix1_inp3_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL, + 0, 6, rx_mix1_text); + +/* RX2 MIX2 */ +static const struct soc_enum rx2_mix2_inp1_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B3_CTL, + 0, 3, rx_mix2_text); + +/* RX3 MIX1 */ +static const struct soc_enum rx3_mix1_inp1_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL, + 0, 6, rx_mix1_text); + +static const struct soc_enum rx3_mix1_inp2_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL, + 3, 6, rx_mix1_text); + +static const struct soc_enum rx3_mix1_inp3_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL, + 0, 6, rx_mix1_text); + +/* DEC */ +static const struct soc_enum dec1_mux_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B1_CTL, + 0, 6, dec_mux_text); + +static const struct soc_enum dec2_mux_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B1_CTL, + 3, 6, dec_mux_text); + +static const struct soc_enum dec3_mux_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX3_MUX_CTL, + 0, ARRAY_SIZE(dec3_mux_text), dec3_mux_text); + +static const struct soc_enum dec4_mux_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX4_MUX_CTL, + 0, ARRAY_SIZE(dec4_mux_text), dec4_mux_text); + +static const struct soc_enum iir1_inp1_mux_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL, + 0, 6, iir_inp1_text); + +static const struct soc_enum iir2_inp1_mux_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL, + 0, 6, iir_inp1_text); + +/*cut of frequency for high pass filter*/ +static const char * const cf_text[] = { + "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz" +}; + +static const struct soc_enum cf_rxmix1_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX1_B4_CTL, 0, 3, cf_text); + +static const struct soc_enum cf_rxmix2_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX2_B4_CTL, 0, 3, cf_text); + +static const struct soc_enum cf_rxmix3_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX3_B4_CTL, 0, 3, cf_text); + +static const struct snd_kcontrol_new rx3_mix1_inp1_mux = + SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum); + +#define MSM89XX_DEC_ENUM(xname, xenum) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_info_enum_double, \ + .get = snd_soc_dapm_get_enum_double, \ + .put = msm_dig_cdc_put_dec_enum, \ + .private_value = (unsigned long)&xenum } + +static const struct snd_kcontrol_new dec1_mux = + MSM89XX_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum); + +static const struct snd_kcontrol_new dec2_mux = + MSM89XX_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum); + +static const struct snd_kcontrol_new dec3_mux = + SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum); + +static const struct snd_kcontrol_new dec4_mux = + SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_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 iir2_inp1_mux = + SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum); + +static const struct snd_kcontrol_new rx_mix1_inp1_mux = + SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_mix1_inp2_mux = + SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_mix1_inp3_mux = + SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum); + +static const struct snd_kcontrol_new rx2_mix1_inp1_mux = + SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum); + +static const struct snd_kcontrol_new rx2_mix1_inp2_mux = + SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum); + +static const struct snd_kcontrol_new rx2_mix1_inp3_mux = + SOC_DAPM_ENUM("RX2 MIX1 INP3 Mux", rx2_mix1_inp3_chain_enum); + +static const struct snd_kcontrol_new rx3_mix1_inp2_mux = + SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum); + +static const struct snd_kcontrol_new rx3_mix1_inp3_mux = + SOC_DAPM_ENUM("RX3 MIX1 INP3 Mux", rx3_mix1_inp3_chain_enum); + +static const struct snd_kcontrol_new rx1_mix2_inp1_mux = + SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx_mix2_inp1_chain_enum); + +static const struct snd_kcontrol_new rx2_mix2_inp1_mux = + SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum); + +static const struct snd_soc_dapm_widget msm_dig_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("I2S RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_OUT("I2S TX1", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("I2S TX2", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2 VI", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_MIXER_E("RX1 MIX2", MSM89XX_CDC_CORE_CLK_RX_B1_CTL, + MSM89XX_RX1, 0, NULL, 0, + msm_dig_cdc_codec_enable_interpolator, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("RX2 MIX2", MSM89XX_CDC_CORE_CLK_RX_B1_CTL, + MSM89XX_RX2, 0, NULL, 0, + msm_dig_cdc_codec_enable_interpolator, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("RX3 MIX1", MSM89XX_CDC_CORE_CLK_RX_B1_CTL, + MSM89XX_RX3, 0, NULL, 0, + msm_dig_cdc_codec_enable_interpolator, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("RX1 CHAIN", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX2 CHAIN", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX3 CHAIN", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_mix1_inp1_mux), + SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_mix1_inp2_mux), + SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0, + &rx_mix1_inp3_mux), + + SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx2_mix1_inp1_mux), + SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx2_mix1_inp2_mux), + SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0, + &rx2_mix1_inp3_mux), + + SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx3_mix1_inp1_mux), + SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx3_mix1_inp2_mux), + SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0, + &rx3_mix1_inp3_mux), + + SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0, + &rx1_mix2_inp1_mux), + SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0, + &rx2_mix2_inp1_mux), + + SND_SOC_DAPM_SUPPLY_S("CDC_CONN", -2, MSM89XX_CDC_CORE_CLK_OTHR_CTL, + 2, 0, NULL, 0), + + SND_SOC_DAPM_MUX_E("DEC1 MUX", + MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 0, 0, + &dec1_mux, msm_dig_cdc_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("DEC2 MUX", + MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 1, 0, + &dec2_mux, msm_dig_cdc_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("DEC3 MUX", + MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 2, 0, + &dec3_mux, msm_dig_cdc_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("DEC4 MUX", + MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 3, 0, + &dec4_mux, msm_dig_cdc_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + /* Sidetone */ + SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux), + SND_SOC_DAPM_PGA_E("IIR1", MSM89XX_CDC_CORE_CLK_SD_CTL, 0, 0, NULL, 0, + msm_dig_cdc_codec_set_iir_gain, SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux), + SND_SOC_DAPM_PGA_E("IIR2", MSM89XX_CDC_CORE_CLK_SD_CTL, 1, 0, NULL, 0, + msm_dig_cdc_codec_set_iir_gain, SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", + MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", + MSM89XX_CDC_CORE_CLK_TX_I2S_CTL, 4, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DIGITAL_REGULATOR", SND_SOC_NOPM, + ON_DEMAND_DIGITAL, 0, + msm_dig_cdc_enable_on_demand_supply, + SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + /* Digital Mic Inputs */ + SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, + msm_dig_cdc_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0, + msm_dig_cdc_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_INPUT("DMIC3"), + SND_SOC_DAPM_INPUT("DMIC4"), + SND_SOC_DAPM_INPUT("ADC1_IN"), + SND_SOC_DAPM_INPUT("ADC2_IN"), + SND_SOC_DAPM_INPUT("ADC3_IN"), + SND_SOC_DAPM_OUTPUT("PDM_OUT_RX1"), + SND_SOC_DAPM_OUTPUT("PDM_OUT_RX2"), + SND_SOC_DAPM_OUTPUT("PDM_OUT_RX3"), +}; + +static const struct soc_enum cf_dec1_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX1_MUX_CTL, 4, 3, cf_text); + +static const struct soc_enum cf_dec2_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX2_MUX_CTL, 4, 3, cf_text); + +static const struct soc_enum cf_dec3_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX3_MUX_CTL, 4, 3, cf_text); + +static const struct soc_enum cf_dec4_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX4_MUX_CTL, 4, 3, cf_text); + +static const struct snd_kcontrol_new msm_dig_snd_controls[] = { + SOC_SINGLE_SX_TLV("DEC1 Volume", + MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("DEC2 Volume", + MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("DEC3 Volume", + MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("DEC4 Volume", + MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN, + 0, -84, 40, digital_gain), + + SOC_SINGLE_SX_TLV("IIR1 INP1 Volume", + MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("IIR1 INP2 Volume", + MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("IIR1 INP3 Volume", + MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("IIR1 INP4 Volume", + MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("IIR2 INP1 Volume", + MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL, + 0, -84, 40, digital_gain), + + SOC_SINGLE_SX_TLV("RX1 Digital Volume", + MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX2 Digital Volume", + MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX3 Digital Volume", + MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL, + 0, -84, 40, digital_gain), + + SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0, + msm_dig_cdc_get_iir_enable_audio_mixer, + msm_dig_cdc_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0, + msm_dig_cdc_get_iir_enable_audio_mixer, + msm_dig_cdc_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0, + msm_dig_cdc_get_iir_enable_audio_mixer, + msm_dig_cdc_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0, + msm_dig_cdc_get_iir_enable_audio_mixer, + msm_dig_cdc_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0, + msm_dig_cdc_get_iir_enable_audio_mixer, + msm_dig_cdc_put_iir_enable_audio_mixer), + + SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0, + msm_dig_cdc_get_iir_enable_audio_mixer, + msm_dig_cdc_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0, + msm_dig_cdc_get_iir_enable_audio_mixer, + msm_dig_cdc_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0, + msm_dig_cdc_get_iir_enable_audio_mixer, + msm_dig_cdc_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0, + msm_dig_cdc_get_iir_enable_audio_mixer, + msm_dig_cdc_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0, + msm_dig_cdc_get_iir_enable_audio_mixer, + msm_dig_cdc_put_iir_enable_audio_mixer), + + SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5, + msm_dig_cdc_get_iir_band_audio_mixer, + msm_dig_cdc_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5, + msm_dig_cdc_get_iir_band_audio_mixer, + msm_dig_cdc_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5, + msm_dig_cdc_get_iir_band_audio_mixer, + msm_dig_cdc_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5, + msm_dig_cdc_get_iir_band_audio_mixer, + msm_dig_cdc_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5, + msm_dig_cdc_get_iir_band_audio_mixer, + msm_dig_cdc_put_iir_band_audio_mixer), + + SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5, + msm_dig_cdc_get_iir_band_audio_mixer, + msm_dig_cdc_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5, + msm_dig_cdc_get_iir_band_audio_mixer, + msm_dig_cdc_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5, + msm_dig_cdc_get_iir_band_audio_mixer, + msm_dig_cdc_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5, + msm_dig_cdc_get_iir_band_audio_mixer, + msm_dig_cdc_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5, + msm_dig_cdc_get_iir_band_audio_mixer, + msm_dig_cdc_put_iir_band_audio_mixer), + + SOC_SINGLE("RX1 HPF Switch", + MSM89XX_CDC_CORE_RX1_B5_CTL, 2, 1, 0), + SOC_SINGLE("RX2 HPF Switch", + MSM89XX_CDC_CORE_RX2_B5_CTL, 2, 1, 0), + SOC_SINGLE("RX3 HPF Switch", + MSM89XX_CDC_CORE_RX3_B5_CTL, 2, 1, 0), + + SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum), + SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum), + SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum), + + SOC_ENUM("TX1 HPF cut off", cf_dec1_enum), + SOC_ENUM("TX2 HPF cut off", cf_dec2_enum), + SOC_ENUM("TX3 HPF cut off", cf_dec3_enum), + SOC_ENUM("TX4 HPF cut off", cf_dec4_enum), + SOC_SINGLE("TX1 HPF Switch", + MSM89XX_CDC_CORE_TX1_MUX_CTL, 3, 1, 0), + SOC_SINGLE("TX2 HPF Switch", + MSM89XX_CDC_CORE_TX2_MUX_CTL, 3, 1, 0), + SOC_SINGLE("TX3 HPF Switch", + MSM89XX_CDC_CORE_TX3_MUX_CTL, 3, 1, 0), + SOC_SINGLE("TX4 HPF Switch", + MSM89XX_CDC_CORE_TX4_MUX_CTL, 3, 1, 0), +}; + +static int msm_dig_cdc_enable_on_demand_supply( + struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + int ret = 0; + const char *err_msg = "failed for micbias with err ="; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct msm_dig_priv *msm_dig_cdc = + snd_soc_component_get_drvdata(component); + struct on_demand_dig_supply *supply; + + if (w->shift >= ON_DEMAND_DIG_SUPPLIES_MAX) { + dev_err(component->dev, + "%s: error index >= MAX on demand supplies", __func__); + ret = -EINVAL; + goto out; + } + dev_dbg(component->dev, "%s: supply: %s event: %d ref: %d\n", + __func__, on_demand_supply_name[w->shift], event, + atomic_read(&msm_dig_cdc->on_demand_list[w->shift].ref)); + + supply = &msm_dig_cdc->on_demand_list[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 (atomic_inc_return(&supply->ref) == 1) { + ret = regulator_set_voltage(supply->supply, + supply->min_uv, + supply->max_uv); + if (ret) { + dev_err(component->dev, + "Setting regulator voltage(en) %s %d\n", + err_msg, ret); + goto out; + } + ret = regulator_set_load(supply->supply, + supply->optimum_ua); + if (ret < 0) { + dev_err(component->dev, + "Setting regulator optimum mode(en) %s %d\n", + err_msg, ret); + goto out; + } + 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: + if (atomic_read(&supply->ref) == 0) { + dev_dbg(component->dev, + "%s: %s supply has been disabled.\n", + __func__, on_demand_supply_name[w->shift]); + goto out; + } + if (atomic_dec_return(&supply->ref) == 0) { + ret = regulator_disable(supply->supply); + if (ret) + dev_err(component->dev, + "%s: Failed to disable %s\n", + __func__, + on_demand_supply_name[w->shift]); + ret = regulator_set_voltage(supply->supply, + 0, + supply->max_uv); + if (ret) { + dev_err(component->dev, + "Setting regulator voltage(dis) %s %d\n", + err_msg, ret); + goto out; + } + ret = regulator_set_load(supply->supply, 0); + if (ret < 0) + dev_err(component->dev, + "Setting regulator optimum mode(dis) %s %d\n", + err_msg, ret); + } + break; + default: + break; + } +out: + return ret; +} + +static int msm_digital_cdc_init_supplies(struct msm_dig_priv *msm_cdc) +{ + int ret; + int i; + const char *err_msg1 = "Setting regulator voltage"; + const char *err_msg2 = "Setting regulator optimum mode"; + + msm_cdc->supplies = devm_kzalloc(msm_cdc->dev, + sizeof(struct regulator_bulk_data) * + ARRAY_SIZE(msm_cdc->regulator), + GFP_KERNEL); + if (!msm_cdc->supplies) { + ret = -ENOMEM; + goto err; + } + + msm_cdc->num_of_supplies = 0; + + if (ARRAY_SIZE(msm_cdc->regulator) > MAX_REGULATOR) { + dev_err(msm_cdc->dev, "%s: Array Size out of bound\n", + __func__); + ret = -EINVAL; + goto err; + } + + for (i = 0; i < ARRAY_SIZE(msm_cdc->regulator); i++) { + if (msm_cdc->regulator[i].name) { + msm_cdc->supplies[i].supply = + msm_cdc->regulator[i].name; + msm_cdc->num_of_supplies++; + } + } + + ret = devm_regulator_bulk_get(msm_cdc->dev, + msm_cdc->num_of_supplies, + msm_cdc->supplies); + if (ret != 0) { + dev_err(msm_cdc->dev, + "Failed to get supplies: err = %d\n", + ret); + goto err_supplies; + } + + for (i = 0; i < msm_cdc->num_of_supplies; i++) { + if (regulator_count_voltages( + msm_cdc->supplies[i].consumer) <= 0) + continue; + ret = regulator_set_voltage( + msm_cdc->supplies[i].consumer, + msm_cdc->regulator[i].min_uv, + msm_cdc->regulator[i].max_uv); + if (ret) { + dev_err(msm_cdc->dev, + "%s failed for regulator %s err = %d\n", + err_msg1, msm_cdc->supplies[i].supply, ret); + goto err_supplies; + } + ret = regulator_set_load(msm_cdc->supplies[i].consumer, + msm_cdc->regulator[i].optimum_ua); + if (ret < 0) { + dev_err(msm_cdc->dev, + "%s failed for regulator %s err = %d\n", + err_msg2, msm_cdc->supplies[i].supply, ret); + goto err_supplies; + } else { + ret = 0; + } + } + + return ret; + +err_supplies: +err: + return ret; +} + +static int msm_digital_cdc_dt_parse_vreg_info(struct device *dev, + struct dig_cdc_regulator *vreg, const char *vreg_name) +{ + int len, ret = 0; + const __be32 *prop; + char prop_name[CODEC_DT_MAX_PROP_SIZE]; + struct device_node *regnode = NULL; + u32 prop_val; + + snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "%s-supply", + vreg_name); + regnode = of_parse_phandle(dev->of_node, prop_name, 0); + + if (!regnode) { + dev_err(dev, "Looking up %s property in node %s failed\n", + prop_name, dev->of_node->full_name); + return -ENODEV; + } + + dev_dbg(dev, "Looking up %s property in node %s\n", + prop_name, dev->of_node->full_name); + + vreg->name = vreg_name; + + snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, + "qcom,%s-voltage", vreg_name); + prop = of_get_property(dev->of_node, prop_name, &len); + + if (!prop || (len != (2 * sizeof(__be32)))) { + dev_err(dev, "%s %s property\n", + prop ? "invalid format" : "no", prop_name); + return -EINVAL; + } + vreg->min_uv = be32_to_cpup(&prop[0]); + vreg->max_uv = be32_to_cpup(&prop[1]); + + snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, + "qcom,%s-current", vreg_name); + + ret = of_property_read_u32(dev->of_node, prop_name, &prop_val); + if (ret) { + dev_err(dev, "Looking up %s property in node %s failed", + prop_name, dev->of_node->full_name); + return -EFAULT; + } + vreg->optimum_ua = prop_val; + dev_dbg(dev, "%s: vol=[%d %d]uV, curr=[%d]uA\n", vreg->name, + vreg->min_uv, vreg->max_uv, vreg->optimum_ua); + return 0; +} + +static struct snd_soc_dai_ops msm_dig_dai_ops = { + .hw_params = msm_dig_cdc_hw_params, +}; + + +static struct snd_soc_dai_driver msm_codec_dais[] = { + { + .name = "msm_dig_cdc_dai_rx1", + .id = AIF1_PB, + .playback = { /* Support maximum range */ + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .rate_max = 192000, + .rate_min = 8000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE, + }, + .ops = &msm_dig_dai_ops, + }, + { + .name = "msm_dig_cdc_dai_tx1", + .id = AIF1_CAP, + .capture = { /* Support maximum range */ + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 4, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &msm_dig_dai_ops, + }, + { + .name = "msm_dig_cdc_dai_vifeed", + .id = AIF2_VIFEED, + .capture = { /* Support maximum range */ + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &msm_dig_dai_ops, + }, +}; + +static int msm_dig_cdc_suspend(struct snd_soc_component *component) +{ + struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(component->dev); + + msm_dig_cdc->dapm_bias_off = 1; + return 0; +} + +static int msm_dig_cdc_resume(struct snd_soc_component *component) +{ + struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(component->dev); + + msm_dig_cdc->dapm_bias_off = 0; + return 0; +} + +const struct snd_soc_component_driver soc_msm_dig_codec = { + .probe = msm_dig_cdc_soc_probe, + .remove = msm_dig_cdc_soc_remove, + .suspend = msm_dig_cdc_suspend, + .resume = msm_dig_cdc_resume, + .controls = msm_dig_snd_controls, + .num_controls = ARRAY_SIZE(msm_dig_snd_controls), + .dapm_widgets = msm_dig_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(msm_dig_dapm_widgets), + .dapm_routes = audio_dig_map, + .num_dapm_routes = ARRAY_SIZE(audio_dig_map), +}; + +const struct regmap_config msm_digital_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 8, + .lock = enable_digital_callback, + .unlock = disable_digital_callback, + .cache_type = REGCACHE_FLAT, + .reg_defaults = msm89xx_cdc_core_defaults, + .num_reg_defaults = MSM89XX_CDC_CORE_MAX_REGISTER, + .writeable_reg = msm89xx_cdc_core_writeable_reg, + .readable_reg = msm89xx_cdc_core_readable_reg, + .volatile_reg = msm89xx_cdc_core_volatile_reg, + .reg_format_endian = REGMAP_ENDIAN_NATIVE, + .val_format_endian = REGMAP_ENDIAN_NATIVE, + .max_register = MSM89XX_CDC_CORE_MAX_REGISTER, +}; + +static bool msm_digital_cdc_populate_dt_pdata( + struct device *dev, + struct msm_dig_priv *dig_priv) +{ + int ret, ond_cnt, i, idx = 0; + const char *name = NULL; + const char *ond_prop_name = "qcom,cdc-on-demand-supplies"; + + ond_cnt = of_property_count_strings(dev->of_node, ond_prop_name); + if (ond_cnt < 0) + ond_cnt = 0; + + if (ond_cnt > ARRAY_SIZE(dig_priv->regulator)) { + ret = -EINVAL; + goto err; + } + + for (i = 0; i < ond_cnt; i++, idx++) { + ret = of_property_read_string_index(dev->of_node, ond_prop_name, + i, &name); + if (ret) { + dev_err(dev, "%s: err parsing on_demand for %s idx %d\n", + __func__, ond_prop_name, i); + goto err; + } + + dev_dbg(dev, "%s: Found on-demand cdc supply %s\n", __func__, + name); + ret = msm_digital_cdc_dt_parse_vreg_info(dev, + &dig_priv->regulator[idx], + name); + if (ret) { + dev_err(dev, "%s: err parsing vreg on_demand for %s idx %d\n", + __func__, name, idx); + goto err; + } + } + + return true; +err: + dev_err(dev, "%s: Failed to populate DT data ret = %d\n", + __func__, ret); + return false; +} + +static void msm_digital_cdc_disable_supplies(struct msm_dig_priv *msm_cdc) +{ + int i; + + if (!msm_cdc->supplies) + return; + + regulator_bulk_disable(msm_cdc->num_of_supplies, + msm_cdc->supplies); + for (i = 0; i < msm_cdc->num_of_supplies; i++) { + if (regulator_count_voltages( + msm_cdc->supplies[i].consumer) <= 0) + continue; + regulator_set_voltage(msm_cdc->supplies[i].consumer, 0, + msm_cdc->regulator[i].max_uv); + regulator_set_load(msm_cdc->supplies[i].consumer, 0); + } + regulator_bulk_free(msm_cdc->num_of_supplies, + msm_cdc->supplies); + devm_kfree(msm_cdc->dev, msm_cdc->supplies); +} + +static int msm_dig_cdc_probe(struct platform_device *pdev) +{ + int ret = -EINVAL; + u32 dig_cdc_addr; + struct msm_dig_priv *msm_dig_cdc; + struct dig_ctrl_platform_data *pdata = NULL; + int adsp_state = 0; + + adsp_state = apr_get_subsys_state(); + if ((adsp_state != APR_SUBSYS_LOADED) || (!q6core_is_adsp_ready())) { + dev_err(&pdev->dev, "Adsp is not loaded yet %d\n", + adsp_state); + return -EPROBE_DEFER; + } + device_init_wakeup(&pdev->dev, true); + + msm_dig_cdc = devm_kzalloc(&pdev->dev, sizeof(struct msm_dig_priv), + GFP_KERNEL); + if (!msm_dig_cdc) + return -ENOMEM; + msm_dig_cdc->dev = &pdev->dev; + if (pdev->dev.of_node == NULL) + return -EINVAL; + + if (pdev->dev.of_node) + msm_dig_cdc->no_analog_codec = of_property_read_bool( + pdev->dev.of_node, + "qcom,no-analog-codec"); + if (msm_dig_cdc->no_analog_codec) { + dev_dbg(&pdev->dev, "%s:Platform data from device tree\n", + __func__); + if (msm_digital_cdc_populate_dt_pdata(&pdev->dev, + msm_dig_cdc)) { + ret = msm_digital_cdc_init_supplies( + msm_dig_cdc); + if (ret) { + dev_err(&pdev->dev, + "%s: Fail to enable Codec supplies\n", + __func__); + goto rtn; + } + } + } else { + pdata = dev_get_platdata(&pdev->dev); + if (!pdata) { + dev_err(&pdev->dev, "%s: pdata from parent is NULL\n", + __func__); + ret = -EINVAL; + goto err_supplies; + } + msm_dig_cdc->update_clkdiv = pdata->update_clkdiv; + msm_dig_cdc->set_compander_mode = pdata->set_compander_mode; + msm_dig_cdc->get_cdc_version = pdata->get_cdc_version; + msm_dig_cdc->handle = pdata->handle; + msm_dig_cdc->register_notifier = pdata->register_notifier; + } + + ret = of_property_read_u32(pdev->dev.of_node, "reg", + &dig_cdc_addr); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "reg"); + goto err_supplies; + } + + msm_dig_cdc->dig_base = ioremap(dig_cdc_addr, + MSM89XX_CDC_CORE_MAX_REGISTER); + if (msm_dig_cdc->dig_base == NULL) { + dev_err(&pdev->dev, "%s ioremap failed\n", __func__); + ret = -ENOMEM; + goto err_supplies; + } + msm_dig_cdc->regmap = + devm_regmap_init_mmio_clk(&pdev->dev, NULL, + msm_dig_cdc->dig_base, &msm_digital_regmap_config); + + + dev_set_drvdata(&pdev->dev, msm_dig_cdc); + snd_soc_register_component(&pdev->dev, &soc_msm_dig_codec, + msm_codec_dais, ARRAY_SIZE(msm_codec_dais)); + dev_dbg(&pdev->dev, "%s: registered DIG CODEC 0x%x\n", + __func__, dig_cdc_addr); + return ret; +err_supplies: + if (msm_dig_cdc->no_analog_codec) + msm_digital_cdc_disable_supplies(msm_dig_cdc); +rtn: + return ret; +} + +static int msm_dig_cdc_remove(struct platform_device *pdev) +{ + struct msm_dig_priv *msm_cdc = dev_get_drvdata(&pdev->dev); + + snd_soc_unregister_component(&pdev->dev); + msm_digital_cdc_disable_supplies(msm_cdc); + return 0; +} + +#ifdef CONFIG_PM +static int msm_dig_suspend(struct device *dev) +{ + struct msm_asoc_mach_data *pdata; + struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(dev); + + if (!registered_digcodec || !msm_dig_cdc) { + pr_debug("%s:digcodec not initialized, return\n", __func__); + return 0; + } + pdata = snd_soc_card_get_drvdata(registered_digcodec->card); + if (!pdata) { + pr_debug("%s:card not initialized, return\n", __func__); + return 0; + } + if (msm_dig_cdc->dapm_bias_off) { + pr_debug("%s: mclk cnt = %d, mclk_enabled = %d\n", + __func__, atomic_read(&pdata->int_mclk0_rsc_ref), + atomic_read(&pdata->int_mclk0_enabled)); + + if (atomic_read(&pdata->int_mclk0_enabled) == true) { + cancel_delayed_work_sync( + &pdata->disable_int_mclk0_work); + mutex_lock(&pdata->cdc_int_mclk0_mutex); + pdata->digital_cdc_core_clk.enable = 0; + afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX, + &pdata->digital_cdc_core_clk); + atomic_set(&pdata->int_mclk0_enabled, false); + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + } + } + + return 0; +} + +static int msm_dig_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops msm_dig_pm_ops = { + .suspend_late = msm_dig_suspend, + .resume_early = msm_dig_resume, +}; +#endif + +static const struct of_device_id msm_dig_cdc_of_match[] = { + {.compatible = "qcom,msm-digital-codec"}, + {}, +}; + +static struct platform_driver msm_digcodec_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + .of_match_table = msm_dig_cdc_of_match, +#ifdef CONFIG_PM + .pm = &msm_dig_pm_ops, +#endif + }, + .probe = msm_dig_cdc_probe, + .remove = msm_dig_cdc_remove, +}; +module_platform_driver(msm_digcodec_driver); + +MODULE_DESCRIPTION("MSM Audio Digital codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/asoc/codecs/sdm660_cdc/msm-digital-cdc.h b/asoc/codecs/sdm660_cdc/msm-digital-cdc.h index a6178cd20419..3d2b34275c66 100644 --- a/asoc/codecs/sdm660_cdc/msm-digital-cdc.h +++ b/asoc/codecs/sdm660_cdc/msm-digital-cdc.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2017, 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, 2020-2021, The Linux Foundation. All rights reserved. */ #ifndef MSM_DIGITAL_CDC_H #define MSM_DIGITAL_CDC_H @@ -8,7 +8,7 @@ #define HPHL_PA_DISABLE (0x01 << 1) #define HPHR_PA_DISABLE (0x01 << 2) #define SPKR_PA_DISABLE (0x01 << 3) - +#define MAX_REGULATOR 7 #define NUM_DECIMATORS 5 /* Codec supports 1 compander */ enum { @@ -25,30 +25,62 @@ enum { MSM89XX_RX_MAX, }; +enum { + ON_DEMAND_DIGITAL = 0, + ON_DEMAND_DIG_SUPPLIES_MAX, +}; + +struct on_demand_dig_supply { + struct regulator *supply; + atomic_t ref; + int min_uv; + int max_uv; + int optimum_ua; +}; + +struct dig_cdc_regulator { + const char *name; + int min_uv; + int max_uv; + int optimum_ua; + struct regulator *regulator; +}; + struct tx_mute_work { struct msm_dig_priv *dig_cdc; u32 decimator; struct delayed_work dwork; }; +struct msm_cap_mode { + u8 micbias1_cap_mode; + u8 micbias2_cap_mode; +}; + struct msm_dig_priv { struct snd_soc_component *component; + struct device *dev; u32 comp_enabled[MSM89XX_RX_MAX]; int (*codec_hph_comp_gpio)(bool enable, - struct snd_soc_component *component); + struct snd_soc_component *component); s32 dmic_1_2_clk_cnt; s32 dmic_3_4_clk_cnt; bool dec_active[NUM_DECIMATORS]; int version; + /* cal info for codec */ + struct fw_info *fw_data; + bool no_analog_codec; /* Entry for version info */ struct snd_info_entry *entry; struct snd_info_entry *version_entry; char __iomem *dig_base; struct regmap *regmap; struct notifier_block nblock; + struct notifier_block service_nb; u32 mute_mask; int dapm_bias_off; void *handle; + struct on_demand_dig_supply on_demand_list[ON_DEMAND_DIG_SUPPLIES_MAX]; void (*set_compander_mode)(void *handle, int val); void (*update_clkdiv)(void *handle, int val); int (*get_cdc_version)(void *handle); @@ -56,6 +88,9 @@ struct msm_dig_priv { struct notifier_block *nblock, bool enable); struct tx_mute_work tx_mute_dwork[NUM_DECIMATORS]; + u32 num_of_supplies; + struct regulator_bulk_data *supplies; + struct dig_cdc_regulator regulator[MAX_REGULATOR]; }; struct dig_ctrl_platform_data { @@ -85,13 +120,16 @@ enum { BAND_MAX, }; -#if IS_ENABLED(CONFIG_SND_SOC_DIGITAL_CDC) +#if (IS_ENABLED(CONFIG_SND_SOC_DIGITAL_CDC) || \ + IS_ENABLED(CONFIG_SND_SOC_DIGITAL_CDC_LEGACY)) extern void msm_dig_cdc_hph_comp_cb( int (*codec_hph_comp_gpio)( bool enable, struct snd_soc_component *component), struct snd_soc_component *component); int msm_dig_codec_info_create_codec_entry(struct snd_info_entry *codec_root, struct snd_soc_component *component); +extern int msm_digcdc_mclk_enable(struct snd_soc_component *component, + int mclk_enable, bool dapm); #else /* CONFIG_SND_SOC_DIGITAL_CDC */ static inline void msm_dig_cdc_hph_comp_cb( int (*codec_hph_comp_gpio)( @@ -106,5 +144,10 @@ static inline int msm_dig_codec_info_create_codec_entry( { return 0; } +static inline int msm_digcdc_mclk_enable(struct snd_soc_component *component, + int mclk_enable, bool dapm) +{ + return 0; +} #endif /* CONFIG_SND_SOC_DIGITAL_CDC */ #endif diff --git a/asoc/codecs/wcd_cpe_core.c b/asoc/codecs/wcd_cpe_core.c index 5b5291f8a603..10854bd41f18 100644 --- a/asoc/codecs/wcd_cpe_core.c +++ b/asoc/codecs/wcd_cpe_core.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2019, 2021, The Linux Foundation. All rights reserved. */ #include @@ -18,7 +18,7 @@ #include #include #include -#include "cpe_core.h" +#include #include "cpe_err.h" #include "cpe_cmi.h" #include "wcd_cpe_core.h" diff --git a/asoc/codecs/wcd_cpe_services.c b/asoc/codecs/wcd_cpe_services.c index 96e2bb1945a4..3f513a5c668e 100644 --- a/asoc/codecs/wcd_cpe_services.c +++ b/asoc/codecs/wcd_cpe_services.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, 2021, The Linux Foundation. All rights reserved. */ #include @@ -283,7 +283,7 @@ static enum cpe_svc_result cpe_is_command_valid( static int cpe_register_read(u32 reg, u8 *val) { - *(val) = snd_soc_read(cpe_d.cdc_priv, reg); + *(val) = snd_soc_component_read32(cpe_d.cdc_priv, reg); return 0; } @@ -292,7 +292,7 @@ static enum cpe_svc_result cpe_update_bits(u32 reg, { int ret = 0; - ret = snd_soc_update_bits(cpe_d.cdc_priv, reg, + ret = snd_soc_component_update_bits(cpe_d.cdc_priv, reg, mask, value); if (ret < 0) return CPE_SVC_FAILED; @@ -308,7 +308,7 @@ static int cpe_register_write(u32 reg, u32 val) pr_debug("%s: reg = 0x%x, value = 0x%x\n", __func__, reg, val); - ret = snd_soc_write(cpe_d.cdc_priv, reg, val); + ret = snd_soc_component_write(cpe_d.cdc_priv, reg, val); if (ret < 0) return CPE_SVC_FAILED; @@ -317,8 +317,9 @@ static int cpe_register_write(u32 reg, u32 val) static int cpe_register_write_repeat(u32 reg, u8 *ptr, u32 to_write) { - struct snd_soc_codec *codec = cpe_d.cdc_priv; - struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent); + struct snd_soc_component *component = cpe_d.cdc_priv; + struct wcd9xxx *wcd9xxx = + snd_soc_component_get_drvdata(component); int ret = 0; ret = wcd9xxx_slim_write_repeat(wcd9xxx, reg, to_write, ptr); diff --git a/asoc/msm-cpe-lsm.c b/asoc/msm-cpe-lsm.c index 0f98192a083e..c30135890602 100644 --- a/asoc/msm-cpe-lsm.c +++ b/asoc/msm-cpe-lsm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2013-2019, 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2019, 2020-2021, The Linux Foundation. All rights reserved. */ #include @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -129,7 +130,7 @@ struct cpe_lsm_lab { struct cpe_priv { void *core_handle; - struct snd_soc_codec *codec; + struct snd_soc_component *component; struct wcd_cpe_lsm_ops lsm_ops; struct wcd_cpe_afe_ops afe_ops; bool afe_mad_ctl; @@ -196,14 +197,14 @@ static struct cpe_priv *cpe_get_private_data( rtd = substream->private_data; - if (!rtd || !rtd->platform) { + if (!rtd) { pr_err("%s: %s is invalid\n", __func__, (!rtd) ? "runtime" : "platform"); goto err_ret; } - return snd_soc_platform_get_drvdata(rtd->platform); + return snd_soc_card_get_drvdata(rtd->card); err_ret: return NULL; @@ -756,7 +757,7 @@ static int msm_cpe_lsm_open(struct snd_pcm_substream *substream) struct wcd_cpe_lsm_ops *lsm_ops; int rc = 0; - if (!cpe || !cpe->codec) { + if (!cpe || !cpe->component) { dev_err(rtd->dev, "%s: Invalid private data\n", __func__); @@ -792,11 +793,11 @@ static int msm_cpe_lsm_open(struct snd_pcm_substream *substream) return -EINVAL; } - cpe->core_handle = wcd_cpe_get_core_handle(cpe->codec); + cpe->core_handle = wcd_cpe_get_core_handle(cpe->component); if (!cpe->core_handle) { dev_err(rtd->dev, - "%s: Invalid handle to codec core\n", + "%s: Invalid handle to component core\n", __func__); return -EINVAL; } @@ -3215,7 +3216,6 @@ static int msm_asoc_cpe_lsm_probe(struct snd_soc_component *component) { struct snd_soc_card *card; struct snd_soc_pcm_runtime *rtd; - struct snd_soc_codec *codec; struct cpe_priv *cpe_priv; struct snd_soc_component *component_rtd = NULL; const struct snd_kcontrol_new *kcontrol; @@ -3259,14 +3259,12 @@ static int msm_asoc_cpe_lsm_probe(struct snd_soc_component *component) port_id = 1; } - codec = rtd->codec; - cpe_priv = kzalloc(sizeof(struct cpe_priv), GFP_KERNEL); if (!cpe_priv) return -ENOMEM; - cpe_priv->codec = codec; + cpe_priv->component = component; cpe_priv->input_port_id = port_id; wcd_cpe_get_lsm_ops(&cpe_priv->lsm_ops); wcd_cpe_get_afe_ops(&cpe_priv->afe_ops); @@ -3317,7 +3315,7 @@ static int msm_cpe_lsm_probe(struct platform_device *pdev) */ static int msm_cpe_lsm_remove(struct platform_device *pdev) { - snd_soc_unregister_commponent(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } diff --git a/asoc/msm8952-dai-links.c b/asoc/msm8952-dai-links.c new file mode 100644 index 000000000000..37243adf7c58 --- /dev/null +++ b/asoc/msm8952-dai-links.c @@ -0,0 +1,1669 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2015-2018, 2020-2021, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include "msm8952-slimbus.h" +#include "msm-pcm-routing-v2.h" +#include "codecs/wcd9335.h" + +#define DEV_NAME_STR_LEN 32 + +/* dummy definition of below deprecated FE DAI's*/ +enum { + MSM_FRONTEND_DAI_CS_VOICE = 39, + MSM_FRONTEND_DAI_VOICE2, + MSM_FRONTEND_DAI_VOLTE, + MSM_FRONTEND_DAI_VOWLAN, +}; + +enum TASHA_LITE_DEVICE { + MSM8952_TASHA_LITE = 0, + MSM8953_TASHA_LITE, + NUM_OF_TASHA_LITE_DEVICE, +}; + +static struct snd_soc_card snd_soc_card_msm_card; + +static struct snd_soc_ops msm8952_quat_mi2s_be_ops = { + .startup = msm_quat_mi2s_snd_startup, + .hw_params = msm_mi2s_snd_hw_params, + .shutdown = msm_quat_mi2s_snd_shutdown, +}; + +static struct snd_soc_ops msm8952_quin_mi2s_be_ops = { + .startup = msm_quin_mi2s_snd_startup, + .hw_params = msm_mi2s_snd_hw_params, + .shutdown = msm_quin_mi2s_snd_shutdown, +}; + +static struct snd_soc_ops msm_pri_auxpcm_be_ops = { + .startup = msm_prim_auxpcm_startup, + .shutdown = msm_prim_auxpcm_shutdown, +}; + +static struct snd_soc_ops msm8952_slimbus_be_ops = { + .hw_params = msm_snd_hw_params, +}; + + +static struct snd_soc_ops msm8952_cpe_ops = { + .hw_params = msm_snd_cpe_hw_params, +}; + +static struct snd_soc_ops msm8952_slimbus_2_be_ops = { + .hw_params = msm8952_slimbus_2_hw_params, +}; + +static struct snd_soc_ops msm_tdm_be_ops = { + .startup = msm_tdm_startup, + .hw_params = msm_tdm_snd_hw_params, + .shutdown = msm_tdm_shutdown, +}; + +static struct snd_soc_dai_link msm8952_tasha_fe_dai[] = { + /* tasha_vifeedback for speaker protection */ + { + .name = LPASS_BE_SLIMBUS_4_TX, + .stream_name = "Slimbus4 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16393", + .platform_name = "msm-pcm-hostless", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_vifeedback", + .id = MSM_BACKEND_DAI_SLIMBUS_4_TX, + .be_hw_params_fixup = msm_slim_4_tx_be_hw_params_fixup, + .ops = &msm8952_slimbus_be_ops, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + }, + /* Ultrasound RX DAI Link */ + { + .name = "SLIMBUS_2 Hostless Playback", + .stream_name = "SLIMBUS_2 Hostless Playback", + .cpu_dai_name = "msm-dai-q6-dev.16388", + .platform_name = "msm-pcm-hostless", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_rx2", + .ignore_suspend = 1, + .dpcm_playback = 1, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ops = &msm8952_slimbus_2_be_ops, + }, + /* Ultrasound TX DAI Link */ + { + .name = "SLIMBUS_2 Hostless Capture", + .stream_name = "SLIMBUS_2 Hostless Capture", + .cpu_dai_name = "msm-dai-q6-dev.16389", + .platform_name = "msm-pcm-hostless", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_tx2", + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ops = &msm8952_slimbus_2_be_ops, + }, + /* CPE LSM direct dai-link */ + { + .name = "CPE Listen service", + .stream_name = "CPE Listen Audio Service", + .cpu_dai_name = "msm-dai-slim", + .platform_name = "msm-cpe-lsm", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .dpcm_capture = 1, + .codec_dai_name = "tasha_mad1", + .codec_name = "tasha_codec", + .ops = &msm8952_cpe_ops, + }, + /* slimbus rx 6 hostless */ + { + .name = "SLIMBUS_6 Hostless Playback", + .stream_name = "SLIMBUS_6 Hostless", + .cpu_dai_name = "SLIMBUS6_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dailink has playback support */ + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + /* QCHAT */ + {/* hw:x,42 */ + .name = "QCHAT", + .stream_name = "QCHAT", + .cpu_dai_name = "QCHAT", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_QCHAT, + }, +}; + +static struct snd_soc_dai_link msm8952_tasha_be_dai[] = { + /* Backend DAI Links */ + { + .name = LPASS_BE_SLIMBUS_0_RX, + .stream_name = "Slimbus Playback", + .cpu_dai_name = "msm-dai-q6-dev.16384", + .platform_name = "msm-pcm-routing", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_mix_rx1", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_0_RX, + .init = &msm_audrx_init, + .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + .ops = &msm8952_slimbus_be_ops, + }, + { + .name = LPASS_BE_SLIMBUS_0_TX, + .stream_name = "Slimbus Capture", + .cpu_dai_name = "msm-dai-q6-dev.16385", + .platform_name = "msm-pcm-routing", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_tx1", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_0_TX, + .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup, + .ignore_suspend = 1, + .ops = &msm8952_slimbus_be_ops, + }, + { + .name = LPASS_BE_SLIMBUS_1_RX, + .stream_name = "Slimbus1 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16386", + .platform_name = "msm-pcm-routing", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_mix_rx1", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_1_RX, + .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup, + .ops = &msm8952_slimbus_be_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_1_TX, + .stream_name = "Slimbus1 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16387", + .platform_name = "msm-pcm-routing", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_tx3", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_1_TX, + .be_hw_params_fixup = msm_slim_1_tx_be_hw_params_fixup, + .ops = &msm8952_slimbus_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_3_RX, + .stream_name = "Slimbus3 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16390", + .platform_name = "msm-pcm-routing", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_mix_rx1", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_3_RX, + .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup, + .ops = &msm8952_slimbus_be_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_3_TX, + .stream_name = "Slimbus3 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16391", + .platform_name = "msm-pcm-routing", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_tx1", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_3_TX, + .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup, + .ops = &msm8952_slimbus_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_4_RX, + .stream_name = "Slimbus4 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16392", + .platform_name = "msm-pcm-routing", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_mix_rx1", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_4_RX, + .be_hw_params_fixup = msm_slim_4_rx_be_hw_params_fixup, + .ops = &msm8952_slimbus_be_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_5_RX, + .stream_name = "Slimbus5 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16394", + .platform_name = "msm-pcm-routing", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_rx3", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_5_RX, + .be_hw_params_fixup = msm_slim_5_rx_be_hw_params_fixup, + .ops = &msm8952_slimbus_be_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + /* MAD BE */ + { + .name = LPASS_BE_SLIMBUS_5_TX, + .stream_name = "Slimbus5 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16395", + .platform_name = "msm-pcm-routing", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_mad1", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_5_TX, + .be_hw_params_fixup = msm_slim_5_tx_be_hw_params_fixup, + .ops = &msm8952_slimbus_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_6_RX, + .stream_name = "Slimbus6 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16396", + .platform_name = "msm-pcm-routing", + .codec_name = "tasha_codec", + .codec_dai_name = "tasha_rx4", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_6_RX, + .be_hw_params_fixup = msm_slim_6_rx_be_hw_params_fixup, + .ops = &msm8952_slimbus_be_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, +}; + +static struct snd_soc_dai_link msm8952_common_fe_dai[] = { + /* FrontEnd DAI Links */ + {/* hw:x,0 */ + .name = "MSM8X16 Media1", + .stream_name = "MultiMedia1", + .cpu_dai_name = "MultiMedia1", + .platform_name = "msm-pcm-dsp.0", + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA1 + }, + {/* hw:x,1 */ + .name = "MSM8X16 Media2", + .stream_name = "MultiMedia2", + .cpu_dai_name = "MultiMedia2", + .platform_name = "msm-pcm-dsp.0", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA2, + }, + {/* hw:x,2 */ + .name = "Circuit-Switch Voice", + .stream_name = "CS-Voice", + .cpu_dai_name = "VoiceMMode1", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_CS_VOICE, + }, + {/* hw:x,3 */ + .name = "MSM VoIP", + .stream_name = "VoIP", + .cpu_dai_name = "VoIP", + .platform_name = "msm-voip-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_VOIP, + }, + {/* hw:x,4 */ + .name = "MSM8X16 ULL", + .stream_name = "ULL", + .cpu_dai_name = "MultiMedia3", + .platform_name = "msm-pcm-dsp.2", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA3, + }, + /* Hostless PCM purpose */ + {/* hw:x,5 */ + .name = "SLIMBUS_0 Hostless", + .stream_name = "SLIMBUS_0 Hostless", + .cpu_dai_name = "SLIMBUS0_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* This dai link has MI2S support */ + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + {/* hw:x,6 */ + .name = "INT_FM Hostless", + .stream_name = "INT_FM Hostless", + .cpu_dai_name = "INT_FM_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + {/* hw:x,7 */ + .name = "MSM AFE-PCM RX", + .stream_name = "AFE-PROXY RX", + .cpu_dai_name = "msm-dai-q6-dev.241", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .platform_name = "msm-pcm-afe", + .ignore_suspend = 1, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + }, + {/* hw:x,8 */ + .name = "MSM AFE-PCM TX", + .stream_name = "AFE-PROXY TX", + .cpu_dai_name = "msm-dai-q6-dev.240", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .platform_name = "msm-pcm-afe", + .ignore_suspend = 1, + }, + {/* hw:x,9 */ + .name = "MSM8X16 Compress1", + .stream_name = "Compress1", + .cpu_dai_name = "MultiMedia4", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dai link has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA4, + }, + {/* hw:x,10 */ + .name = "AUXPCM Hostless", + .stream_name = "AUXPCM Hostless", + .cpu_dai_name = "AUXPCM_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + {/* hw:x,11 */ + .name = "SLIMBUS_1 Hostless", + .stream_name = "SLIMBUS_1 Hostless", + .cpu_dai_name = "SLIMBUS1_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, /* dai link has playback support */ + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + {/* hw:x,12 */ + .name = "MSM8952 LowLatency", + .stream_name = "MultiMedia5", + .cpu_dai_name = "MultiMedia5", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA5, + }, + {/* hw:x,13 */ + .name = "Voice2", + .stream_name = "Voice2", + .cpu_dai_name = "VoiceMMode1", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_VOICE2, + }, + {/* hw:x,14 */ + .name = "MSM8952 Media9", + .stream_name = "MultiMedia9", + .cpu_dai_name = "MultiMedia9", + .platform_name = "msm-pcm-dsp.0", + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* This dailink has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA9, + }, + { /* hw:x,15 */ + .name = "VoLTE", + .stream_name = "VoLTE", + .cpu_dai_name = "VoiceMMode1", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_VOLTE, + }, + { /* hw:x,16 */ + .name = "VoWLAN", + .stream_name = "VoWLAN", + .cpu_dai_name = "VoiceMMode1", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_VOWLAN, + }, + {/* hw:x,17 */ + .name = "INT_HFP_BT Hostless", + .stream_name = "INT_HFP_BT Hostless", + .cpu_dai_name = "INT_HFP_BT_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + {/* hw:x,18 */ + .name = "MSM8916 HFP", + .stream_name = "MultiMedia6", + .cpu_dai_name = "MultiMedia6", + .platform_name = "msm-pcm-loopback", + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA6, + }, + /* LSM FE */ + {/* hw:x,19 */ + .name = "Listen 1 Audio Service", + .stream_name = "Listen 1 Audio Service", + .cpu_dai_name = "LSM1", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_LSM1, + }, + {/* hw:x,20 */ + .name = "Listen 2 Audio Service", + .stream_name = "Listen 2 Audio Service", + .cpu_dai_name = "LSM2", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_LSM2, + }, + {/* hw:x,21 */ + .name = "Listen 3 Audio Service", + .stream_name = "Listen 3 Audio Service", + .cpu_dai_name = "LSM3", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_LSM3, + }, + {/* hw:x,22 */ + .name = "Listen 4 Audio Service", + .stream_name = "Listen 4 Audio Service", + .cpu_dai_name = "LSM4", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_LSM4, + }, + {/* hw:x,23 */ + .name = "Listen 5 Audio Service", + .stream_name = "Listen 5 Audio Service", + .cpu_dai_name = "LSM5", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_LSM5, + }, + {/* hw:x,24 */ + .name = "MSM8X16 Compress2", + .stream_name = "Compress2", + .cpu_dai_name = "MultiMedia7", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA7, + }, + {/* hw:x,25 */ + .name = "SLIMBUS_3 Hostless", + .stream_name = "SLIMBUS_3 Hostless", + .cpu_dai_name = "SLIMBUS3_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, /* dai link has playback support */ + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + {/* hw:x,26 */ + .name = "SLIMBUS_4 Hostless", + .stream_name = "SLIMBUS_4 Hostless", + .cpu_dai_name = "SLIMBUS4_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, /* dai link has playback support */ + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { /* hw:x,27 */ + .name = "QUAT_MI2S Hostless", + .stream_name = "QUAT_MI2S Hostless", + .cpu_dai_name = "QUAT_MI2S_RX_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + {/* hw:x,28 */ + .name = "MSM8X16 MultiMedia10", + .stream_name = "MultiMedia10", + .cpu_dai_name = "MultiMedia10", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dai link has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA10, + }, + {/* hw:x,29 */ + .name = "MSM8X16 Compress4", + .stream_name = "Compress4", + .cpu_dai_name = "MultiMedia11", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dai link has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA11, + }, + {/* hw:x,30 */ + .name = "MSM8X16 Compress5", + .stream_name = "Compress5", + .cpu_dai_name = "MultiMedia12", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dai link has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA12, + }, + {/* hw:x,31 */ + .name = "MSM8X16 Compress6", + .stream_name = "Compress6", + .cpu_dai_name = "MultiMedia13", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dai link has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA13, + }, + {/* hw:x,32 */ + .name = "MSM8X16 Compress7", + .stream_name = "Compress7", + .cpu_dai_name = "MultiMedia14", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dai link has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA14, + }, + {/* hw:x,33 */ + .name = "MSM8X16 Compress8", + .stream_name = "Compress8", + .cpu_dai_name = "MultiMedia15", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dai link has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA15, + }, + {/* hw:x,34 */ + .name = "MSM8X16 Compress9", + .stream_name = "Compress9", + .cpu_dai_name = "MultiMedia16", + .platform_name = "msm-pcm-dsp-noirq", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dai link has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA16, + }, + {/* hw:x,35 */ + .name = "VoiceMMode1", + .stream_name = "VoiceMMode1", + .cpu_dai_name = "VoiceMMode1", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_VOICEMMODE1, + }, + {/* hw:x,36 */ + .name = "VoiceMMode2", + .stream_name = "VoiceMMode2", + .cpu_dai_name = "VoiceMMode2", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_VOICEMMODE2, + }, + {/* hw:x,37 */ + .name = "MSM8X16 Compress10", + .stream_name = "Compress10", + .cpu_dai_name = "MultiMedia17", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dai link has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA17, + }, + {/* hw:x,38 */ + .name = "MSM8X16 Compress11", + .stream_name = "Compress11", + .cpu_dai_name = "MultiMedia18", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dai link has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA18, + }, + {/* hw:x,39 */ + .name = "MSM8X16 Compress12", + .stream_name = "Compress12", + .cpu_dai_name = "MultiMedia19", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dai link has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA19, + }, +}; + +static struct snd_soc_dai_link msm8952_tdm_fe_dai[] = { + /* FE TDM DAI links */ + { + .name = "Primary TDM RX 0 Hostless", + .stream_name = "Primary TDM RX 0 Hostless", + .cpu_dai_name = "PRI_TDM_RX_0_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "Primary TDM TX 0 Hostless", + .stream_name = "Primary TDM TX 0 Hostless", + .cpu_dai_name = "PRI_TDM_TX_0_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "Secondary TDM RX 0 Hostless", + .stream_name = "Secondary TDM RX 0 Hostless", + .cpu_dai_name = "SEC_TDM_RX_0_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "Secondary TDM TX 0 Hostless", + .stream_name = "Secondary TDM TX 0 Hostless", + .cpu_dai_name = "SEC_TDM_TX_0_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, +}; + +static struct snd_soc_dai_link msm8952_common_be_dai[] = { + /* Backend I2S DAI Links */ + { + .name = LPASS_BE_QUAT_MI2S_RX, + .stream_name = "Quaternary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.3", + .platform_name = "msm-pcm-routing", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm8952_quat_mi2s_be_ops, + .ignore_pmdown_time = 1, /* dai link has playback support */ + .ignore_suspend = 1, + }, + /* Primary AUX PCM Backend DAI Links */ + { + .name = LPASS_BE_AUXPCM_RX, + .stream_name = "AUX PCM Playback", + .cpu_dai_name = "msm-dai-q6-auxpcm.1", + .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_AUXPCM_RX, + .be_hw_params_fixup = msm_auxpcm_be_params_fixup, + .ops = &msm_pri_auxpcm_be_ops, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_AUXPCM_TX, + .stream_name = "AUX PCM Capture", + .cpu_dai_name = "msm-dai-q6-auxpcm.1", + .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_AUXPCM_TX, + .be_hw_params_fixup = msm_auxpcm_be_params_fixup, + .ops = &msm_pri_auxpcm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_QUAT_MI2S_TX, + .stream_name = "Quaternary MI2S Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.3", + .platform_name = "msm-pcm-routing", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm8952_quat_mi2s_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_INT_BT_SCO_RX, + .stream_name = "Internal BT-SCO Playback", + .cpu_dai_name = "msm-dai-q6-dev.12288", + .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_INT_BT_SCO_RX, + .be_hw_params_fixup = msm_btsco_be_hw_params_fixup, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_INT_BT_SCO_TX, + .stream_name = "Internal BT-SCO Capture", + .cpu_dai_name = "msm-dai-q6-dev.12289", + .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_INT_BT_SCO_TX, + .be_hw_params_fixup = msm_btsco_be_hw_params_fixup, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_INT_FM_RX, + .stream_name = "Internal FM Playback", + .cpu_dai_name = "msm-dai-q6-dev.12292", + .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_INT_FM_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_INT_FM_TX, + .stream_name = "Internal FM Capture", + .cpu_dai_name = "msm-dai-q6-dev.12293", + .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_INT_FM_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_AFE_PCM_RX, + .stream_name = "AFE Playback", + .cpu_dai_name = "msm-dai-q6-dev.224", + .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_AFE_PCM_RX, + .be_hw_params_fixup = msm_proxy_rx_be_hw_params_fixup, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_AFE_PCM_TX, + .stream_name = "AFE Capture", + .cpu_dai_name = "msm-dai-q6-dev.225", + .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_AFE_PCM_TX, + .be_hw_params_fixup = msm_proxy_tx_be_hw_params_fixup, + .ignore_suspend = 1, + }, + /* 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_pmdown_time = 1, + .ignore_suspend = 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_pmdown_time = 1, + .ignore_suspend = 1, + }, + + { + .name = LPASS_BE_QUIN_MI2S_TX, + .stream_name = "Quinary MI2S Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.5", + .platform_name = "msm-pcm-routing", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_QUINARY_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm8952_quin_mi2s_be_ops, + .ignore_suspend = 1, + }, + /* Proxy Tx BACK END DAI Link */ + { + .name = LPASS_BE_PROXY_TX, + .stream_name = "Proxy Capture", + .cpu_dai_name = "msm-dai-q6-dev.8195", + .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_PROXY_TX, + .ignore_suspend = 1, + }, + /* Proxy Rx BACK END DAI Link */ + { + .name = LPASS_BE_PROXY_RX, + .stream_name = "Proxy Playback", + .cpu_dai_name = "msm-dai-q6-dev.8194", + .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_PROXY_RX, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, +}; + +static struct snd_soc_dai_link msm8952_hdmi_dba_dai_link[] = { + { + .name = LPASS_BE_QUIN_MI2S_RX, + .stream_name = "Quinary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.5", + .platform_name = "msm-pcm-routing", + .codec_dai_name = "msm_hdmi_dba_codec_rx_dai", + .codec_name = "msm-hdmi-dba-codec-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_QUINARY_MI2S_RX, + .be_hw_params_fixup = msm_quin_be_hw_params_fixup, + .ops = &msm8952_quin_mi2s_be_ops, + .ignore_pmdown_time = 1, /* dai link has playback support */ + .ignore_suspend = 1, + }, +}; + +static struct snd_soc_dai_link msm8952_quin_dai_link[] = { + { + .name = LPASS_BE_QUIN_MI2S_RX, + .stream_name = "Quinary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.5", + .platform_name = "msm-pcm-routing", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_QUINARY_MI2S_RX, + .be_hw_params_fixup = msm_quin_be_hw_params_fixup, + .ops = &msm8952_quin_mi2s_be_ops, + .ignore_pmdown_time = 1, /* dai link has playback support */ + .ignore_suspend = 1, + }, +}; + +static struct snd_soc_dai_link msm8952_tdm_be_dai_link[] = { + /* TDM be dai links */ + { + .name = LPASS_BE_PRI_TDM_RX_0, + .stream_name = "Primary TDM0 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36864", + .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_PRI_TDM_RX_0, + .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_PRI_TDM_TX_0, + .stream_name = "Primary TDM0 Capture", + .cpu_dai_name = "msm-dai-q6-tdm.36865", + .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_PRI_TDM_TX_0, + .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SEC_TDM_RX_0, + .stream_name = "Secondary TDM0 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36880", + .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_SEC_TDM_RX_0, + .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SEC_TDM_TX_0, + .stream_name = "Secondary TDM0 Capture", + .cpu_dai_name = "msm-dai-q6-tdm.36881", + .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_SEC_TDM_TX_0, + .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, +}; + +struct msm895x_wsa881x_dev_info { + struct device_node *of_node; + u32 index; +}; + +static struct snd_soc_aux_dev *msm895x_aux_dev; +static struct snd_soc_codec_conf *msm895x_codec_conf; + +static struct snd_soc_dai_link msm8952_tasha_dai_links[ +ARRAY_SIZE(msm8952_common_fe_dai) + +ARRAY_SIZE(msm8952_tasha_fe_dai) + +ARRAY_SIZE(msm8952_tdm_fe_dai) + +ARRAY_SIZE(msm8952_common_be_dai) + +ARRAY_SIZE(msm8952_tasha_be_dai) + +ARRAY_SIZE(msm8952_hdmi_dba_dai_link) + +ARRAY_SIZE(msm8952_tdm_be_dai_link)]; + +int msm8952_init_wsa_dev(struct platform_device *pdev, + struct snd_soc_card *card) +{ + struct device_node *wsa_of_node; + u32 wsa_max_devs; + u32 wsa_dev_cnt; + char *dev_name_str = NULL; + struct msm895x_wsa881x_dev_info *wsa881x_dev_info; + const char *wsa_auxdev_name_prefix[1]; + int found = 0; + int i; + int ret; + + /* Get maximum WSA device count for this platform */ + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,wsa-max-devs", &wsa_max_devs); + if (ret) { + dev_dbg(&pdev->dev, + "%s: wsa-max-devs property missing in DT %s, ret = %d\n", + __func__, pdev->dev.of_node->full_name, ret); + card->num_aux_devs = 0; + return 0; + } + if (wsa_max_devs == 0) { + dev_warn(&pdev->dev, + "%s: Max WSA devices is 0 for this target?\n", + __func__); + card->num_aux_devs = 0; + return 0; + } + + /* Get count of WSA device phandles for this platform */ + wsa_dev_cnt = of_count_phandle_with_args(pdev->dev.of_node, + "qcom,wsa-devs", NULL); + if (wsa_dev_cnt == -ENOENT) { + dev_warn(&pdev->dev, "%s: No wsa device defined in DT.\n", + __func__); + return 0; + } else if (wsa_dev_cnt <= 0) { + dev_err(&pdev->dev, + "%s: Error reading wsa device from DT. wsa_dev_cnt = %d\n", + __func__, wsa_dev_cnt); + return -EINVAL; + } + + /* + * Expect total phandles count to be NOT less than maximum possible + * WSA count. However, if it is less, then assign same value to + * max count as well. + */ + + if (wsa_dev_cnt < wsa_max_devs) { + dev_dbg(&pdev->dev, + "%s: wsa_max_devs = %d cannot exceed wsa_dev_cnt = %d\n", + __func__, wsa_max_devs, wsa_dev_cnt); + wsa_max_devs = wsa_dev_cnt; + } + + /* 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 != wsa_dev_cnt) { + dev_err(&pdev->dev, + "%s: expecting %d wsa prefix. Defined only %d in DT\n", + __func__, wsa_dev_cnt, ret); + return -EINVAL; + } + + /* + * Alloc mem to store phandle and index info of WSA device, if already + * registered with ALSA core + */ + wsa881x_dev_info = devm_kcalloc(&pdev->dev, wsa_max_devs, + sizeof(struct msm895x_wsa881x_dev_info), + GFP_KERNEL); + if (!wsa881x_dev_info) + return -ENOMEM; + + /* + * search and check whether all WSA devices are already + * registered with ALSA core or not. If found a node, store + * the node and the index in a local array of struct for later + * use. + */ + for (i = 0; i < wsa_dev_cnt; i++) { + wsa_of_node = of_parse_phandle(pdev->dev.of_node, + "qcom,wsa-devs", i); + if (unlikely(!wsa_of_node)) { + /* we should not be here */ + dev_err(&pdev->dev, + "%s: wsa dev node is not present\n", + __func__); + ret = -EINVAL; + goto err_free_dev_info; + } + if (soc_find_component(wsa_of_node, NULL)) { + /* WSA device registered with ALSA core */ + wsa881x_dev_info[found].of_node = wsa_of_node; + wsa881x_dev_info[found].index = i; + found++; + if (found == wsa_max_devs) + break; + } + } + + if (found < wsa_max_devs) { + dev_dbg(&pdev->dev, + "%s: failed to find %d components. Found only %d\n", + __func__, wsa_max_devs, found); + return -EPROBE_DEFER; + } + dev_info(&pdev->dev, + "%s: found %d wsa881x devices registered with ALSA core\n", + __func__, found); + + card->num_aux_devs = wsa_max_devs; + card->num_configs = wsa_max_devs; + + /* Alloc array of AUX devs struct */ + msm895x_aux_dev = devm_kcalloc(&pdev->dev, card->num_aux_devs, + sizeof(struct snd_soc_aux_dev), + GFP_KERNEL); + if (!msm895x_aux_dev) { + ret = -ENOMEM; + goto err_free_dev_info; + } + + /* Alloc array of codec conf struct */ + msm895x_codec_conf = devm_kcalloc(&pdev->dev, card->num_aux_devs, + sizeof(struct snd_soc_codec_conf), + GFP_KERNEL); + if (!msm895x_codec_conf) { + ret = -ENOMEM; + goto err_free_aux_dev; + } + + for (i = 0; i < card->num_aux_devs; i++) { + dev_name_str = devm_kzalloc(&pdev->dev, DEV_NAME_STR_LEN, + GFP_KERNEL); + if (!dev_name_str) { + ret = -ENOMEM; + goto err_free_cdc_conf; + } + + ret = of_property_read_string_index(pdev->dev.of_node, + "qcom,wsa-aux-dev-prefix", + wsa881x_dev_info[i].index, + wsa_auxdev_name_prefix); + if (ret) { + dev_err(&pdev->dev, + "%s: failed to read wsa aux dev prefix, ret = %d\n", + __func__, ret); + ret = -EINVAL; + goto err_free_dev_name_str; + } + + snprintf(dev_name_str, strlen("wsa881x.%d"), "wsa881x.%d", i); + msm895x_aux_dev[i].name = dev_name_str; + msm895x_aux_dev[i].codec_name = NULL; + msm895x_aux_dev[i].codec_of_node = + wsa881x_dev_info[i].of_node; + msm895x_aux_dev[i].init = msm895x_wsa881x_init; + msm895x_codec_conf[i].dev_name = NULL; + msm895x_codec_conf[i].name_prefix = wsa_auxdev_name_prefix[0]; + msm895x_codec_conf[i].of_node = + wsa881x_dev_info[i].of_node; + } + card->codec_conf = msm895x_codec_conf; + card->aux_dev = msm895x_aux_dev; + + return 0; +err_free_dev_name_str: + devm_kfree(&pdev->dev, dev_name_str); +err_free_cdc_conf: + devm_kfree(&pdev->dev, msm895x_codec_conf); +err_free_aux_dev: + devm_kfree(&pdev->dev, msm895x_aux_dev); +err_free_dev_info: + devm_kfree(&pdev->dev, wsa881x_dev_info); + + return ret; +} + +struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) +{ + struct snd_soc_card *card = &snd_soc_card_msm_card; + struct snd_soc_dai_link *msm8952_dai_links = NULL; + int num_links, ret, len1, len2, len3, len4, len5 = 0; + enum codec_variant codec_ver = 0; + const char *tasha_lite[NUM_OF_TASHA_LITE_DEVICE] = { + "msm8952-tashalite-snd-card", + "msm8953-tashalite-snd-card" + }; + + card->dev = dev; + ret = snd_soc_of_parse_card_name(card, "qcom,model"); + if (ret) { + dev_err(dev, "%s: parse card name failed, err:%d\n", + __func__, ret); + return NULL; + } + if (strnstr(card->name, "tasha", strlen(card->name))) { + codec_ver = tasha_codec_ver(); + if (codec_ver == WCD9XXX) + return NULL; + if (codec_ver == WCD9326) { + if (!strcmp(card->name, "msm8952-tasha-snd-card")) + card->name = tasha_lite[MSM8952_TASHA_LITE]; + else if (!strcmp(card->name, "msm8953-tasha-snd-card")) + card->name = tasha_lite[MSM8953_TASHA_LITE]; + } + + len1 = ARRAY_SIZE(msm8952_common_fe_dai); + len2 = len1 + ARRAY_SIZE(msm8952_tasha_fe_dai); + len3 = len2 + ARRAY_SIZE(msm8952_tdm_fe_dai); + len4 = len3 + ARRAY_SIZE(msm8952_common_be_dai); + len5 = len4 + ARRAY_SIZE(msm8952_tasha_be_dai); + snd_soc_card_msm_card.name = card->name; + card = &snd_soc_card_msm_card; + num_links = ARRAY_SIZE(msm8952_tasha_dai_links); + memcpy(msm8952_tasha_dai_links, msm8952_common_fe_dai, + sizeof(msm8952_common_fe_dai)); + memcpy(msm8952_tasha_dai_links + len1, + msm8952_tasha_fe_dai, sizeof(msm8952_tasha_fe_dai)); + memcpy(msm8952_tasha_dai_links + len2, + msm8952_tdm_fe_dai, sizeof(msm8952_tdm_fe_dai)); + memcpy(msm8952_tasha_dai_links + len3, + msm8952_common_be_dai, sizeof(msm8952_common_be_dai)); + memcpy(msm8952_tasha_dai_links + len4, + msm8952_tasha_be_dai, sizeof(msm8952_tasha_be_dai)); + msm8952_dai_links = msm8952_tasha_dai_links; + } + if (of_property_read_bool(dev->of_node, "qcom,hdmi-dba-codec-rx")) { + dev_dbg(dev, "%s(): hdmi dba audio support present\n", + __func__); + memcpy(msm8952_dai_links + len5, msm8952_hdmi_dba_dai_link, + sizeof(msm8952_hdmi_dba_dai_link)); + len5 += ARRAY_SIZE(msm8952_hdmi_dba_dai_link); + } else { + dev_dbg(dev, "%s(): No hdmi dba present, add quin dai\n", + __func__); + memcpy(msm8952_dai_links + len5, msm8952_quin_dai_link, + sizeof(msm8952_quin_dai_link)); + len5 += ARRAY_SIZE(msm8952_quin_dai_link); + } + if (of_property_read_bool(dev->of_node, "qcom,tdm-audio-intf")) { + dev_dbg(dev, "%s(): TDM support present\n", + __func__); + memcpy(msm8952_dai_links + len5, msm8952_tdm_be_dai_link, + sizeof(msm8952_tdm_be_dai_link)); + len5 += ARRAY_SIZE(msm8952_tdm_be_dai_link); + } + card->dai_link = msm8952_dai_links; + card->num_links = len5; + card->dev = dev; + return card; +} + +void msm895x_free_auxdev_mem(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + int i; + + if (card->num_aux_devs > 0) { + for (i = 0; i < card->num_aux_devs; i++) { + kfree(msm895x_aux_dev[i].codec_name); + kfree(msm895x_codec_conf[i].dev_name); + kfree(msm895x_codec_conf[i].name_prefix); + } + } +} diff --git a/asoc/msm8952-slimbus.c b/asoc/msm8952-slimbus.c new file mode 100644 index 000000000000..9fa6d6af53e7 --- /dev/null +++ b/asoc/msm8952-slimbus.c @@ -0,0 +1,3845 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2015-2018, 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 "msm-pcm-routing-v2.h" +#include +#include "codecs/wcd9335.h" +#include +#include "codecs/wsa881x.h" +#include "msm8952-slimbus.h" + +#define DRV_NAME "msm8952-slimbus-wcd" + +#define BTSCO_RATE_8KHZ 8000 +#define BTSCO_RATE_16KHZ 16000 +#define SAMPLING_RATE_8KHZ 8000 +#define SAMPLING_RATE_16KHZ 16000 +#define SAMPLING_RATE_32KHZ 32000 +#define SAMPLING_RATE_48KHZ 48000 +#define SAMPLING_RATE_96KHZ 96000 +#define SAMPLING_RATE_192KHZ 192000 +#define SAMPLING_RATE_44P1KHZ 44100 + +#define MSM8952_SPK_ON 1 +#define MSM8952_SPK_OFF 0 + +#define WCD9XXX_MBHC_DEF_BUTTONS 8 +#define WCD9XXX_MBHC_DEF_RLOADS 5 +#define CODEC_EXT_CLK_RATE 9600000 + +#define PRI_MI2S_ID (1 << 0) +#define SEC_MI2S_ID (1 << 1) +#define TER_MI2S_ID (1 << 2) +#define QUAT_MI2S_ID (1 << 3) +#define QUIN_MI2S_ID (1 << 4) + +#define HS_STARTWORK_TIMEOUT 4000 + +#define Q6AFE_LPASS_OSR_CLK_9_P600_MHZ 0x927C00 +#define MAX_AUX_CODECS 4 + +#define WSA8810_NAME_1 "wsa881x.20170211" +#define WSA8810_NAME_2 "wsa881x.20170212" + +#define TDM_SLOT_OFFSET_MAX 8 + +enum btsco_rates { + RATE_8KHZ_ID, + RATE_16KHZ_ID, +}; + +enum { + PRIMARY_TDM_RX_0, + PRIMARY_TDM_TX_0, + SECONDARY_TDM_RX_0, + SECONDARY_TDM_TX_0, + TDM_MAX, +}; + +static int slim0_rx_sample_rate = SAMPLING_RATE_48KHZ; +static int slim0_tx_sample_rate = SAMPLING_RATE_48KHZ; +static int slim1_tx_sample_rate = SAMPLING_RATE_48KHZ; +static int slim2_tx_sample_rate = SAMPLING_RATE_48KHZ; +static int slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; +static int slim0_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE; +static int slim1_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE; +static int slim2_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE; +static int msm_slim_0_rx_ch = 1; +static int msm_slim_0_tx_ch = 1; +static int msm_slim_1_tx_ch = 1; +static int msm_slim_2_tx_ch = 1; +static int msm_vi_feed_tx_ch = 2; +static int msm_slim_5_rx_ch = 1; +static int msm_slim_6_rx_ch = 1; +static int slim5_rx_sample_rate = SAMPLING_RATE_48KHZ; +static int slim5_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; +static int slim6_rx_sample_rate = SAMPLING_RATE_48KHZ; +static int slim6_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; +static int msm8952_auxpcm_rate = SAMPLING_RATE_8KHZ; +static int slim4_rx_sample_rate = SAMPLING_RATE_48KHZ; +static int slim4_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; +static int msm_slim_4_rx_ch = 1; +static int msm_btsco_rate = SAMPLING_RATE_8KHZ; +static int msm_btsco_ch = 1; +static int msm8952_spk_control = 1; + +static bool codec_reg_done; + +static int mi2s_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; + +static int msm_proxy_rx_ch = 2; +static void *adsp_state_notifier; + +/* TDM default channels */ +static int msm_pri_tdm_rx_0_ch = 8; +static int msm_pri_tdm_tx_0_ch = 8; + +static int msm_sec_tdm_rx_0_ch = 8; +static int msm_sec_tdm_tx_0_ch = 8; + +/* TDM default bit format */ +static int msm_pri_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; +static int msm_pri_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; + +static int msm_sec_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; +static int msm_sec_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; + +/* TDM default sampling rate */ +static int msm_pri_tdm_rx_0_sample_rate = SAMPLING_RATE_48KHZ; +static int msm_pri_tdm_tx_0_sample_rate = SAMPLING_RATE_48KHZ; + +static int msm_sec_tdm_rx_0_sample_rate = SAMPLING_RATE_48KHZ; +static int msm_sec_tdm_tx_0_sample_rate = SAMPLING_RATE_48KHZ; + +static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", "Eight"}; +static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE", + "S32_LE"}; +static char const *tdm_sample_rate_text[] = {"KHZ_16", "KHZ_48"}; + +/* TDM default offset */ +static unsigned int tdm_slot_offset[TDM_MAX][TDM_SLOT_OFFSET_MAX] = { + /* PRI_TDM_RX */ + {0, 4, 8, 12, 16, 20, 24, 28}, + /* PRI_TDM_TX */ + {0, 4, 8, 12, 16, 20, 24, 28}, + /* SEC_TDM_RX */ + {0, 4, 8, 12, 16, 20, 24, 28}, + /* SEC_TDM_TX */ + {0, 4, 8, 12, 16, 20, 24, 28}, +}; + +static int msm8952_enable_codec_mclk(struct snd_soc_component *component, + int enable, bool dapm); + +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, +}; + +static void *def_tasha_mbhc_cal(void) +{ + void *tasha_wcd_cal; + struct wcd_mbhc_btn_detect_cfg *btn_cfg; + u16 *btn_high; + + tasha_wcd_cal = kzalloc(WCD_MBHC_CAL_SIZE(WCD_MBHC_DEF_BUTTONS, + WCD9XXX_MBHC_DEF_RLOADS), GFP_KERNEL); + if (!tasha_wcd_cal) + return NULL; + +#define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(tasha_wcd_cal)->X) = (Y)) + S(v_hs_max, 1500); +#undef S +#define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(tasha_wcd_cal)->X) = (Y)) + S(num_btn, WCD_MBHC_DEF_BUTTONS); +#undef S + + btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(tasha_wcd_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] = 450; + btn_high[4] = 450; + btn_high[5] = 450; + btn_high[6] = 450; + btn_high[7] = 450; + + return tasha_wcd_cal; +} + +static struct afe_clk_set mi2s_tx_clk = { + AFE_API_VERSION_I2S_CONFIG, + Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT, + Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, +}; + +static struct afe_clk_set mi2s_rx_clk = { + AFE_API_VERSION_I2S_CONFIG, + Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT, + Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, +}; + +struct msm895x_auxcodec_prefix_map { + char codec_name[50]; + char codec_prefix[25]; +}; + +static inline int param_is_mask(int p) +{ + return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) && + (p <= SNDRV_PCM_HW_PARAM_LAST_MASK); +} + +static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n) +{ + return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]); +} + +int msm895x_wsa881x_init(struct snd_soc_component *component) +{ + u8 spkleft_ports[WSA881X_MAX_SWR_PORTS] = {100, 101, 102, 106}; + u8 spkright_ports[WSA881X_MAX_SWR_PORTS] = {103, 104, 105, 107}; + unsigned int ch_rate[WSA881X_MAX_SWR_PORTS] = {2400, 600, 300, 1200}; + unsigned int ch_mask[WSA881X_MAX_SWR_PORTS] = {0x1, 0xF, 0x3, 0x3}; + struct msm8952_asoc_mach_data *pdata; + struct snd_soc_dapm_context *dapm; + + if (!component) { + pr_err("%s component is NULL\n", __func__); + return -EINVAL; + } + dapm = snd_soc_component_get_dapm(component); + + if (!strcmp(component->name_prefix, "SpkrLeft")) { + dev_dbg(component->dev, "%s: setting left ch map to codec %s\n", + __func__, component->name); + wsa881x_set_channel_map(component, &spkleft_ports[0], + WSA881X_MAX_SWR_PORTS, &ch_mask[0], + &ch_rate[0], NULL); + if (dapm->component) { + snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft IN"); + snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft SPKR"); + } + } else if (!strcmp(component->name_prefix, "SpkrRight")) { + dev_dbg(component->dev, "%s: setting right ch map to codec %s\n", + __func__, component->name); + wsa881x_set_channel_map(component, &spkright_ports[0], + WSA881X_MAX_SWR_PORTS, &ch_mask[0], + &ch_rate[0], NULL); + if (dapm->component) { + snd_soc_dapm_ignore_suspend(dapm, "SpkrRight IN"); + snd_soc_dapm_ignore_suspend(dapm, "SpkrRight SPKR"); + } + } else { + dev_err(component->dev, "%s: wrong codec name %s\n", __func__, + component->name); + return -EINVAL; + } + + + pdata = snd_soc_card_get_drvdata(component->card); + if (pdata && pdata->codec_root) + wsa881x_codec_info_create_codec_entry(pdata->codec_root, + component); + return 0; +} + +static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned int bit) +{ + if (bit >= SNDRV_MASK_MAX) + return; + if (param_is_mask(n)) { + struct snd_mask *m = param_to_mask(p, n); + + m->bits[0] = 0; + m->bits[1] = 0; + m->bits[bit >> 5] |= (1 << (bit & 31)); + } +} + +static void msm8952_ext_control(struct snd_soc_component *codec) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(codec); + + pr_debug("%s: msm8952_spk_control = %d\n", + __func__, msm8952_spk_control); + if (msm8952_spk_control == MSM8952_SPK_ON) { + snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp"); + snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp"); + } else { + snd_soc_dapm_disable_pin(dapm, "Lineout_1 amp"); + snd_soc_dapm_disable_pin(dapm, "Lineout_3 amp"); + } + snd_soc_dapm_sync(dapm); +} + +static int msm8952_get_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm8952_spk_control = %d\n", + __func__, msm8952_spk_control); + ucontrol->value.integer.value[0] = msm8952_spk_control; + return 0; +} + +static int msm8952_set_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + pr_debug("%s()\n", __func__); + if (msm8952_spk_control == ucontrol->value.integer.value[0]) + return 0; + + msm8952_spk_control = ucontrol->value.integer.value[0]; + msm8952_ext_control(component); + return 1; +} + + +static int msm8952_enable_codec_mclk(struct snd_soc_component *component, + int enable, bool dapm) +{ + int ret; + + pr_debug("%s: enable = %d\n", __func__, enable); + if (!strcmp(dev_name(component->dev), "tasha_codec")) + ret = tasha_cdc_mclk_enable(component, enable, dapm); + else { + dev_err(component->dev, "%s: unknown codec to enable ext clk\n", + __func__); + ret = -EINVAL; + } + return ret; +} + +static int slim5_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate_val = 0; + + switch (slim5_rx_sample_rate) { + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 3; + break; + + case SAMPLING_RATE_192KHZ: + sample_rate_val = 2; + break; + + case SAMPLING_RATE_96KHZ: + sample_rate_val = 1; + break; + + case SAMPLING_RATE_48KHZ: + default: + sample_rate_val = 0; + break; + } + + ucontrol->value.integer.value[0] = sample_rate_val; + pr_debug("%s: slim5_rx_sample_rate = %d\n", __func__, + slim5_rx_sample_rate); + + return 0; +} + +static int slim5_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: ucontrol value = %ld\n", __func__, + ucontrol->value.integer.value[0]); + + switch (ucontrol->value.integer.value[0]) { + case 3: + slim5_rx_sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 2: + slim5_rx_sample_rate = SAMPLING_RATE_192KHZ; + break; + case 1: + slim5_rx_sample_rate = SAMPLING_RATE_96KHZ; + break; + case 0: + default: + slim5_rx_sample_rate = SAMPLING_RATE_48KHZ; + } + + pr_debug("%s: slim5_rx_sample_rate = %d\n", __func__, + slim5_rx_sample_rate); + + return 0; +} + +static int mi2s_rx_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + switch (mi2s_rx_bit_format) { + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + + pr_debug("%s: mi2s_rx_bit_format = %d, ucontrol value = %ld\n", + __func__, mi2s_rx_bit_format, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int mi2s_rx_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 2: + mi2s_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + mi2s_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + mi2s_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + return 0; +} + +static int msm_slim_1_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_slim_1_tx_ch = %d\n", __func__, + msm_slim_1_tx_ch); + ucontrol->value.integer.value[0] = msm_slim_1_tx_ch - 1; + return 0; +} + +static int msm_slim_1_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_slim_1_tx_ch = ucontrol->value.integer.value[0] + 1; + + pr_debug("%s: msm_slim_1_tx_ch = %d\n", __func__, msm_slim_1_tx_ch); + return 1; +} + +static int slim0_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate_val = 0; + + switch (slim0_rx_sample_rate) { + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 3; + break; + + case SAMPLING_RATE_192KHZ: + sample_rate_val = 2; + break; + + case SAMPLING_RATE_96KHZ: + sample_rate_val = 1; + break; + + case SAMPLING_RATE_48KHZ: + default: + sample_rate_val = 0; + break; + } + + ucontrol->value.integer.value[0] = sample_rate_val; + pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__, + slim0_rx_sample_rate); + + return 0; +} + +static int slim0_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: ucontrol value = %ld\n", __func__, + ucontrol->value.integer.value[0]); + + switch (ucontrol->value.integer.value[0]) { + case 3: + slim0_rx_sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 2: + slim0_rx_sample_rate = SAMPLING_RATE_192KHZ; + break; + case 1: + slim0_rx_sample_rate = SAMPLING_RATE_96KHZ; + break; + case 0: + default: + slim0_rx_sample_rate = SAMPLING_RATE_48KHZ; + } + + pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__, + slim0_rx_sample_rate); + + return 0; +} + +static int slim4_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate_val = 0; + + switch (slim4_rx_sample_rate) { + case SAMPLING_RATE_16KHZ: + sample_rate_val = 4; + break; + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 3; + break; + + case SAMPLING_RATE_192KHZ: + sample_rate_val = 2; + break; + + case SAMPLING_RATE_96KHZ: + sample_rate_val = 1; + break; + + case SAMPLING_RATE_48KHZ: + default: + sample_rate_val = 0; + break; + } + + ucontrol->value.integer.value[0] = sample_rate_val; + pr_debug("%s: slim4_rx_sample_rate = %d\n", __func__, + slim4_rx_sample_rate); + + return 0; +} + +static int slim4_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: ucontrol value = %ld\n", __func__, + ucontrol->value.integer.value[0]); + + switch (ucontrol->value.integer.value[0]) { + case 4: + slim4_rx_sample_rate = SAMPLING_RATE_16KHZ; + break; + case 3: + slim4_rx_sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 2: + slim4_rx_sample_rate = SAMPLING_RATE_192KHZ; + break; + case 1: + slim4_rx_sample_rate = SAMPLING_RATE_96KHZ; + break; + case 0: + default: + slim4_rx_sample_rate = SAMPLING_RATE_48KHZ; + } + + pr_debug("%s: slim4_rx_sample_rate = %d\n", __func__, + slim4_rx_sample_rate); + + return 0; +} + +static int slim5_rx_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + switch (slim5_rx_bit_format) { + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + + pr_debug("%s: slim5_rx_bit_format = %d, ucontrol value = %ld\n", + __func__, slim5_rx_bit_format, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int slim5_rx_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 2: + slim5_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + slim5_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + slim5_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + return 0; +} +static int slim6_rx_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + switch (slim6_rx_bit_format) { + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + + pr_debug("%s: slim6_rx_bit_format = %d, ucontrol value = %ld\n", + __func__, slim6_rx_bit_format, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int slim6_rx_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 2: + slim6_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + slim6_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + slim6_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + return 1; +} +static int slim6_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate_val = 0; + + switch (slim6_rx_sample_rate) { + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 3; + break; + + case SAMPLING_RATE_192KHZ: + sample_rate_val = 2; + break; + + case SAMPLING_RATE_96KHZ: + sample_rate_val = 1; + break; + + case SAMPLING_RATE_48KHZ: + default: + sample_rate_val = 0; + break; + } + + ucontrol->value.integer.value[0] = sample_rate_val; + pr_debug("%s: slim6_rx_sample_rate = %d\n", __func__, + slim6_rx_sample_rate); + + return 0; +} + +static int slim6_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 3: + slim6_rx_sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 2: + slim6_rx_sample_rate = SAMPLING_RATE_192KHZ; + break; + case 1: + slim6_rx_sample_rate = SAMPLING_RATE_96KHZ; + break; + case 0: + default: + slim6_rx_sample_rate = SAMPLING_RATE_48KHZ; + break; + } + + pr_debug("%s: ucontrol value = %ld, slim6_rx_sample_rate = %d\n", + __func__, ucontrol->value.integer.value[0], + slim6_rx_sample_rate); + + return 1; +} + +static int slim0_rx_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + switch (slim0_rx_bit_format) { + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + + pr_debug("%s: slim0_rx_bit_format = %d, ucontrol value = %ld\n", + __func__, slim0_rx_bit_format, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int slim0_rx_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 2: + slim0_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + slim0_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + return 0; +} + +static int slim4_rx_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + switch (slim4_rx_bit_format) { + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + + pr_debug("%s: slim4_rx_bit_format = %d, ucontrol value = %ld\n", + __func__, slim4_rx_bit_format, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int slim4_rx_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 2: + slim4_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + slim4_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + slim4_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + return 0; +} + +static int msm_vi_feed_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + if (!strcmp(dev_name(component->dev), "tasha_codec")) + ucontrol->value.integer.value[0] = + (msm_vi_feed_tx_ch - 1); + else + ucontrol->value.integer.value[0] = + (msm_vi_feed_tx_ch/2 - 1); + + pr_debug("%s: msm_vi_feed_tx_ch = %ld\n", __func__, + ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_vi_feed_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + if (!strcmp(dev_name(component->dev), "tasha_codec")) + msm_vi_feed_tx_ch = + ucontrol->value.integer.value[0] + 1; + else + msm_vi_feed_tx_ch = + roundup_pow_of_two( + ucontrol->value.integer.value[0] + 2); + + pr_debug("%s: msm_vi_feed_tx_ch = %d\n", __func__, msm_vi_feed_tx_ch); + return 1; +} + +static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__, + msm_slim_0_rx_ch); + ucontrol->value.integer.value[0] = msm_slim_0_rx_ch - 1; + return 0; +} + +static int msm_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1; + + pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__, + msm_slim_0_rx_ch); + return 1; +} + +static int msm_slim_4_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_slim_4_rx_ch = %d\n", __func__, + msm_slim_4_rx_ch); + ucontrol->value.integer.value[0] = msm_slim_4_rx_ch - 1; + return 0; +} + +static int msm_slim_4_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_slim_4_rx_ch = ucontrol->value.integer.value[0] + 1; + + pr_debug("%s: msm_slim_4_rx_ch = %d\n", __func__, + msm_slim_4_rx_ch); + return 1; +} + +static int slim0_tx_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (slim0_tx_bit_format) { + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: slim0_tx_bit_format = %d, ucontrol value = %ld\n", + __func__, slim0_tx_bit_format, + ucontrol->value.integer.value[0]); + return 0; +} + +static int slim0_tx_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int rc = 0; + + switch (ucontrol->value.integer.value[0]) { + case 2: + slim0_tx_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + slim0_tx_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + slim0_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + default: + pr_err("%s: invalid value %ld\n", __func__, + ucontrol->value.integer.value[0]); + rc = -EINVAL; + break; + } + return rc; +} + +static int slim2_tx_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (slim2_tx_bit_format) { + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: slim2_tx_bit_format = %d, ucontrol value = %ld\n", + __func__, slim2_tx_bit_format, + ucontrol->value.integer.value[0]); + return 0; +} + +static int slim2_tx_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int rc = 0; + + switch (ucontrol->value.integer.value[0]) { + case 2: + slim2_tx_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + slim2_tx_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + slim2_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + default: + pr_err("%s: invalid value %ld\n", __func__, + ucontrol->value.integer.value[0]); + rc = -EINVAL; + break; + } + return rc; +} + +static int msm_slim_5_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_slim_5_rx_ch = %d\n", __func__, + msm_slim_5_rx_ch); + ucontrol->value.integer.value[0] = msm_slim_5_rx_ch - 1; + return 0; +} + +static int msm_slim_5_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_slim_5_rx_ch = ucontrol->value.integer.value[0] + 1; + + pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__, + msm_slim_5_rx_ch); + return 0; +} +static int msm_slim_6_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_slim_6_rx_ch = %d\n", __func__, + msm_slim_6_rx_ch); + ucontrol->value.integer.value[0] = msm_slim_6_rx_ch - 1; + return 0; +} + +static int msm_slim_6_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_slim_6_rx_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_slim_6_rx_ch = %d\n", __func__, + msm_slim_6_rx_ch); + return 1; +} + +static int msm_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__, + msm_slim_0_tx_ch); + ucontrol->value.integer.value[0] = msm_slim_0_tx_ch - 1; + return 0; +} + +static int msm_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1; + + pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__, msm_slim_0_tx_ch); + return 1; +} + +static int msm_slim_2_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_slim_2_tx_ch = %d\n", __func__, + msm_slim_2_tx_ch); + ucontrol->value.integer.value[0] = msm_slim_2_tx_ch - 1; + return 0; +} + +static int msm_slim_2_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_slim_2_tx_ch = ucontrol->value.integer.value[0] + 1; + + pr_debug("%s: msm_slim_2_tx_ch = %d\n", __func__, msm_slim_2_tx_ch); + return 1; +} + +static int slim0_tx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate_val = 0; + + switch (slim0_tx_sample_rate) { + case SAMPLING_RATE_16KHZ: + sample_rate_val = 4; + break; + case SAMPLING_RATE_192KHZ: + sample_rate_val = 2; + break; + case SAMPLING_RATE_96KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_48KHZ: + default: + sample_rate_val = 0; + break; + } + + ucontrol->value.integer.value[0] = sample_rate_val; + pr_debug("%s: slim0_tx_sample_rate = %d\n", __func__, + slim0_tx_sample_rate); + return 0; + +} + +static int slim0_tx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int rc = 0; + + pr_debug("%s: ucontrol value = %ld\n", __func__, + ucontrol->value.integer.value[0]); + + switch (ucontrol->value.integer.value[0]) { + case 4: + slim0_tx_sample_rate = SAMPLING_RATE_16KHZ; + break; + case 2: + slim0_tx_sample_rate = SAMPLING_RATE_192KHZ; + break; + case 1: + slim0_tx_sample_rate = SAMPLING_RATE_96KHZ; + break; + case 0: + slim0_tx_sample_rate = SAMPLING_RATE_48KHZ; + break; + default: + rc = -EINVAL; + pr_err("%s: invalid sample rate being passed\n", __func__); + break; + } + pr_debug("%s: slim0_tx_sample_rate = %d\n", __func__, + slim0_tx_sample_rate); + return rc; +} + +static int slim2_tx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate_val = 0; + + switch (slim2_tx_sample_rate) { + case SAMPLING_RATE_16KHZ: + sample_rate_val = 4; + break; + case SAMPLING_RATE_192KHZ: + sample_rate_val = 2; + break; + case SAMPLING_RATE_96KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_48KHZ: + default: + sample_rate_val = 0; + break; + } + + ucontrol->value.integer.value[0] = sample_rate_val; + pr_debug("%s: slim2_tx_sample_rate = %d\n", __func__, + slim2_tx_sample_rate); + return 0; + +} + +static int slim2_tx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int rc = 0; + + pr_debug("%s: ucontrol value = %ld\n", __func__, + ucontrol->value.integer.value[0]); + + switch (ucontrol->value.integer.value[0]) { + case 4: + slim2_tx_sample_rate = SAMPLING_RATE_16KHZ; + break; + case 2: + slim2_tx_sample_rate = SAMPLING_RATE_192KHZ; + break; + case 1: + slim2_tx_sample_rate = SAMPLING_RATE_96KHZ; + break; + case 0: + slim2_tx_sample_rate = SAMPLING_RATE_48KHZ; + break; + default: + rc = -EINVAL; + pr_err("%s: invalid sample rate being passed\n", __func__); + break; + } + pr_debug("%s: slim2_tx_sample_rate = %d\n", __func__, + slim2_tx_sample_rate); + return rc; +} + +static int msm_btsco_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_btsco_rate = %d", __func__, msm_btsco_rate); + ucontrol->value.integer.value[0] = msm_btsco_rate; + return 0; +} + +static int msm_btsco_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case RATE_8KHZ_ID: + msm_btsco_rate = BTSCO_RATE_8KHZ; + break; + case RATE_16KHZ_ID: + msm_btsco_rate = BTSCO_RATE_16KHZ; + break; + default: + msm_btsco_rate = BTSCO_RATE_8KHZ; + break; + } + + pr_debug("%s: msm_btsco_rate = %d\n", __func__, msm_btsco_rate); + return 0; +} + +static int msm_auxpcm_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_auxpcm_rate = %d", __func__, msm8952_auxpcm_rate); + ucontrol->value.integer.value[0] = msm8952_auxpcm_rate; + return 0; +} + +static int msm_auxpcm_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case RATE_8KHZ_ID: + msm8952_auxpcm_rate = SAMPLING_RATE_8KHZ; + break; + case RATE_16KHZ_ID: + msm8952_auxpcm_rate = SAMPLING_RATE_16KHZ; + break; + default: + msm8952_auxpcm_rate = SAMPLING_RATE_8KHZ; + break; + } + + pr_debug("%s: msm_auxpcm_rate = %d\n", __func__, msm8952_auxpcm_rate); + return 0; +} + +static int msm_proxy_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_proxy_rx_ch = %d\n", __func__, + msm_proxy_rx_ch); + ucontrol->value.integer.value[0] = msm_proxy_rx_ch - 1; + return 0; +} + +static int msm_proxy_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_proxy_rx_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_proxy_rx_ch = %d\n", __func__, + msm_proxy_rx_ch); + return 1; +} + +static int msm_pri_tdm_rx_0_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_pri_tdm_rx_0_ch = %d\n", __func__, + msm_pri_tdm_rx_0_ch); + ucontrol->value.integer.value[0] = msm_pri_tdm_rx_0_ch - 1; + return 0; +} + +static int msm_pri_tdm_rx_0_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_pri_tdm_rx_0_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_pri_tdm_rx_0_ch = %d\n", __func__, + msm_pri_tdm_rx_0_ch); + return 0; +} + +static int msm_pri_tdm_tx_0_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_pri_tdm_tx_0_ch = %d\n", __func__, + msm_pri_tdm_tx_0_ch); + ucontrol->value.integer.value[0] = msm_pri_tdm_tx_0_ch - 1; + return 0; +} + +static int msm_pri_tdm_tx_0_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_pri_tdm_tx_0_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_pri_tdm_tx_0_ch = %d\n", __func__, + msm_pri_tdm_tx_0_ch); + return 0; +} + +static int msm_sec_tdm_rx_0_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_sec_tdm_rx_0_ch = %d\n", __func__, + msm_sec_tdm_rx_0_ch); + ucontrol->value.integer.value[0] = msm_sec_tdm_rx_0_ch - 1; + return 0; +} + +static int msm_sec_tdm_rx_0_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_sec_tdm_rx_0_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_sec_tdm_rx_0_ch = %d\n", __func__, + msm_sec_tdm_rx_0_ch); + return 0; +} + +static int msm_sec_tdm_tx_0_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_sec_tdm_tx_0_ch = %d\n", __func__, + msm_sec_tdm_tx_0_ch); + ucontrol->value.integer.value[0] = msm_sec_tdm_tx_0_ch - 1; + return 0; +} + +static int msm_sec_tdm_tx_0_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_sec_tdm_tx_0_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_sec_tdm_tx_0_ch = %d\n", __func__, + msm_sec_tdm_tx_0_ch); + return 0; +} + +static int msm_pri_tdm_rx_0_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_pri_tdm_rx_0_bit_format) { + case SNDRV_PCM_FORMAT_S32_LE: + ucontrol->value.integer.value[0] = 3; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: msm_pri_tdm_rx_0_bit_format = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_pri_tdm_rx_0_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 3: + msm_pri_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S32_LE; + break; + case 2: + msm_pri_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + msm_pri_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + msm_pri_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: msm_pri_tdm_rx_0_bit_format = %d\n", + __func__, msm_pri_tdm_rx_0_bit_format); + return 0; +} + +static int msm_pri_tdm_tx_0_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_pri_tdm_tx_0_bit_format) { + case SNDRV_PCM_FORMAT_S32_LE: + ucontrol->value.integer.value[0] = 3; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: msm_pri_tdm_tx_0_bit_format = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_pri_tdm_tx_0_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 3: + msm_pri_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S32_LE; + break; + case 2: + msm_pri_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + msm_pri_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + msm_pri_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: msm_pri_tdm_tx_0_bit_format = %d\n", + __func__, msm_pri_tdm_tx_0_bit_format); + return 0; +} + +static int msm_sec_tdm_rx_0_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_sec_tdm_rx_0_bit_format) { + case SNDRV_PCM_FORMAT_S32_LE: + ucontrol->value.integer.value[0] = 3; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: msm_sec_tdm_rx_0_bit_format = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_sec_tdm_rx_0_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 3: + msm_sec_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S32_LE; + break; + case 2: + msm_sec_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + msm_sec_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + msm_sec_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: msm_sec_tdm_rx_0_bit_format = %d\n", + __func__, msm_sec_tdm_rx_0_bit_format); + return 0; +} + +static int msm_sec_tdm_tx_0_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_sec_tdm_tx_0_bit_format) { + case SNDRV_PCM_FORMAT_S32_LE: + ucontrol->value.integer.value[0] = 3; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: msm_sec_tdm_tx_0_bit_format = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_sec_tdm_tx_0_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 3: + msm_sec_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S32_LE; + break; + case 2: + msm_sec_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + msm_sec_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + msm_sec_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: msm_sec_tdm_tx_0_bit_format = %d\n", + __func__, msm_sec_tdm_tx_0_bit_format); + return 0; +} + +static int msm_pri_tdm_rx_0_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_pri_tdm_rx_0_sample_rate) { + case SAMPLING_RATE_16KHZ: + ucontrol->value.integer.value[0] = 0; + break; + case SAMPLING_RATE_48KHZ: + default: + ucontrol->value.integer.value[0] = 1; + break; + } + pr_debug("%s: msm_pri_tdm_rx_0_sample_rate = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_pri_tdm_rx_0_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 0: + msm_pri_tdm_rx_0_sample_rate = SAMPLING_RATE_16KHZ; + break; + case 1: + default: + msm_pri_tdm_rx_0_sample_rate = SAMPLING_RATE_48KHZ; + break; + } + pr_debug("%s: msm_pri_tdm_rx_0_sample_rate = %d\n", + __func__, msm_pri_tdm_rx_0_sample_rate); + return 0; +} + +static int msm_sec_tdm_rx_0_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_sec_tdm_rx_0_sample_rate) { + case SAMPLING_RATE_16KHZ: + ucontrol->value.integer.value[0] = 0; + break; + case SAMPLING_RATE_48KHZ: + default: + ucontrol->value.integer.value[0] = 1; + break; + } + pr_debug("%s: msm_sec_tdm_rx_0_sample_rate = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_sec_tdm_rx_0_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 0: + msm_sec_tdm_rx_0_sample_rate = SAMPLING_RATE_16KHZ; + break; + case 1: + default: + msm_sec_tdm_rx_0_sample_rate = SAMPLING_RATE_48KHZ; + break; + } + pr_debug("%s: msm_sec_tdm_rx_0_sample_rate = %d\n", + __func__, msm_sec_tdm_rx_0_sample_rate); + return 0; +} + +static int msm_pri_tdm_tx_0_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_pri_tdm_tx_0_sample_rate) { + case SAMPLING_RATE_16KHZ: + ucontrol->value.integer.value[0] = 0; + break; + case SAMPLING_RATE_48KHZ: + default: + ucontrol->value.integer.value[0] = 1; + break; + } + pr_debug("%s: msm_pri_tdm_tx_0_sample_rate = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_pri_tdm_tx_0_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 0: + msm_pri_tdm_tx_0_sample_rate = SAMPLING_RATE_16KHZ; + break; + case 1: + default: + msm_pri_tdm_tx_0_sample_rate = SAMPLING_RATE_48KHZ; + break; + } + pr_debug("%s: msm_pri_tdm_tx_0_sample_rate = %d\n", + __func__, msm_pri_tdm_tx_0_sample_rate); + return 0; +} + +static int msm_sec_tdm_tx_0_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_sec_tdm_tx_0_sample_rate) { + case SAMPLING_RATE_16KHZ: + ucontrol->value.integer.value[0] = 0; + break; + case SAMPLING_RATE_48KHZ: + default: + ucontrol->value.integer.value[0] = 1; + break; + } + pr_debug("%s: msm_sec_tdm_tx_0_sample_rate = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_sec_tdm_tx_0_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 0: + msm_sec_tdm_tx_0_sample_rate = SAMPLING_RATE_16KHZ; + break; + case 1: + default: + msm_sec_tdm_tx_0_sample_rate = SAMPLING_RATE_48KHZ; + break; + } + pr_debug("%s: msm_sec_tdm_tx_0_sample_rate = %d\n", + __func__, msm_sec_tdm_tx_0_sample_rate); + return 0; +} + +static const char *const spk_function[] = {"Off", "On"}; +static const char *const slim0_rx_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", + "Eight"}; +static const char *const slim4_rx_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", + "Eight"}; +static const char *const slim0_tx_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", + "Eight"}; +static const char *const slim2_tx_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", + "Eight"}; +static const char *const slim4_tx_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", + "Eight"}; +static const char *const vi_feed_ch_text[] = {"One", "Two"}; +static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"}; +static char const *slim0_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96", + "KHZ_192", "KHZ_44P1", "KHZ_16"}; +static char const *slim4_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96", + "KHZ_192", "KHZ_44P1", "KHZ_16"}; +static const char *const slim5_rx_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", + "Eight"}; +static const char *const slim6_rx_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", + "Eight"}; +static char const *slim5_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96", + "KHZ_192", "KHZ_44P1"}; +static char const *slim6_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96", + "KHZ_192", "KHZ_44P1"}; +static char const *slim4_rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"}; +static char const *slim5_rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"}; +static const char *const proxy_rx_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", "Eight"}; +static char const *slim6_rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"}; + +static const struct soc_enum msm_snd_enum[] = { + SOC_ENUM_SINGLE_EXT(2, spk_function), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim0_rx_ch_text), slim0_rx_ch_text), + SOC_ENUM_SINGLE_EXT(8, slim0_tx_ch_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_bit_format_text), + rx_bit_format_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim0_rx_sample_rate_text), + slim0_rx_sample_rate_text), + SOC_ENUM_SINGLE_EXT(2, vi_feed_ch_text), + SOC_ENUM_SINGLE_EXT(4, slim5_rx_sample_rate_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim5_rx_bit_format_text), + slim5_rx_bit_format_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim5_rx_ch_text), slim5_rx_ch_text), + SOC_ENUM_SINGLE_EXT(8, proxy_rx_ch_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim6_rx_sample_rate_text), + slim6_rx_sample_rate_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim6_rx_bit_format_text), + slim6_rx_bit_format_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim6_rx_ch_text), slim6_rx_ch_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tdm_ch_text), + tdm_ch_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tdm_bit_format_text), + tdm_bit_format_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tdm_sample_rate_text), + tdm_sample_rate_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim4_rx_ch_text), slim4_rx_ch_text), + SOC_ENUM_SINGLE_EXT(8, slim2_tx_ch_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim4_rx_sample_rate_text), + slim4_rx_sample_rate_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim4_rx_bit_format_text), + slim4_rx_bit_format_text), +}; + +static const char *const btsco_rate_text[] = {"BTSCO_RATE_8KHZ", + "BTSCO_RATE_16KHZ"}; +static const struct soc_enum msm_btsco_enum[] = { + SOC_ENUM_SINGLE_EXT(2, btsco_rate_text), +}; + +static const char *const auxpcm_rate_text[] = {"SAMPLING_RATE_8KHZ", + "SAMPLING_RATE_16KHZ"}; +static const struct soc_enum msm_auxpcm_enum[] = { + SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text), +}; + +static const struct snd_kcontrol_new msm_snd_controls[] = { + SOC_ENUM_EXT("Speaker Function", msm_snd_enum[0], msm8952_get_spk, + msm8952_set_spk), + SOC_ENUM_EXT("SLIM_0_RX Channels", msm_snd_enum[1], + msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put), + SOC_ENUM_EXT("SLIM_4_RX Channels", msm_snd_enum[16], + msm_slim_4_rx_ch_get, msm_slim_4_rx_ch_put), + SOC_ENUM_EXT("SLIM_5_RX Channels", msm_snd_enum[8], + msm_slim_5_rx_ch_get, msm_slim_5_rx_ch_put), + SOC_ENUM_EXT("SLIM_6_RX Channels", msm_snd_enum[12], + msm_slim_6_rx_ch_get, msm_slim_6_rx_ch_put), + SOC_ENUM_EXT("SLIM_0_TX Channels", msm_snd_enum[2], + msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put), + SOC_ENUM_EXT("SLIM_1_TX Channels", msm_snd_enum[2], + msm_slim_1_tx_ch_get, msm_slim_1_tx_ch_put), + SOC_ENUM_EXT("SLIM_2_TX Channels", msm_snd_enum[17], + msm_slim_2_tx_ch_get, msm_slim_2_tx_ch_put), + SOC_ENUM_EXT("MI2S_RX Format", msm_snd_enum[3], + mi2s_rx_bit_format_get, mi2s_rx_bit_format_put), + SOC_ENUM_EXT("SLIM_0_RX Format", msm_snd_enum[3], + slim0_rx_bit_format_get, slim0_rx_bit_format_put), + SOC_ENUM_EXT("SLIM_4_RX Format", msm_snd_enum[19], + slim4_rx_bit_format_get, slim4_rx_bit_format_put), + SOC_ENUM_EXT("SLIM_5_RX Format", msm_snd_enum[7], + slim5_rx_bit_format_get, slim5_rx_bit_format_put), + SOC_ENUM_EXT("SLIM_6_RX Format", msm_snd_enum[11], + slim6_rx_bit_format_get, slim6_rx_bit_format_put), + SOC_ENUM_EXT("SLIM_0_RX SampleRate", msm_snd_enum[4], + slim0_rx_sample_rate_get, slim0_rx_sample_rate_put), + SOC_ENUM_EXT("SLIM_4_RX SampleRate", msm_snd_enum[18], + slim4_rx_sample_rate_get, slim4_rx_sample_rate_put), + SOC_ENUM_EXT("SLIM_5_RX SampleRate", msm_snd_enum[6], + slim5_rx_sample_rate_get, slim5_rx_sample_rate_put), + SOC_ENUM_EXT("SLIM_6_RX SampleRate", msm_snd_enum[10], + slim6_rx_sample_rate_get, slim6_rx_sample_rate_put), + SOC_ENUM_EXT("VI_FEED_TX Channels", msm_snd_enum[5], + msm_vi_feed_tx_ch_get, msm_vi_feed_tx_ch_put), + SOC_ENUM_EXT("SLIM_0_TX SampleRate", msm_snd_enum[4], + slim0_tx_sample_rate_get, slim0_tx_sample_rate_put), + SOC_ENUM_EXT("SLIM_0_TX Format", msm_snd_enum[3], + slim0_tx_bit_format_get, slim0_tx_bit_format_put), + SOC_ENUM_EXT("SLIM_2_TX SampleRate", msm_snd_enum[4], + slim2_tx_sample_rate_get, slim2_tx_sample_rate_put), + SOC_ENUM_EXT("SLIM_2_TX Format", msm_snd_enum[3], + slim2_tx_bit_format_get, slim2_tx_bit_format_put), + SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0], + msm_btsco_rate_get, msm_btsco_rate_put), + SOC_ENUM_EXT("AUXPCM SampleRate", msm_auxpcm_enum[0], + msm_auxpcm_rate_get, msm_auxpcm_rate_put), + SOC_ENUM_EXT("PROXY_RX Channels", msm_snd_enum[9], + msm_proxy_rx_ch_get, msm_proxy_rx_ch_put), + SOC_ENUM_EXT("PRI_TDM_RX_0 Channels", msm_snd_enum[13], + msm_pri_tdm_rx_0_ch_get, msm_pri_tdm_rx_0_ch_put), + SOC_ENUM_EXT("PRI_TDM_TX_0 Channels", msm_snd_enum[13], + msm_pri_tdm_tx_0_ch_get, msm_pri_tdm_tx_0_ch_put), + SOC_ENUM_EXT("SEC_TDM_RX_0 Channels", msm_snd_enum[13], + msm_sec_tdm_rx_0_ch_get, msm_sec_tdm_rx_0_ch_put), + SOC_ENUM_EXT("SEC_TDM_TX_0 Channels", msm_snd_enum[13], + msm_sec_tdm_tx_0_ch_get, msm_sec_tdm_tx_0_ch_put), + SOC_ENUM_EXT("PRI_TDM_RX_0 Bit Format", msm_snd_enum[14], + msm_pri_tdm_rx_0_bit_format_get, + msm_pri_tdm_rx_0_bit_format_put), + SOC_ENUM_EXT("PRI_TDM_TX_0 Bit Format", msm_snd_enum[14], + msm_pri_tdm_tx_0_bit_format_get, + msm_pri_tdm_tx_0_bit_format_put), + SOC_ENUM_EXT("SEC_TDM_RX_0 Bit Format", msm_snd_enum[14], + msm_sec_tdm_rx_0_bit_format_get, + msm_sec_tdm_rx_0_bit_format_put), + SOC_ENUM_EXT("SEC_TDM_TX_0 Bit Format", msm_snd_enum[14], + msm_sec_tdm_tx_0_bit_format_get, + msm_sec_tdm_tx_0_bit_format_put), + SOC_ENUM_EXT("PRI_TDM_RX_0 SampleRate", msm_snd_enum[15], + msm_pri_tdm_rx_0_sample_rate_get, + msm_pri_tdm_rx_0_sample_rate_put), + SOC_ENUM_EXT("PRI_TDM_TX_0 SampleRate", msm_snd_enum[15], + msm_pri_tdm_tx_0_sample_rate_get, + msm_pri_tdm_tx_0_sample_rate_put), + SOC_ENUM_EXT("SEC_TDM_RX_0 SampleRate", msm_snd_enum[15], + msm_sec_tdm_rx_0_sample_rate_get, + msm_sec_tdm_rx_0_sample_rate_put), + SOC_ENUM_EXT("SEC_TDM_TX_0 SampleRate", msm_snd_enum[15], + msm_sec_tdm_tx_0_sample_rate_get, + msm_sec_tdm_tx_0_sample_rate_put), +}; + +int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + pr_debug("%s()\n", __func__); + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + return 0; +} + +int msm_quin_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + pr_debug("%s()\n", __func__); + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + return 0; +} + +int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + rate->min = rate->max = msm8952_auxpcm_rate; + channels->min = channels->max = 1; + + return 0; +} + +int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + rate->min = rate->max = msm_btsco_rate; + channels->min = channels->max = msm_btsco_ch; + + return 0; +} + +int msm_proxy_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + pr_debug("%s: msm_proxy_rx_ch =%d\n", __func__, msm_proxy_rx_ch); + + if (channels->max < 2) + channels->min = channels->max = 2; + channels->min = channels->max = msm_proxy_rx_ch; + rate->min = rate->max = 48000; + return 0; +} + +int msm_proxy_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + rate->min = rate->max = 48000; + return 0; +} + +int msm_tdm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + switch (cpu_dai->id) { + case AFE_PORT_ID_PRIMARY_TDM_RX: + channels->min = channels->max = msm_pri_tdm_rx_0_ch; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + msm_pri_tdm_rx_0_bit_format); + rate->min = rate->max = msm_pri_tdm_rx_0_sample_rate; + break; + case AFE_PORT_ID_PRIMARY_TDM_TX: + channels->min = channels->max = msm_pri_tdm_tx_0_ch; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + msm_pri_tdm_tx_0_bit_format); + rate->min = rate->max = msm_pri_tdm_tx_0_sample_rate; + break; + case AFE_PORT_ID_SECONDARY_TDM_RX: + channels->min = channels->max = msm_sec_tdm_rx_0_ch; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + msm_sec_tdm_rx_0_bit_format); + rate->min = rate->max = msm_sec_tdm_rx_0_sample_rate; + break; + case AFE_PORT_ID_SECONDARY_TDM_TX: + channels->min = channels->max = msm_sec_tdm_tx_0_ch; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + msm_sec_tdm_tx_0_bit_format); + rate->min = rate->max = msm_sec_tdm_tx_0_sample_rate; + break; + default: + pr_err("%s: dai id 0x%x not supported\n", + __func__, cpu_dai->id); + return -EINVAL; + } + + pr_debug("%s: dai id = 0x%x channels = %d rate = %d\n", + __func__, cpu_dai->id, channels->max, rate->max); + + return 0; +} + +static unsigned int tdm_param_set_slot_mask(u16 port_id, + int slot_width, int slots) +{ + unsigned int slot_mask = 0; + int upper, lower, i, j; + unsigned int *slot_offset; + + switch (port_id) { + case AFE_PORT_ID_PRIMARY_TDM_RX: + lower = PRIMARY_TDM_RX_0; + upper = PRIMARY_TDM_RX_0; + break; + case AFE_PORT_ID_PRIMARY_TDM_TX: + lower = PRIMARY_TDM_TX_0; + upper = PRIMARY_TDM_TX_0; + break; + case AFE_PORT_ID_SECONDARY_TDM_RX: + lower = SECONDARY_TDM_RX_0; + upper = SECONDARY_TDM_RX_0; + break; + case AFE_PORT_ID_SECONDARY_TDM_TX: + lower = SECONDARY_TDM_TX_0; + upper = SECONDARY_TDM_TX_0; + break; + default: + return slot_mask; + } + + for (i = lower; i <= upper; i++) { + slot_offset = tdm_slot_offset[i]; + for (j = 0; j < TDM_SLOT_OFFSET_MAX; j++) { + if (slot_offset[j] != AFE_SLOT_MAPPING_OFFSET_INVALID) + /* + * set the mask of active slot according to + * the offset table for the group of devices + */ + slot_mask |= + (1 << ((slot_offset[j] * 8) / slot_width)); + else + break; + } + } + + return slot_mask; +} + +int msm_tdm_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int ret = 0; + int channels, slot_width, slots; + unsigned int slot_mask; + unsigned int *slot_offset; + int offset_channels = 0; + int i; + + pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id); + + channels = params_channels(params); + switch (channels) { + case 1: + case 2: + case 3: + case 4: + case 6: + case 8: + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S16_LE: + /* + * up to 8 channel HW configuration should + * use 32 bit slot width for max support of + * stream bit width. (slot_width > bit_width) + */ + slot_width = 32; + break; + default: + pr_err("%s: invalid param format 0x%x\n", + __func__, params_format(params)); + return -EINVAL; + } + slots = 8; + slot_mask = tdm_param_set_slot_mask(cpu_dai->id, + slot_width, slots); + if (!slot_mask) { + pr_err("%s: invalid slot_mask 0x%x\n", + __func__, slot_mask); + return -EINVAL; + } + break; + default: + pr_err("%s: invalid param channels %d\n", + __func__, channels); + return -EINVAL; + } + + switch (cpu_dai->id) { + case AFE_PORT_ID_PRIMARY_TDM_RX: + slot_offset = tdm_slot_offset[PRIMARY_TDM_RX_0]; + break; + case AFE_PORT_ID_PRIMARY_TDM_TX: + slot_offset = tdm_slot_offset[PRIMARY_TDM_TX_0]; + break; + case AFE_PORT_ID_SECONDARY_TDM_RX: + slot_offset = tdm_slot_offset[SECONDARY_TDM_RX_0]; + break; + case AFE_PORT_ID_SECONDARY_TDM_TX: + slot_offset = tdm_slot_offset[SECONDARY_TDM_TX_0]; + break; + default: + pr_err("%s: dai id 0x%x not supported\n", + __func__, cpu_dai->id); + return -EINVAL; + } + + for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) { + if (slot_offset[i] != AFE_SLOT_MAPPING_OFFSET_INVALID) + offset_channels++; + else + break; + } + + if (offset_channels == 0) { + pr_err("%s: slot offset not supported, offset_channels %d\n", + __func__, offset_channels); + return -EINVAL; + } + + if (channels > offset_channels) { + pr_err("%s: channels %d exceed offset_channels %d\n", + __func__, channels, offset_channels); + return -EINVAL; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask, + slots, slot_width); + if (ret < 0) { + pr_err("%s: failed to set tdm slot, err:%d\n", + __func__, ret); + goto end; + } + + ret = snd_soc_dai_set_channel_map(cpu_dai, + 0, NULL, channels, slot_offset); + if (ret < 0) { + pr_err("%s: failed to set channel map, err:%d\n", + __func__, ret); + goto end; + } + } else { + ret = snd_soc_dai_set_tdm_slot(cpu_dai, slot_mask, 0, + slots, slot_width); + if (ret < 0) { + pr_err("%s: failed to set tdm slot, err:%d\n", + __func__, ret); + goto end; + } + + ret = snd_soc_dai_set_channel_map(cpu_dai, + channels, slot_offset, 0, NULL); + if (ret < 0) { + pr_err("%s: failed to set channel map, err:%d\n", + __func__, ret); + goto end; + } + } + +end: + return ret; +} + +int msm_mi2s_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, mi2s_rx_bit_format); + return 0; +} + +int msm_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai_link *dai_link = rtd->dai_link; + + int ret = 0; + u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS]; + u32 rx_ch_cnt = 0, tx_ch_cnt = 0; + u32 user_set_tx_ch = 0; + u32 rx_ch_count; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); + if (ret < 0) { + pr_err("%s: failed to get codec chan map, err:%d\n", + __func__, ret); + goto end; + } + if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_4_RX) { + pr_debug("%s: rx_4_ch=%d\n", __func__, + msm_slim_4_rx_ch); + rx_ch_count = msm_slim_4_rx_ch; + } else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_5_RX) { + pr_debug("%s: rx_5_ch=%d\n", __func__, + msm_slim_5_rx_ch); + rx_ch_count = msm_slim_5_rx_ch; + } else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_6_RX) { + pr_debug("%s: rx_6_ch=%d\n", __func__, + msm_slim_6_rx_ch); + rx_ch_count = msm_slim_6_rx_ch; + } else { + pr_debug("%s: rx_0_ch=%d\n", __func__, + msm_slim_0_rx_ch); + rx_ch_count = msm_slim_0_rx_ch; + } + ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0, + rx_ch_count, rx_ch); + if (ret < 0) { + pr_err("%s: failed to set cpu chan map, err:%d\n", + __func__, ret); + goto end; + } + } else { + pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__, + codec_dai->name, codec_dai->id, user_set_tx_ch); + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); + if (ret < 0) { + pr_err("%s: failed to get codec chan map\n, err:%d\n", + __func__, ret); + goto end; + } + /* For _tx1 case */ + if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_0_TX) + user_set_tx_ch = msm_slim_0_tx_ch; + /* For _tx2 case */ + else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_1_TX) + user_set_tx_ch = msm_slim_1_tx_ch; + else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_2_TX) + user_set_tx_ch = msm_slim_2_tx_ch; + else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_3_TX) + /* DAI 5 is used for external EC reference from codec. + * Since Rx is fed as reference for EC, the config of + * this DAI is based on that of the Rx path. + */ + user_set_tx_ch = msm_slim_0_rx_ch; + else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_4_TX) + user_set_tx_ch = msm_vi_feed_tx_ch; + else + user_set_tx_ch = tx_ch_cnt; + + pr_debug( + "%s: msm_slim_0_tx_ch(%d) user_set_tx_ch(%d) tx_ch_cnt(%d)\n", + __func__, msm_slim_0_tx_ch, user_set_tx_ch, tx_ch_cnt); + + ret = snd_soc_dai_set_channel_map(cpu_dai, + user_set_tx_ch, tx_ch, 0, 0); + if (ret < 0) { + pr_err("%s: failed to set cpu chan map, err:%d\n", + __func__, ret); + goto end; + } + } +end: + return ret; +} + +int msm8952_slimbus_2_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int ret = 0; + unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS]; + unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0; + unsigned int num_tx_ch = 0; + unsigned int num_rx_ch = 0; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + num_rx_ch = params_channels(params); + pr_debug("%s: %s rx_dai_id = %d num_ch = %d\n", __func__, + codec_dai->name, codec_dai->id, num_rx_ch); + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); + if (ret < 0) { + pr_err("%s: failed to get codec chan map, err:%d\n", + __func__, ret); + goto end; + } + ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0, + num_rx_ch, rx_ch); + if (ret < 0) { + pr_err("%s: failed to set cpu chan map, err:%d\n", + __func__, ret); + goto end; + } + } else { + num_tx_ch = params_channels(params); + pr_debug("%s: %s tx_dai_id = %d num_ch = %d\n", __func__, + codec_dai->name, codec_dai->id, num_tx_ch); + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); + if (ret < 0) { + pr_err("%s: failed to get codec chan map, err:%d\n", + __func__, ret); + goto end; + } + ret = snd_soc_dai_set_channel_map(cpu_dai, + num_tx_ch, tx_ch, 0, 0); + if (ret < 0) { + pr_err("%s: failed to set cpu chan map, err:%d\n", + __func__, ret); + goto end; + } + } +end: + return ret; +} + +int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + + pr_debug("%s()\n", __func__); + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim0_rx_bit_format); + rate->min = rate->max = slim0_rx_sample_rate; + channels->min = channels->max = msm_slim_0_rx_ch; + + pr_debug("%s: format = %d, rate = %d, channels = %d\n", + __func__, params_format(params), params_rate(params), + msm_slim_0_rx_ch); + + return 0; +} + +int msm_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + pr_debug("%s()\n", __func__); + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim0_tx_bit_format); + rate->min = rate->max = slim0_tx_sample_rate; + channels->min = channels->max = msm_slim_0_tx_ch; + + return 0; +} + +int msm_slim_1_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + pr_debug("%s()\n", __func__); + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim1_tx_bit_format); + rate->min = rate->max = slim1_tx_sample_rate; + channels->min = channels->max = msm_slim_1_tx_ch; + + return 0; +} + +int msm_slim_2_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + pr_debug("%s()\n", __func__); + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim2_tx_bit_format); + rate->min = rate->max = slim2_tx_sample_rate; + channels->min = channels->max = msm_slim_2_tx_ch; + + return 0; +} + +int msm_slim_4_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + + pr_debug("%s()\n", __func__); + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim4_rx_bit_format); + rate->min = rate->max = slim4_rx_sample_rate; + channels->min = channels->max = msm_slim_4_rx_ch; + + pr_debug("%s: format = %d, rate = %d, channels = %d\n", + __func__, params_format(params), params_rate(params), + msm_slim_4_rx_ch); + + return 0; +} + +int msm_slim_4_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + pr_debug("%s: codec name: %s", __func__, codec_dai->name); + if (!strcmp(dev_name(codec_dai->dev), "tasha_codec")) { + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + SNDRV_PCM_FORMAT_S32_LE); + rate->min = rate->max = SAMPLING_RATE_8KHZ; + channels->min = channels->max = msm_vi_feed_tx_ch; + pr_debug("%s: tasha vi sample rate = %d\n", + __func__, rate->min); + } else { + rate->min = rate->max = SAMPLING_RATE_48KHZ; + channels->min = channels->max = msm_vi_feed_tx_ch; + pr_debug("%s: default sample rate = %d\n", + __func__, rate->min); + } + + pr_debug("%s: %d\n", __func__, msm_vi_feed_tx_ch); + return 0; +} + +int msm_slim_5_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim5_rx_bit_format); + rate->min = rate->max = slim5_rx_sample_rate; + channels->min = channels->max = msm_slim_5_rx_ch; + + pr_debug("%s: format = %d, rate = %d, channels = %d\n", + __func__, params_format(params), params_rate(params), + msm_slim_5_rx_ch); + + return 0; +} + +int msm_slim_6_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim6_rx_bit_format); + rate->min = rate->max = slim6_rx_sample_rate; + channels->min = channels->max = msm_slim_6_rx_ch; + + pr_debug("%s: format = %d, rate = %d, channels = %d\n", + __func__, params_format(params), params_rate(params), + msm_slim_6_rx_ch); + + return 0; +} + +int msm_slim_5_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + int rc; + void *config; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_component *component; + struct snd_interval *rate = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct msm8952_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(rtd->card); + + pr_debug("%s enter\n", __func__); + if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) + component = snd_soc_rtdcom_lookup(rtd, "tavil_codec"); + else if (!strcmp(dev_name(codec_dai->dev), "tasha_codec")) + component = snd_soc_rtdcom_lookup(rtd, "tasha_codec"); + + rate->min = rate->max = 16000; + channels->min = channels->max = 1; + config = pdata->msm8952_codec_fn.get_afe_config_fn(component, + AFE_SLIMBUS_SLAVE_PORT_CONFIG); + rc = afe_set_config(AFE_SLIMBUS_SLAVE_PORT_CONFIG, config, + SLIMBUS_5_TX); + if (rc) { + pr_err("%s: Failed to set slimbus slave port config %d\n", + __func__, rc); + return rc; + } + return 0; +} + +int msm_snd_cpe_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai_link *dai_link = rtd->dai_link; + int ret = 0; + u32 tx_ch[SLIM_MAX_TX_PORTS]; + u32 tx_ch_cnt = 0; + u32 user_set_tx_ch = 0; + + if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) { + pr_err("%s: Invalid stream type %d\n", + __func__, substream->stream); + ret = -EINVAL; + goto end; + } + + pr_debug("%s: %s_tx_dai_id_%d\n", __func__, + codec_dai->name, codec_dai->id); + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, NULL, NULL); + if (ret < 0) { + pr_err("%s: failed to get codec chan map\n, err:%d\n", + __func__, ret); + goto end; + } + + user_set_tx_ch = tx_ch_cnt; + + pr_debug("%s: tx_ch_cnt(%d) id %d\n", + __func__, tx_ch_cnt, dai_link->id); + + ret = snd_soc_dai_set_channel_map(cpu_dai, + user_set_tx_ch, tx_ch, 0, 0); + if (ret < 0) { + pr_err("%s: failed to set cpu chan map, err:%d\n", + __func__, ret); + goto end; + } +end: + return ret; +} + +static int msm_afe_set_config(struct snd_soc_component *component) +{ + int rc; + void *config_data; + struct snd_soc_card *card = component->card; + struct msm8952_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + + pr_debug("%s: enter\n", __func__); + + if (!pdata->msm8952_codec_fn.get_afe_config_fn) { + dev_err(component->dev, "%s: codec get afe config not init'ed\n", + __func__); + return -EINVAL; + } + config_data = pdata->msm8952_codec_fn.get_afe_config_fn(component, + AFE_CDC_REGISTERS_CONFIG); + if (config_data) { + rc = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0); + if (rc) { + pr_err("%s: Failed to set codec registers config %d\n", + __func__, rc); + return rc; + } + } + + config_data = pdata->msm8952_codec_fn.get_afe_config_fn(component, + AFE_CDC_REGISTER_PAGE_CONFIG); + if (config_data) { + rc = afe_set_config(AFE_CDC_REGISTER_PAGE_CONFIG, config_data, + 0); + if (rc) + pr_err("%s: Failed to set cdc register page config\n", + __func__); + } + + config_data = pdata->msm8952_codec_fn.get_afe_config_fn(component, + AFE_SLIMBUS_SLAVE_CONFIG); + if (config_data) { + rc = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0); + if (rc) { + pr_err("%s: Failed to set slimbus slave config %d\n", + __func__, rc); + return rc; + } + } + + config_data = pdata->msm8952_codec_fn.get_afe_config_fn(component, + AFE_AANC_VERSION); + if (config_data) { + rc = afe_set_config(AFE_AANC_VERSION, config_data, 0); + if (rc) { + pr_err("%s: Failed to set AANC version %d\n", + __func__, rc); + return rc; + } + } + + config_data = pdata->msm8952_codec_fn.get_afe_config_fn(component, + AFE_CDC_CLIP_REGISTERS_CONFIG); + if (config_data) { + rc = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG, + config_data, 0); + if (rc) { + pr_err("%s: Failed to set clip registers %d\n", + __func__, rc); + return rc; + } + } + + config_data = pdata->msm8952_codec_fn.get_afe_config_fn(component, + AFE_CLIP_BANK_SEL); + if (config_data) { + rc = afe_set_config(AFE_CLIP_BANK_SEL, + config_data, 0); + if (rc) { + pr_err("%s: Failed to set AFE bank selection %d\n", + __func__, rc); + return rc; + } + } + + config_data = pdata->msm8952_codec_fn.get_afe_config_fn(component, + AFE_CDC_REGISTER_PAGE_CONFIG); + if (config_data) { + rc = afe_set_config(AFE_CDC_REGISTER_PAGE_CONFIG, config_data, + 0); + if (rc) + pr_err("%s: Failed to set cdc register page config\n", + __func__); + } + + return 0; +} + +static void msm_afe_clear_config(void) +{ + afe_clear_config(AFE_CDC_REGISTERS_CONFIG); + afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG); +} + +static int quat_mi2s_clk_ctl(struct snd_pcm_substream *substream, bool enable) +{ + int ret = 0; + + if (enable) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + mi2s_rx_clk.enable = enable; + mi2s_rx_clk.clk_id = + Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT; + if ((mi2s_rx_bit_format == SNDRV_PCM_FORMAT_S24_LE) || + (mi2s_rx_bit_format == + SNDRV_PCM_FORMAT_S24_3LE)) + mi2s_rx_clk.clk_freq_in_hz = + Q6AFE_LPASS_IBIT_CLK_3_P072_MHZ; + else + mi2s_rx_clk.clk_freq_in_hz = + Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_QUATERNARY_MI2S_RX, + &mi2s_rx_clk); + } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + mi2s_tx_clk.enable = enable; + mi2s_tx_clk.clk_id = + Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT; + mi2s_tx_clk.clk_freq_in_hz = + Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_QUATERNARY_MI2S_TX, + &mi2s_tx_clk); + } else { + pr_err("%s:Not valid substream.\n", __func__); + } + + if (ret < 0) + pr_err("%s:afe_set_lpass_clock failed %d\n", + __func__, ret); + } else { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + mi2s_rx_clk.enable = enable; + mi2s_rx_clk.clk_id = + Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_QUATERNARY_MI2S_RX, + &mi2s_rx_clk); + } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + mi2s_tx_clk.enable = enable; + mi2s_tx_clk.clk_id = + Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_QUATERNARY_MI2S_TX, + &mi2s_tx_clk); + } else + pr_err("%s:Not valid substream %d\n", __func__, + substream->stream); + + if (ret < 0) + pr_err("%s:afe_set_lpass_clock failed ret=%d\n", + __func__, ret); + } + return ret; +} + +static int quin_mi2s_sclk_ctl(struct snd_pcm_substream *substream, bool enable) +{ + int ret = 0; + + if (enable) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + mi2s_rx_clk.enable = enable; + mi2s_rx_clk.clk_id = + Q6AFE_LPASS_CLK_ID_QUI_MI2S_IBIT; + if ((mi2s_rx_bit_format == SNDRV_PCM_FORMAT_S24_LE) || + (mi2s_rx_bit_format == + SNDRV_PCM_FORMAT_S24_3LE)) + mi2s_rx_clk.clk_freq_in_hz = + Q6AFE_LPASS_IBIT_CLK_3_P072_MHZ; + else + mi2s_rx_clk.clk_freq_in_hz = + Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_QUINARY_MI2S_RX, + &mi2s_rx_clk); + } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + mi2s_tx_clk.enable = enable; + mi2s_tx_clk.clk_id = + Q6AFE_LPASS_CLK_ID_QUI_MI2S_IBIT; + mi2s_tx_clk.clk_freq_in_hz = + Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_QUINARY_MI2S_TX, + &mi2s_tx_clk); + } else { + pr_err("%s:Not valid substream.\n", __func__); + } + + if (ret < 0) + pr_err("%s:afe_set_lpass_clock failed\n", __func__); + } else { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + mi2s_rx_clk.enable = enable; + mi2s_rx_clk.clk_id = + Q6AFE_LPASS_CLK_ID_QUI_MI2S_IBIT; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_QUINARY_MI2S_RX, + &mi2s_rx_clk); + } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + mi2s_tx_clk.enable = enable; + mi2s_tx_clk.clk_id = + Q6AFE_LPASS_CLK_ID_QUI_MI2S_IBIT; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_QUINARY_MI2S_TX, + &mi2s_tx_clk); + } else + pr_err("%s:Not valid substream %d\n", __func__, + substream->stream); + + if (ret < 0) + pr_err("%s:afe_set_lpass_clock failed ret=%d\n", + __func__, ret); + } + return ret; +} + +static int msm8952_adsp_state_callback(struct notifier_block *nb, + unsigned long value, void *priv) +{ + if (value == SUBSYS_BEFORE_SHUTDOWN) { + pr_debug("%s: ADSP is about to shutdown. Clearing AFE config\n", + __func__); + msm_afe_clear_config(); + } else if (value == SUBSYS_AFTER_POWERUP) { + pr_debug("%s: ADSP is up\n", __func__); + } + + return NOTIFY_OK; +} + +static struct notifier_block adsp_state_notifier_block = { + .notifier_call = msm8952_adsp_state_callback, + .priority = -INT_MAX, +}; + +void msm_quat_mi2s_snd_shutdown(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 msm8952_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + + pr_debug("%s(): substream = %s stream = %d, ext_pa = %d\n", __func__, + substream->name, substream->stream, pdata->ext_pa); + + ret = quat_mi2s_clk_ctl(substream, false); + if (ret < 0) + pr_err("%s:clock disable failed\n", __func__); + if (atomic_read(&pdata->clk_ref.quat_mi2s_clk_ref) > 0) + atomic_dec(&pdata->clk_ref.quat_mi2s_clk_ref); + if (pdata->mi2s_gpio_p[QUAT_MI2S]) { + ret = msm_cdc_pinctrl_select_sleep_state( + pdata->mi2s_gpio_p[QUAT_MI2S]); + if (ret < 0) { + pr_err("%s: failed to disable quat gpio's state\n", + __func__); + return; + } + } +} + +int msm_prim_auxpcm_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct msm8952_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + int ret = 0, val = 0; + + pr_debug("%s(): substream = %s\n", + __func__, substream->name); + + /* mux config to route the AUX MI2S */ + if (pdata->vaddr_gpio_mux_mic_ctl) { + val = ioread32(pdata->vaddr_gpio_mux_mic_ctl); + val = val | 0x2; + iowrite32(val, pdata->vaddr_gpio_mux_mic_ctl); + } + if (pdata->vaddr_gpio_mux_pcm_ctl) { + val = ioread32(pdata->vaddr_gpio_mux_pcm_ctl); + val = val | 0x1; + iowrite32(val, pdata->vaddr_gpio_mux_pcm_ctl); + } + atomic_inc(&pdata->clk_ref.auxpcm_mi2s_clk_ref); + + /* enable the gpio's used for the external AUXPCM interface */ + if (pdata->mi2s_gpio_p[QUAT_MI2S]) { + ret = msm_cdc_pinctrl_select_active_state( + pdata->mi2s_gpio_p[QUAT_MI2S]); + if (ret < 0) + pr_err("%s(): configure gpios failed = %s\n", + __func__, "quat_i2s"); + } + return ret; +} + +void msm_prim_auxpcm_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct msm8952_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + int ret; + + pr_debug("%s(): substream = %s\n", + __func__, substream->name); + if (atomic_read(&pdata->clk_ref.auxpcm_mi2s_clk_ref) > 0) + atomic_dec(&pdata->clk_ref.auxpcm_mi2s_clk_ref); + if (pdata->mi2s_gpio_p[QUAT_MI2S]) { + ret = msm_cdc_pinctrl_select_sleep_state( + pdata->mi2s_gpio_p[QUAT_MI2S]); + if (ret < 0) + pr_err("%s(): configure gpios failed = %s\n", + __func__, "quat_i2s"); + } +} + +int msm_quat_mi2s_snd_startup(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 *cpu_dai = rtd->cpu_dai; + struct msm8952_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + int ret = 0, val; + + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + + /* Configure mux for quaternary i2s */ + if (pdata->vaddr_gpio_mux_mic_ctl) { + val = ioread32(pdata->vaddr_gpio_mux_mic_ctl); + val = val | 0x02020002; + iowrite32(val, pdata->vaddr_gpio_mux_mic_ctl); + } + ret = quat_mi2s_clk_ctl(substream, true); + if (ret < 0) { + pr_err("%s: failed to enable bit clock\n", + __func__); + return ret; + } + + if (pdata->mi2s_gpio_p[QUAT_MI2S]) { + ret = msm_cdc_pinctrl_select_active_state( + pdata->mi2s_gpio_p[QUAT_MI2S]); + if (ret < 0) { + pr_err("%s: failed to actiavte the quat gpio's state\n", + __func__); + goto err; + } + } + + if (atomic_inc_return(&pdata->clk_ref.quat_mi2s_clk_ref) == 1) { + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + pr_err("%s: set fmt cpu dai failed\n", __func__); + } + return ret; + +err: + ret = quat_mi2s_clk_ctl(substream, false); + if (ret < 0) + pr_err("%s:failed to disable sclk\n", __func__); + return ret; +} + +int msm_quin_mi2s_snd_startup(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 *cpu_dai = rtd->cpu_dai; + struct msm8952_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + int ret = 0, val = 0; + + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + if (pdata->vaddr_gpio_mux_quin_ctl) { + val = ioread32(pdata->vaddr_gpio_mux_quin_ctl); + val = val | 0x00000001; + iowrite32(val, pdata->vaddr_gpio_mux_quin_ctl); + } else { + return -EINVAL; + } + ret = quin_mi2s_sclk_ctl(substream, true); + if (ret < 0) { + pr_err("failed to enable sclk\n"); + return ret; + } + if (pdata->mi2s_gpio_p[QUIN_MI2S]) { + ret = msm_cdc_pinctrl_select_active_state( + pdata->mi2s_gpio_p[QUIN_MI2S]); + if (ret < 0) { + pr_err("failed to enable codec gpios\n"); + goto err; + } + } + + if (atomic_inc_return(&pdata->clk_ref.quin_mi2s_clk_ref) == 1) { + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + pr_debug("%s: set fmt cpu dai failed\n", __func__); + } + return ret; +err: + ret = quin_mi2s_sclk_ctl(substream, false); + if (ret < 0) + pr_err("failed to disable sclk\n"); + return ret; +} + +void msm_quin_mi2s_snd_shutdown(struct snd_pcm_substream *substream) +{ + int ret; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct msm8952_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + ret = quin_mi2s_sclk_ctl(substream, false); + if (ret < 0) + pr_err("%s:clock disable failed\n", __func__); + if (atomic_read(&pdata->clk_ref.quin_mi2s_clk_ref) > 0) + atomic_dec(&pdata->clk_ref.quin_mi2s_clk_ref); + if (pdata->mi2s_gpio_p[QUIN_MI2S]) { + ret = msm_cdc_pinctrl_select_sleep_state( + pdata->mi2s_gpio_p[QUIN_MI2S]); + if (ret < 0) { + pr_err("%s: gpio set cannot be de-activated %sd", + __func__, "quin_i2s"); + return; + } + } +} + +int msm_tdm_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct msm8952_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int ret = 0, val = 0; + + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id); + + switch (cpu_dai->id) { + case AFE_PORT_ID_PRIMARY_TDM_RX: + case AFE_PORT_ID_PRIMARY_TDM_RX_1: + case AFE_PORT_ID_PRIMARY_TDM_RX_2: + case AFE_PORT_ID_PRIMARY_TDM_RX_3: + case AFE_PORT_ID_PRIMARY_TDM_RX_4: + case AFE_PORT_ID_PRIMARY_TDM_RX_5: + case AFE_PORT_ID_PRIMARY_TDM_RX_6: + case AFE_PORT_ID_PRIMARY_TDM_RX_7: + case AFE_PORT_ID_PRIMARY_TDM_TX: + case AFE_PORT_ID_PRIMARY_TDM_TX_1: + case AFE_PORT_ID_PRIMARY_TDM_TX_2: + case AFE_PORT_ID_PRIMARY_TDM_TX_3: + case AFE_PORT_ID_PRIMARY_TDM_TX_4: + case AFE_PORT_ID_PRIMARY_TDM_TX_5: + case AFE_PORT_ID_PRIMARY_TDM_TX_6: + case AFE_PORT_ID_PRIMARY_TDM_TX_7: + /* Configure mux for Primary TDM */ + if (pdata->vaddr_gpio_mux_pcm_ctl) { + val = ioread32(pdata->vaddr_gpio_mux_pcm_ctl); + val = val | 0x00000001; + iowrite32(val, pdata->vaddr_gpio_mux_pcm_ctl); + } else { + return -EINVAL; + } + + if (pdata->vaddr_gpio_mux_mic_ctl) { + val = ioread32(pdata->vaddr_gpio_mux_mic_ctl); + val = val | 0x00000002; + iowrite32(val, pdata->vaddr_gpio_mux_mic_ctl); + } else { + return -EINVAL; + } + if (pdata->mi2s_gpio_p[QUAT_MI2S]) { + ret = msm_cdc_pinctrl_select_active_state( + pdata->mi2s_gpio_p[QUAT_MI2S]); + if (ret < 0) + pr_err("%s: failed to activate pri TDM gpio\n", + __func__); + } + break; + case AFE_PORT_ID_SECONDARY_TDM_RX: + case AFE_PORT_ID_SECONDARY_TDM_RX_1: + case AFE_PORT_ID_SECONDARY_TDM_RX_2: + case AFE_PORT_ID_SECONDARY_TDM_RX_3: + case AFE_PORT_ID_SECONDARY_TDM_RX_4: + case AFE_PORT_ID_SECONDARY_TDM_RX_5: + case AFE_PORT_ID_SECONDARY_TDM_RX_6: + case AFE_PORT_ID_SECONDARY_TDM_RX_7: + case AFE_PORT_ID_SECONDARY_TDM_TX: + case AFE_PORT_ID_SECONDARY_TDM_TX_1: + case AFE_PORT_ID_SECONDARY_TDM_TX_2: + case AFE_PORT_ID_SECONDARY_TDM_TX_3: + case AFE_PORT_ID_SECONDARY_TDM_TX_4: + case AFE_PORT_ID_SECONDARY_TDM_TX_5: + case AFE_PORT_ID_SECONDARY_TDM_TX_6: + case AFE_PORT_ID_SECONDARY_TDM_TX_7: + /* Configure mux for Secondary TDM */ + if (pdata->vaddr_gpio_mux_qui_pcm_sec_mode_ctl) { + val = ioread32( + pdata->vaddr_gpio_mux_qui_pcm_sec_mode_ctl); + val = val | 0x00000001; + iowrite32(val, + pdata->vaddr_gpio_mux_qui_pcm_sec_mode_ctl); + } else { + return -EINVAL; + } + + if (pdata->vaddr_gpio_mux_quin_ctl) { + val = ioread32(pdata->vaddr_gpio_mux_quin_ctl); + val = val | 0x00000001; + iowrite32(val, pdata->vaddr_gpio_mux_quin_ctl); + } else { + return -EINVAL; + } + + if (pdata->vaddr_gpio_mux_mic_ext_clk_ctl) { + val = ioread32(pdata->vaddr_gpio_mux_mic_ext_clk_ctl); + val = val | 0x00000001; + iowrite32(val, pdata->vaddr_gpio_mux_mic_ext_clk_ctl); + } else { + return -EINVAL; + } + + if (pdata->vaddr_gpio_mux_sec_tlmm_ctl) { + val = ioread32(pdata->vaddr_gpio_mux_sec_tlmm_ctl); + val = val | 0x00000002; + iowrite32(val, pdata->vaddr_gpio_mux_sec_tlmm_ctl); + } else { + return -EINVAL; + } + + if (pdata->vaddr_gpio_mux_spkr_ctl) { + val = ioread32(pdata->vaddr_gpio_mux_spkr_ctl); + val = val | 0x00000002; + iowrite32(val, pdata->vaddr_gpio_mux_spkr_ctl); + } else { + return -EINVAL; + } + if (pdata->mi2s_gpio_p[QUIN_MI2S]) { + ret = msm_cdc_pinctrl_select_active_state( + pdata->mi2s_gpio_p[QUIN_MI2S]); + if (ret < 0) + pr_err("%s: failed to activate sec TDM gpio\n", + __func__); + } + break; + default: + pr_err("%s: dai id 0x%x not supported\n", + __func__, cpu_dai->id); + break; + return -EINVAL; + } + return ret; +} + +void msm_tdm_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_card *card = rtd->card; + struct msm8952_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + int ret; + + switch (cpu_dai->id) { + case AFE_PORT_ID_PRIMARY_TDM_RX: + case AFE_PORT_ID_PRIMARY_TDM_RX_1: + case AFE_PORT_ID_PRIMARY_TDM_RX_2: + case AFE_PORT_ID_PRIMARY_TDM_RX_3: + case AFE_PORT_ID_PRIMARY_TDM_RX_4: + case AFE_PORT_ID_PRIMARY_TDM_RX_5: + case AFE_PORT_ID_PRIMARY_TDM_RX_6: + case AFE_PORT_ID_PRIMARY_TDM_RX_7: + case AFE_PORT_ID_PRIMARY_TDM_TX: + case AFE_PORT_ID_PRIMARY_TDM_TX_1: + case AFE_PORT_ID_PRIMARY_TDM_TX_2: + case AFE_PORT_ID_PRIMARY_TDM_TX_3: + case AFE_PORT_ID_PRIMARY_TDM_TX_4: + case AFE_PORT_ID_PRIMARY_TDM_TX_5: + case AFE_PORT_ID_PRIMARY_TDM_TX_6: + case AFE_PORT_ID_PRIMARY_TDM_TX_7: + if (pdata->mi2s_gpio_p[QUAT_MI2S]) { + ret = msm_cdc_pinctrl_select_sleep_state( + pdata->mi2s_gpio_p[QUAT_MI2S]); + if (ret < 0) { + pr_err("%s: gpio cannot be de-activated %s\n", + __func__, "pri_tdm"); + return; + } + } + break; + case AFE_PORT_ID_SECONDARY_TDM_RX: + case AFE_PORT_ID_SECONDARY_TDM_RX_1: + case AFE_PORT_ID_SECONDARY_TDM_RX_2: + case AFE_PORT_ID_SECONDARY_TDM_RX_3: + case AFE_PORT_ID_SECONDARY_TDM_RX_4: + case AFE_PORT_ID_SECONDARY_TDM_RX_5: + case AFE_PORT_ID_SECONDARY_TDM_RX_6: + case AFE_PORT_ID_SECONDARY_TDM_RX_7: + case AFE_PORT_ID_SECONDARY_TDM_TX: + case AFE_PORT_ID_SECONDARY_TDM_TX_1: + case AFE_PORT_ID_SECONDARY_TDM_TX_2: + case AFE_PORT_ID_SECONDARY_TDM_TX_3: + case AFE_PORT_ID_SECONDARY_TDM_TX_4: + case AFE_PORT_ID_SECONDARY_TDM_TX_5: + case AFE_PORT_ID_SECONDARY_TDM_TX_6: + case AFE_PORT_ID_SECONDARY_TDM_TX_7: + if (pdata->mi2s_gpio_p[QUIN_MI2S]) { + ret = msm_cdc_pinctrl_select_sleep_state( + pdata->mi2s_gpio_p[QUIN_MI2S]); + if (ret < 0) { + pr_err("%s: gpio cannot be de-activated %s", + __func__, "sec_tdm"); + return; + } + } + break; + } +} + +static int msm8952_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); + + pr_debug("%s: event = %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + return msm8952_enable_codec_mclk(component, 1, true); + case SND_SOC_DAPM_POST_PMD: + return msm8952_enable_codec_mclk(component, 0, true); + } + return 0; +} + +static const struct snd_soc_dapm_widget msm8952_tasha_dapm_widgets[] = { + + SND_SOC_DAPM_SUPPLY_S("MCLK", -1, SND_SOC_NOPM, 0, 0, + msm8952_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SPK("Lineout_1 amp", NULL), + SND_SOC_DAPM_SPK("Lineout_3 amp", NULL), + SND_SOC_DAPM_SPK("Lineout_2 amp", NULL), + SND_SOC_DAPM_SPK("Lineout_4 amp", NULL), + SND_SOC_DAPM_MIC("Handset Mic", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Secondary Mic", NULL), + SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL), + SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL), + SND_SOC_DAPM_MIC("Analog Mic4", NULL), + SND_SOC_DAPM_MIC("Analog Mic6", NULL), + SND_SOC_DAPM_MIC("Analog Mic7", NULL), + SND_SOC_DAPM_MIC("Analog Mic8", NULL), + + SND_SOC_DAPM_MIC("Digital Mic0", NULL), + SND_SOC_DAPM_MIC("Digital Mic1", NULL), + SND_SOC_DAPM_MIC("Digital Mic2", NULL), + SND_SOC_DAPM_MIC("Digital Mic3", NULL), + SND_SOC_DAPM_MIC("Digital Mic4", NULL), + SND_SOC_DAPM_MIC("Digital Mic5", NULL), + SND_SOC_DAPM_MIC("Digital Mic6", NULL), +}; + +static struct snd_soc_dapm_route wcd9335_audio_paths[] = { + {"MIC BIAS1", NULL, "MCLK"}, + {"MIC BIAS2", NULL, "MCLK"}, + {"MIC BIAS3", NULL, "MCLK"}, + {"MIC BIAS4", NULL, "MCLK"}, +}; + +int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret = -EINVAL; + int err; + struct snd_soc_component *component; + struct snd_soc_dapm_context *dapm; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_card *card; + struct snd_soc_component *aux_comp; + struct snd_info_entry *entry; + struct msm8952_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(rtd->card); + + /* Codec SLIMBUS configuration + * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13 + * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13 + * TX14, TX15, TX16 + */ + unsigned int rx_ch[TASHA_RX_MAX] = {144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156}; + unsigned int tx_ch[TASHA_TX_MAX] = {128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143}; + + pr_debug("%s: dev_name%s\n", __func__, dev_name(cpu_dai->dev)); + + component = snd_soc_rtdcom_lookup(rtd, "tasha_codec"); + if (!component) { + pr_err("%s: could not find component for tasha_codec\n", + __func__); + return ret; + } + dapm = snd_soc_component_get_dapm(component); + rtd->pmdown_time = 0; + + err = snd_soc_add_component_controls(component, msm_snd_controls, + ARRAY_SIZE(msm_snd_controls)); + if (err < 0) { + pr_err("%s: add_component_controls failed, err%d\n", + __func__, err); + return err; + } + + if (!strcmp(dev_name(codec_dai->dev), "tasha_codec")) { + pdata->msm8952_codec_fn.get_afe_config_fn = + tasha_get_afe_config; + snd_soc_dapm_new_controls(dapm, msm8952_tasha_dapm_widgets, + ARRAY_SIZE(msm8952_tasha_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, wcd9335_audio_paths, + ARRAY_SIZE(wcd9335_audio_paths)); + } + + snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp"); + snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp"); + snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp"); + snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp"); + + snd_soc_dapm_ignore_suspend(dapm, "MADINPUT"); + snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_INPUT"); + snd_soc_dapm_ignore_suspend(dapm, "Handset Mic"); + snd_soc_dapm_ignore_suspend(dapm, "Headset Mic"); + snd_soc_dapm_ignore_suspend(dapm, "Secondary Mic"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2"); + snd_soc_dapm_ignore_suspend(dapm, "Lineout_1 amp"); + snd_soc_dapm_ignore_suspend(dapm, "Lineout_3 amp"); + snd_soc_dapm_ignore_suspend(dapm, "Lineout_2 amp"); + snd_soc_dapm_ignore_suspend(dapm, "Lineout_4 amp"); + snd_soc_dapm_ignore_suspend(dapm, "Handset Mic"); + snd_soc_dapm_ignore_suspend(dapm, "Headset Mic"); + snd_soc_dapm_ignore_suspend(dapm, "ANCRight Headset Mic"); + snd_soc_dapm_ignore_suspend(dapm, "ANCLeft Headset Mic"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic3"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic4"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic5"); + snd_soc_dapm_ignore_suspend(dapm, "Analog Mic4"); + snd_soc_dapm_ignore_suspend(dapm, "Analog Mic6"); + snd_soc_dapm_ignore_suspend(dapm, "Analog Mic7"); + snd_soc_dapm_ignore_suspend(dapm, "Analog Mic8"); + snd_soc_dapm_ignore_suspend(dapm, "MADINPUT"); + snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_INPUT"); + + snd_soc_dapm_ignore_suspend(dapm, "EAR"); + snd_soc_dapm_ignore_suspend(dapm, "LINEOUT1"); + snd_soc_dapm_ignore_suspend(dapm, "LINEOUT2"); + snd_soc_dapm_ignore_suspend(dapm, "LINEOUT3"); + snd_soc_dapm_ignore_suspend(dapm, "LINEOUT4"); + 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, "DMIC1"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC2"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC3"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC4"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC5"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC6"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic6"); + snd_soc_dapm_ignore_suspend(dapm, "ANC EAR"); + snd_soc_dapm_ignore_suspend(dapm, "ANC HEADPHONE"); + if (!strcmp(dev_name(codec_dai->dev), "tasha_codec")) { + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic0"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC0"); + snd_soc_dapm_ignore_suspend(dapm, "SPK1 OUT"); + snd_soc_dapm_ignore_suspend(dapm, "SPK2 OUT"); + snd_soc_dapm_ignore_suspend(dapm, "HPHL"); + snd_soc_dapm_ignore_suspend(dapm, "HPHR"); + snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL"); + snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR"); + snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1"); + snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2"); + snd_soc_dapm_ignore_suspend(dapm, "AIF4 VI"); + snd_soc_dapm_ignore_suspend(dapm, "VIINPUT"); + + } + + snd_soc_dapm_sync(dapm); + snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), + tx_ch, ARRAY_SIZE(rx_ch), rx_ch); + + err = msm_afe_set_config(component); + if (err) { + pr_err("%s: Failed to set AFE config %d\n", __func__, err); + goto out; + } + + adsp_state_notifier = + subsys_notif_register_notifier("adsp", + &adsp_state_notifier_block); + if (!adsp_state_notifier) { + pr_err("%s: Failed to register adsp state notifier\n", + __func__); + err = -EFAULT; + goto out; + } + + if (rtd->card->num_aux_devs && + !list_empty(&rtd->card->aux_comp_list)) { + aux_comp = list_first_entry(&rtd->card->aux_comp_list, + struct snd_soc_component, card_aux_list); + if (!strcmp(aux_comp->name, WSA8810_NAME_1) || + !strcmp(aux_comp->name, WSA8810_NAME_2)) { + tasha_set_spkr_mode(component, SPKR_MODE_1); + tasha_set_spkr_gain_offset(component, + RX_GAIN_OFFSET_M1P5_DB); + } + } + + if (!strcmp(dev_name(codec_dai->dev), "tasha_codec")) { + wcd_mbhc_cfg.calibration = def_tasha_mbhc_cal(); + if (wcd_mbhc_cfg.calibration) { + //pdata->codec = codec; + err = tasha_mbhc_hs_detect(component, &wcd_mbhc_cfg); + if (err < 0) + pr_err("%s: Failed to initialise mbhc %d\n", + __func__, err); + } else { + pr_err("%s: wcd_mbhc_cfg calibration is NULL\n", + __func__); + err = -ENOMEM; + goto out; + } + + } + + codec_reg_done = true; + + if (!strcmp(dev_name(codec_dai->dev), "tasha_codec")) { + card = rtd->card->snd_card; + entry = snd_info_create_subdir(card->module, + "codecs", + card->proc_root); + if (!entry) { + pr_debug("%s: Cannot create codecs module entry\n", + __func__); + err = 0; + goto out; + } + pdata->codec_root = entry; + tasha_codec_info_create_codec_entry(pdata->codec_root, + component); + } + return 0; +out: + return err; +} + +static bool msm8952_swap_gnd_mic(struct snd_soc_component *component, + bool active) +{ + struct snd_soc_card *card = component->card; + struct msm8952_asoc_mach_data *pdata = NULL; + int value = 0; + int ret = 0; + + pdata = snd_soc_card_get_drvdata(card); + if (!gpio_is_valid(pdata->us_euro_gpio)) { + pr_err("%s: Invalid gpio: %d", __func__, pdata->us_euro_gpio); + return false; + } + value = gpio_get_value_cansleep(pdata->us_euro_gpio); + if (pdata->us_euro_gpio_p) { + ret = msm_cdc_pinctrl_select_active_state( + pdata->us_euro_gpio_p); + if (ret < 0) { + pr_err("%s: gpio set cannot be activated %sd", + __func__, "us_eu_gpio"); + return false; + } + } + gpio_set_value_cansleep(pdata->us_euro_gpio, !value); + pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value); + if (pdata->us_euro_gpio_p) { + ret = msm_cdc_pinctrl_select_sleep_state( + pdata->us_euro_gpio_p); + if (ret < 0) { + pr_err("%s: gpio set cannot be de-activated %sd", + __func__, "us_eu_gpio"); + return false; + } + } + return true; +} + +static int is_us_eu_switch_gpio_support(struct platform_device *pdev, + struct msm8952_asoc_mach_data *pdata) +{ + pr_debug("%s\n", __func__); + + /* check if US-EU GPIO is supported */ + pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node, + "qcom,cdc-us-euro-gpios", 0); + if (pdata->us_euro_gpio < 0) { + dev_err(&pdev->dev, + "property %s in node %s not found %d\n", + "qcom,cdc-us-euro-gpios", pdev->dev.of_node->full_name, + pdata->us_euro_gpio); + } else { + if (!gpio_is_valid(pdata->us_euro_gpio)) { + pr_err("%s: Invalid gpio: %d", __func__, + pdata->us_euro_gpio); + return -EINVAL; + } + pdata->us_euro_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,cdc-us-eu-gpios", 0); + wcd_mbhc_cfg.swap_gnd_mic = msm8952_swap_gnd_mic; + } + return 0; +} + +static int msm8952_populate_dai_link_component_of_node( + struct snd_soc_card *card) +{ + int i, index, ret = 0; + struct device *cdev = card->dev; + struct snd_soc_dai_link *dai_link = card->dai_link; + struct device_node *phandle; + + 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].platform_of_node && dai_link[i].cpu_of_node) + continue; + /* populate platform_of_node for snd card dai links */ + if (dai_link[i].platform_name && + !dai_link[i].platform_of_node) { + index = of_property_match_string(cdev->of_node, + "asoc-platform-names", + dai_link[i].platform_name); + if (index < 0) { + pr_err("%s: No match found for platform name: %s\n", + __func__, dai_link[i].platform_name); + ret = index; + goto cpu_dai; + } + phandle = of_parse_phandle(cdev->of_node, + "asoc-platform", + index); + if (!phandle) { + pr_err("%s: retrieving phandle for platform %s, index %d failed\n", + __func__, dai_link[i].platform_name, + index); + ret = -ENODEV; + goto err; + } + dai_link[i].platform_of_node = phandle; + dai_link[i].platform_name = NULL; + } +cpu_dai: + /* populate cpu_of_node for snd card dai links */ + if (dai_link[i].cpu_dai_name && !dai_link[i].cpu_of_node) { + index = of_property_match_string(cdev->of_node, + "asoc-cpu-names", + dai_link[i].cpu_dai_name); + if (index < 0) { + pr_debug("cpu-names not found index = %d\n", i); + goto codec_dai; + } + phandle = of_parse_phandle(cdev->of_node, "asoc-cpu", + index); + if (!phandle) { + pr_err("%s: phandle for cpu dai %s failed\n", + __func__, dai_link[i].cpu_dai_name); + ret = -ENODEV; + goto err; + } + dai_link[i].cpu_of_node = phandle; + dai_link[i].cpu_dai_name = NULL; + } +codec_dai: + /* populate codec_of_node for snd card dai links */ + if (dai_link[i].codec_name && !dai_link[i].codec_of_node) { + index = of_property_match_string(cdev->of_node, + "asoc-codec-names", + dai_link[i].codec_name); + if (index < 0) + continue; + phandle = of_parse_phandle(cdev->of_node, "asoc-codec", + index); + if (!phandle) { + pr_err("%s: retrieving phandle for codec dai %s failed\n", + __func__, dai_link[i].codec_name); + ret = -ENODEV; + goto err; + } + dai_link[i].codec_of_node = phandle; + dai_link[i].codec_name = NULL; + } + } +err: + return ret; +} + +static int msm8952_asoc_machine_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card; + struct msm8952_asoc_mach_data *pdata = NULL; + const char *ext_pa = "qcom,msm-ext-pa"; + const char *ext_pa_str = NULL; + int num_strings = 0; + int ret, i; + struct resource *muxsel; + + pdata = devm_kzalloc(&pdev->dev, + sizeof(struct msm8952_asoc_mach_data), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "csr_gp_io_mux_mic_ctl"); + if (!muxsel) { + dev_err(&pdev->dev, "MUX addr invalid for MIC CTL\n"); + ret = -ENODEV; + goto err; + } + pdata->vaddr_gpio_mux_mic_ctl = + ioremap(muxsel->start, resource_size(muxsel)); + if (pdata->vaddr_gpio_mux_mic_ctl == NULL) { + pr_err("%s ioremap failure for muxsel virt addr\n", + __func__); + ret = -ENOMEM; + goto err; + } + + muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel"); + if (!muxsel) { + dev_err(&pdev->dev, "MUX addr invalid for QUAT I2S\n"); + ret = -ENODEV; + goto err; + } + pdata->vaddr_gpio_mux_pcm_ctl = + ioremap(muxsel->start, resource_size(muxsel)); + if (pdata->vaddr_gpio_mux_pcm_ctl == NULL) { + pr_err("%s ioremap failure for muxsel virt addr\n", + __func__); + ret = -ENOMEM; + goto err; + } + + muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "csr_gp_io_mux_spkr_ctl"); + if (!muxsel) { + dev_err(&pdev->dev, "MUX addr invalid for SPKR CTL\n"); + ret = -ENODEV; + goto err; + } + pdata->vaddr_gpio_mux_spkr_ctl = + ioremap(muxsel->start, resource_size(muxsel)); + if (pdata->vaddr_gpio_mux_spkr_ctl == NULL) { + pr_err("%s ioremap failure for muxsel virt addr\n", + __func__); + ret = -ENOMEM; + goto err; + } + + muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "csr_gp_io_mux_quin_ctl"); + if (!muxsel) { + dev_dbg(&pdev->dev, "MUX addr invalid for QUIN I2S\n"); + ret = -ENODEV; + } else { + pdata->vaddr_gpio_mux_quin_ctl = + ioremap(muxsel->start, resource_size(muxsel)); + if (pdata->vaddr_gpio_mux_quin_ctl == NULL) { + pr_err("%s ioremap failure for muxsel virt addr\n", + __func__); + ret = -ENOMEM; + goto err; + } + } + + muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "csr_gp_io_lpaif_qui_pcm_sec_mode_muxsel"); + if (!muxsel) { + dev_err(&pdev->dev, "MUX addr invalid for QUIN PCM\n"); + ret = -ENODEV; + } else { + pdata->vaddr_gpio_mux_qui_pcm_sec_mode_ctl = + ioremap(muxsel->start, resource_size(muxsel)); + if (pdata->vaddr_gpio_mux_qui_pcm_sec_mode_ctl == NULL) { + pr_err("%s ioremap failure for muxsel virt addr\n", + __func__); + ret = -ENOMEM; + goto err; + } + } + + muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "csr_gp_io_mux_mic_ext_clk_ctl"); + if (!muxsel) { + dev_err(&pdev->dev, "MUX addr invalid for EXT CLK CTL\n"); + ret = -ENODEV; + } else { + pdata->vaddr_gpio_mux_mic_ext_clk_ctl = + ioremap(muxsel->start, resource_size(muxsel)); + if (pdata->vaddr_gpio_mux_mic_ext_clk_ctl == NULL) { + pr_err("%s ioremap failure for muxsel virt addr\n", + __func__); + ret = -ENOMEM; + goto err; + } + } + + muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "csr_gp_io_mux_sec_tlmm_ctl"); + if (!muxsel) { + dev_err(&pdev->dev, "MUX addr invalid for SEC TLMM CTL\n"); + ret = -ENODEV; + } else { + pdata->vaddr_gpio_mux_sec_tlmm_ctl = + ioremap(muxsel->start, resource_size(muxsel)); + if (pdata->vaddr_gpio_mux_sec_tlmm_ctl == NULL) { + pr_err("%s ioremap failure for muxsel virt addr\n", + __func__); + ret = -ENOMEM; + goto err; + } + } + + pdev->id = 0; + + atomic_set(&pdata->clk_ref.quat_mi2s_clk_ref, 0); + atomic_set(&pdata->clk_ref.auxpcm_mi2s_clk_ref, 0); + card = populate_snd_card_dailinks(&pdev->dev); + if (!card) { + ret = -EPROBE_DEFER; + goto err; + } + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, pdata); + + ret = snd_soc_of_parse_audio_routing(card, + "qcom,audio-routing"); + if (ret) + goto err; + + ret = msm8952_populate_dai_link_component_of_node(card); + if (ret) { + ret = -EPROBE_DEFER; + goto err; + } + + ret = msm8952_init_wsa_dev(pdev, card); + if (ret) + goto err; + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) { + if (codec_reg_done) + ret = -EINVAL; + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + goto err; + } + num_strings = of_property_count_strings(pdev->dev.of_node, + ext_pa); + if (num_strings < 0) { + dev_err(&pdev->dev, + "%s: missing %s in dt node or length is incorrect\n", + __func__, ext_pa); + pdata->ext_pa = 0; + } + for (i = 0; i < num_strings; i++) { + of_property_read_string_index(pdev->dev.of_node, + ext_pa, i, &ext_pa_str); + if (!strcmp(ext_pa_str, "primary")) + pdata->ext_pa = (pdata->ext_pa | PRI_MI2S_ID); + else if (!strcmp(ext_pa_str, "secondary")) + pdata->ext_pa = (pdata->ext_pa | SEC_MI2S_ID); + else if (!strcmp(ext_pa_str, "tertiary")) + pdata->ext_pa = (pdata->ext_pa | TER_MI2S_ID); + else if (!strcmp(ext_pa_str, "quaternary")) + pdata->ext_pa = (pdata->ext_pa | QUAT_MI2S_ID); + else if (!strcmp(ext_pa_str, "quinary")) + pdata->ext_pa = (pdata->ext_pa | QUIN_MI2S_ID); + } + + /* 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 + */ + ret = is_us_eu_switch_gpio_support(pdev, pdata); + if (ret < 0) { + pr_err("%s: failed to is_us_eu_switch_gpio_support %d\n", + __func__, ret); + goto err; + } + pdata->mi2s_gpio_p[QUAT_MI2S] = of_parse_phandle(pdev->dev.of_node, + "qcom,quat-mi2s-gpios", 0); + pdata->mi2s_gpio_p[QUIN_MI2S] = of_parse_phandle(pdev->dev.of_node, + "qcom,quin-mi2s-gpios", 0); + + return 0; +err: + if (pdata->us_euro_gpio > 0) { + dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n", + __func__, pdata->us_euro_gpio); + gpio_free(pdata->us_euro_gpio); + pdata->us_euro_gpio = 0; + } + if (pdata->vaddr_gpio_mux_spkr_ctl) + iounmap(pdata->vaddr_gpio_mux_spkr_ctl); + if (pdata->vaddr_gpio_mux_mic_ctl) + iounmap(pdata->vaddr_gpio_mux_mic_ctl); + if (pdata->vaddr_gpio_mux_pcm_ctl) + iounmap(pdata->vaddr_gpio_mux_pcm_ctl); + if (pdata->vaddr_gpio_mux_quin_ctl) + iounmap(pdata->vaddr_gpio_mux_quin_ctl); + if (pdata->vaddr_gpio_mux_qui_pcm_sec_mode_ctl) + iounmap(pdata->vaddr_gpio_mux_qui_pcm_sec_mode_ctl); + if (pdata->vaddr_gpio_mux_mic_ext_clk_ctl) + iounmap(pdata->vaddr_gpio_mux_mic_ext_clk_ctl); + if (pdata->vaddr_gpio_mux_sec_tlmm_ctl) + iounmap(pdata->vaddr_gpio_mux_sec_tlmm_ctl); + devm_kfree(&pdev->dev, pdata); + return ret; +} + +static int msm8952_asoc_machine_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct msm8952_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + + if (pdata->us_euro_gpio > 0) { + dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n", + __func__, pdata->us_euro_gpio); + gpio_free(pdata->us_euro_gpio); + pdata->us_euro_gpio = 0; + } + if (pdata->vaddr_gpio_mux_spkr_ctl) + iounmap(pdata->vaddr_gpio_mux_spkr_ctl); + if (pdata->vaddr_gpio_mux_mic_ctl) + iounmap(pdata->vaddr_gpio_mux_mic_ctl); + if (pdata->vaddr_gpio_mux_pcm_ctl) + iounmap(pdata->vaddr_gpio_mux_pcm_ctl); + if (pdata->vaddr_gpio_mux_quin_ctl) + iounmap(pdata->vaddr_gpio_mux_quin_ctl); + if (pdata->vaddr_gpio_mux_qui_pcm_sec_mode_ctl) + iounmap(pdata->vaddr_gpio_mux_qui_pcm_sec_mode_ctl); + if (pdata->vaddr_gpio_mux_mic_ext_clk_ctl) + iounmap(pdata->vaddr_gpio_mux_mic_ext_clk_ctl); + if (pdata->vaddr_gpio_mux_sec_tlmm_ctl) + iounmap(pdata->vaddr_gpio_mux_sec_tlmm_ctl); + msm895x_free_auxdev_mem(pdev); + + snd_soc_unregister_card(card); + return 0; +} + +static const struct of_device_id msm8952_asoc_machine_of_match[] = { + { .compatible = "qcom,msm8952-audio-slim-codec", }, + {}, +}; + +static struct platform_driver msm8952_asoc_machine_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = msm8952_asoc_machine_of_match, + }, + .probe = msm8952_asoc_machine_probe, + .remove = msm8952_asoc_machine_remove, +}; + +static int __init msm8952_slim_machine_init(void) +{ + return platform_driver_register(&msm8952_asoc_machine_driver); +} +module_init(msm8952_slim_machine_init); + +static void __exit msm8952_slim_machine_exit(void) +{ + return platform_driver_unregister(&msm8952_asoc_machine_driver); +} +module_exit(msm8952_slim_machine_exit); + +MODULE_DESCRIPTION("ALSA SoC msm"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, msm8952_asoc_machine_of_match); diff --git a/asoc/msm8952-slimbus.h b/asoc/msm8952-slimbus.h new file mode 100644 index 000000000000..12fab94bf10b --- /dev/null +++ b/asoc/msm8952-slimbus.h @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2015-2018, 2021, The Linux Foundation. All rights reserved. + */ + +#ifndef __MSM8952_SLIMBUS_AUDIO +#define __MSM8952_SLIMBUS_AUDIO + +#include + +struct ext_intf_cfg { + atomic_t quat_mi2s_clk_ref; + atomic_t quin_mi2s_clk_ref; + atomic_t auxpcm_mi2s_clk_ref; +}; + +enum { + PRIM_MI2S = 0, + SEC_MI2S, + TERT_MI2S, + QUAT_MI2S, + QUIN_MI2S, + MI2S_MAX, +}; + +struct msm8952_codec { + void* (*get_afe_config_fn)(struct snd_soc_component *component, + enum afe_config_type config_type); +}; + +struct msm8952_asoc_mach_data { + int ext_pa; + int us_euro_gpio; + struct delayed_work hs_detect_dwork; + struct snd_soc_codec *codec; + struct msm8952_codec msm8952_codec_fn; + struct ext_intf_cfg clk_ref; + struct snd_info_entry *codec_root; + void __iomem *vaddr_gpio_mux_spkr_ctl; + void __iomem *vaddr_gpio_mux_mic_ctl; + void __iomem *vaddr_gpio_mux_pcm_ctl; + void __iomem *vaddr_gpio_mux_quin_ctl; + void __iomem *vaddr_gpio_mux_qui_pcm_sec_mode_ctl; + void __iomem *vaddr_gpio_mux_mic_ext_clk_ctl; + void __iomem *vaddr_gpio_mux_sec_tlmm_ctl; + struct device_node *us_euro_gpio_p; + struct device_node *mi2s_gpio_p[MI2S_MAX]; +}; + +int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +int msm_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +int msm_slim_1_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +int msm_slim_2_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +int msm_slim_4_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +int msm_slim_4_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +int msm_slim_5_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +int msm_slim_6_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +int msm_slim_5_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +int msm_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); +int msm8952_slimbus_2_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); +int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +int msm_quin_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +int msm_proxy_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +int msm_proxy_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +int msm_tdm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +int msm_audrx_init(struct snd_soc_pcm_runtime *rtd); +int msm_mi2s_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); +int msm_snd_cpe_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); +int msm_tdm_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); +int msm_quat_mi2s_snd_startup(struct snd_pcm_substream *substream); +void msm_quat_mi2s_snd_shutdown(struct snd_pcm_substream *substream); + +int msm_quin_mi2s_snd_startup(struct snd_pcm_substream *substream); +void msm_quin_mi2s_snd_shutdown(struct snd_pcm_substream *substream); + +int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +int msm_prim_auxpcm_startup(struct snd_pcm_substream *substream); +void msm_prim_auxpcm_shutdown(struct snd_pcm_substream *substream); + +int msm_tdm_startup(struct snd_pcm_substream *substream); +void msm_tdm_shutdown(struct snd_pcm_substream *substream); + +struct snd_soc_card *populate_snd_card_dailinks(struct device *dev); +int msm_slim_4_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +int msm895x_wsa881x_init(struct snd_soc_component *component); +int msm8952_init_wsa_dev(struct platform_device *pdev, + struct snd_soc_card *card); +void msm895x_free_auxdev_mem(struct platform_device *pdev); +#endif diff --git a/asoc/msm8952.c b/asoc/msm8952.c new file mode 100644 index 000000000000..b03e135c2ba2 --- /dev/null +++ b/asoc/msm8952.c @@ -0,0 +1,3630 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2015-2016, 2018, 2020-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 "msm-pcm-routing-v2.h" +#include +#include "msm8952.h" + +#define DRV_NAME "msm8952-asoc-wcd" + +#define MSM_INT_DIGITAL_CODEC "msm-dig-codec" +#define PMIC_INT_ANALOG_CODEC "analog-codec" +#define EXT_SMART_PA "ext-smart-pa" + +enum btsco_rates { + RATE_8KHZ_ID, + RATE_16KHZ_ID, +}; + +/* dummy definition of deprecated FE DAI's*/ +enum { + MSM_FRONTEND_DAI_CS_VOICE = 39, + MSM_FRONTEND_DAI_VOICE2, + MSM_FRONTEND_DAI_VOLTE, + MSM_FRONTEND_DAI_VOWLAN, +}; + +static int msm8952_auxpcm_rate = 8000; +static int msm_btsco_rate = BTSCO_RATE_8KHZ; +static int msm_btsco_ch = 1; +static int msm_ter_mi2s_tx_ch = 1; +static int msm_pri_mi2s_rx_ch = 1; +static int msm_proxy_rx_ch = 2; +static int msm_vi_feed_tx_ch = 2; +static int mi2s_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; +static int mi2s_rx_bits_per_sample = 16; +static int mi2s_rx_sample_rate = SAMPLING_RATE_48KHZ; + +static atomic_t quat_mi2s_clk_ref; +static atomic_t quin_mi2s_clk_ref; +static atomic_t auxpcm_mi2s_clk_ref; +static struct snd_info_entry *codec_root; + +static int msm8952_enable_dig_cdc_clk(struct snd_soc_component *component, + int enable, bool dapm); +static bool msm8952_swap_gnd_mic(struct snd_soc_component *component, + bool active); +static int msm8952_mclk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event); +static int msm8952_dig_mclk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event); +static int msm8952_wsa_switch_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event); +static int msm_dmic_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event); +/* + * Android L spec + * Need to report LINEIN + * if R/L channel impedance is larger than 5K ohm + */ +static struct wcd_mbhc_config mbhc_cfg = { + .read_fw_bin = false, + .calibration = NULL, + .detect_extn_cable = true, + .mono_stero_detection = false, + .swap_gnd_mic = NULL, + .hs_ext_micbias = false, + .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 = 0, + .anc_micbias = 0, + .enable_anc_mic_detect = false, +}; + +static struct afe_clk_set mi2s_tx_clk = { + AFE_API_VERSION_I2S_CONFIG, + Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT, + Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, +}; + +static struct afe_clk_set mi2s_rx_clk = { + AFE_API_VERSION_I2S_CONFIG, + Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT, + Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, +}; + +static struct afe_clk_set wsa_ana_clk = { + AFE_API_VERSION_I2S_CONFIG, + Q6AFE_LPASS_CLK_ID_MCLK_1, + Q6AFE_LPASS_OSR_CLK_9_P600_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, +}; + +static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"}; +static const char *const mi2s_ch_text[] = {"One", "Two"}; +static const char *const loopback_mclk_text[] = {"DISABLE", "ENABLE"}; +static const char *const btsco_rate_text[] = {"BTSCO_RATE_8KHZ", + "BTSCO_RATE_16KHZ"}; +static const char *const proxy_rx_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", "Eight"}; +static const char *const vi_feed_ch_text[] = {"One", "Two"}; +static char const *mi2s_rx_sample_rate_text[] = {"KHZ_48", + "KHZ_96", "KHZ_192"}; + +static inline int param_is_mask(int p) +{ + return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) && + (p <= SNDRV_PCM_HW_PARAM_LAST_MASK); +} + +static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n) +{ + return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]); +} + +static void param_set_mask(struct snd_pcm_hw_params *p, int n, + unsigned int bit) +{ + if (bit >= SNDRV_MASK_MAX) + return; + if (param_is_mask(n)) { + struct snd_mask *m = param_to_mask(p, n); + + m->bits[0] = 0; + m->bits[1] = 0; + m->bits[bit >> 5] |= (1 << (bit & 31)); + } +} + +static int msm8952_mclk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct msm_asoc_mach_data *pdata = NULL; + int ret = 0; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + pdata = snd_soc_card_get_drvdata(component->card); + pr_debug("%s: event = %d\n", __func__, event); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (pdata->mi2s_gpio_p[PRIM_MI2S]) { + ret = msm_cdc_pinctrl_select_active_state( + pdata->mi2s_gpio_p[PRIM_MI2S]); + if (ret) { + pr_err("%s: failed to enable pri gpios: %d\n", + __func__, ret); + break; + } + } + msm8952_enable_dig_cdc_clk(component, 1, true); + msm_anlg_cdc_mclk_enable(component, 1, true); + break; + case SND_SOC_DAPM_POST_PMD: + pr_debug("%s: mclk_res_ref = %d\n", + __func__, atomic_read(&pdata->int_mclk0_rsc_ref)); + if (pdata->mi2s_gpio_p[PRIM_MI2S]) { + ret = msm_cdc_pinctrl_select_sleep_state( + pdata->mi2s_gpio_p[PRIM_MI2S]); + if (ret < 0) { + pr_err("%s: gpio set cannot be de-activated %s", + __func__, "pri_i2s"); + return ret; + } + } + pr_debug("%s: disabling MCLK\n", __func__); + /* disable the codec mclk config*/ + msm_anlg_cdc_mclk_enable(component, 0, true); + msm8952_enable_dig_cdc_clk(component, 0, true); + break; + default: + pr_err("%s: invalid DAPM event %d\n", __func__, event); + return -EINVAL; + } + return 0; +} + +static int msm8952_dig_mclk_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); + + pdata = snd_soc_card_get_drvdata(component->card); + pr_debug("%s: event = %d\n", __func__, event); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + msm_digcdc_mclk_enable(component, 1, true); + msm8952_enable_dig_cdc_clk(component, 1, true); + break; + case SND_SOC_DAPM_POST_PMD: + /* disable the codec mclk config*/ + msm_digcdc_mclk_enable(component, 0, true); + msm8952_enable_dig_cdc_clk(component, 0, true); + break; + default: + pr_err("%s: invalid DAPM event %d\n", __func__, event); + return -EINVAL; + } + return 0; +} + +static int msm8952_wsa_switch_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + int ret = 0; + struct msm_asoc_mach_data *pdata = NULL; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct on_demand_supply *supply; + + pdata = snd_soc_card_get_drvdata(component->card); + supply = &pdata->wsa_switch_supply; + if (!supply->supply) { + dev_err(component->card->dev, "%s: no wsa switch supply", + __func__); + return ret; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (atomic_inc_return(&supply->ref) == 1) + ret = regulator_enable(supply->supply); + if (ret) + dev_err(component->card->dev, + "%s: Failed to enable wsa switch supply\n", + __func__); + break; + case SND_SOC_DAPM_POST_PMD: + if (atomic_read(&supply->ref) == 0) { + dev_dbg(component->card->dev, + "%s: wsa switch supply has been disabled.\n", + __func__); + return ret; + } + if (atomic_dec_return(&supply->ref) == 0) { + ret = regulator_disable(supply->supply); + if (ret) + dev_err(component->card->dev, + "%s: Failed to disable wsa switch supply\n", + __func__); + } + break; + default: + break; + } + + 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; + + pdata = snd_soc_card_get_drvdata(component->card); + pr_debug("%s: event = %d\n", __func__, event); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = msm_cdc_pinctrl_select_active_state(pdata->dmic_gpio_p); + if (ret < 0) { + pr_err("%s: gpio set cannot be activated %sd", + __func__, "dmic_gpio"); + return ret; + } + break; + case SND_SOC_DAPM_POST_PMD: + ret = msm_cdc_pinctrl_select_sleep_state(pdata->dmic_gpio_p); + 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 msm8952_dapm_widgets[] = { + + SND_SOC_DAPM_SUPPLY_S("MCLK", -1, SND_SOC_NOPM, 0, 0, + msm8952_mclk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIC("Handset Mic", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Secondary Mic", NULL), + SND_SOC_DAPM_MIC("Digital Mic1", NULL), + SND_SOC_DAPM_MIC("Digital Mic2", NULL), + SND_SOC_DAPM_SUPPLY("VDD_WSA_SWITCH", SND_SOC_NOPM, 0, 0, + msm8952_wsa_switch_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_widget msm8952_dig_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY_S("MCLK", -1, SND_SOC_NOPM, 0, 0, + msm8952_dig_mclk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIC("Digital Mic1", msm_dmic_event), + SND_SOC_DAPM_MIC("Digital Mic2", msm_dmic_event), +}; + +static int config_hph_compander_gpio(bool enable, + struct snd_soc_component *component) +{ + int ret = 0; + struct snd_soc_card *card = component->card; + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + + pr_debug("%s: %s HPH Compander\n", __func__, + enable ? "Enable" : "Disable"); + + if (pdata->comp_gpio_p) { + if (enable) { + ret = msm_cdc_pinctrl_select_active_state( + pdata->comp_gpio_p); + if (ret) { + pr_err("%s: gpio set cannot be activated %s\n", + __func__, "comp_gpio"); + goto done; + } + } else { + ret = msm_cdc_pinctrl_select_sleep_state( + pdata->comp_gpio_p); + if (ret) { + pr_err("%s: gpio set cannot be de-activated %s\n", + __func__, "comp_gpio"); + goto done; + } + } + } + +done: + return ret; +} + +int is_ext_spk_gpio_support(struct platform_device *pdev, + struct msm_asoc_mach_data *pdata) +{ + const char *spk_ext_pa = "qcom,msm-spk-ext-pa"; + + pr_debug("%s:Enter\n", __func__); + + pdata->spk_ext_pa_gpio = of_get_named_gpio(pdev->dev.of_node, + spk_ext_pa, 0); + + if (pdata->spk_ext_pa_gpio < 0) { + dev_err(&pdev->dev, + "%s: missing %s in dt node\n", __func__, spk_ext_pa); + } else { + if (!gpio_is_valid(pdata->spk_ext_pa_gpio)) { + pr_err("%s: Invalid external speaker gpio: %d", + __func__, pdata->spk_ext_pa_gpio); + return -EINVAL; + } + } + return 0; +} + +static int enable_spk_ext_pa(struct snd_soc_component *component, int enable) +{ + struct snd_soc_card *card = component->card; + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + int ret; + + if (!gpio_is_valid(pdata->spk_ext_pa_gpio)) { + pr_err("%s: Invalid gpio: %d\n", __func__, + pdata->spk_ext_pa_gpio); + return false; + } + + pr_debug("%s: %s external speaker PA\n", __func__, + enable ? "Enable" : "Disable"); + + if (enable) { + ret = msm_cdc_pinctrl_select_active_state( + pdata->spk_ext_pa_gpio_p); + if (ret) { + pr_err("%s: gpio set cannot be de-activated %s\n", + __func__, "ext_spk_gpio"); + return ret; + } + gpio_set_value_cansleep(pdata->spk_ext_pa_gpio, enable); + } else { + gpio_set_value_cansleep(pdata->spk_ext_pa_gpio, enable); + ret = msm_cdc_pinctrl_select_sleep_state( + pdata->spk_ext_pa_gpio_p); + if (ret) { + pr_err("%s: gpio set cannot be de-activated %s\n", + __func__, "ext_spk_gpio"); + return ret; + } + } + return 0; +} + +static bool msm8952_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); + int value = 0, ret = 0; + + pr_debug("%s: configure gpios for US_EU\n", __func__); + + if (!gpio_is_valid(pdata->us_euro_gpio)) { + pr_err("%s: Invalid gpio: %d", __func__, pdata->us_euro_gpio); + return false; + } + value = gpio_get_value_cansleep(pdata->us_euro_gpio); + if (pdata->us_euro_gpio_p) { + ret = msm_cdc_pinctrl_select_active_state( + pdata->us_euro_gpio_p); + if (ret < 0) { + pr_err("%s: gpio set cannot be activated %sd", + __func__, "us_eu_gpio"); + return false; + } + } + gpio_set_value_cansleep(pdata->us_euro_gpio, !value); + if (pdata->us_euro_gpio_p) { + ret = msm_cdc_pinctrl_select_sleep_state( + pdata->us_euro_gpio_p); + if (ret < 0) { + pr_err("%s: gpio set cannot be de-activated %sd", + __func__, "us_eu_gpio"); + return false; + } + } + pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value); + return true; +} + +/* Validate whether US EU switch is present or not */ +int is_us_eu_switch_gpio_support(struct platform_device *pdev, + struct msm_asoc_mach_data *pdata) +{ + /* check if US-EU GPIO is supported */ + pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node, + "qcom,cdc-us-euro-gpios", 0); + if (pdata->us_euro_gpio < 0) { + dev_err(&pdev->dev, + "property %s in node %s not found %d\n", + "qcom,cdc-us-euro-gpios", pdev->dev.of_node->full_name, + pdata->us_euro_gpio); + } else { + if (!gpio_is_valid(pdata->us_euro_gpio)) { + pr_err("%s: Invalid gpio: %d", __func__, + pdata->us_euro_gpio); + return -EINVAL; + } + pdata->us_euro_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,cdc-us-eu-gpios", 0); + mbhc_cfg.swap_gnd_mic = msm8952_swap_gnd_mic; + } + return 0; +} + +static int msm_proxy_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_proxy_rx_ch = %d\n", __func__, + msm_proxy_rx_ch); + ucontrol->value.integer.value[0] = msm_proxy_rx_ch - 1; + return 0; +} + +static int msm_proxy_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_proxy_rx_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_proxy_rx_ch = %d\n", __func__, + msm_proxy_rx_ch); + return 0; +} + +static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + + rate->min = rate->max = msm8952_auxpcm_rate; + channels->min = channels->max = 1; + + return 0; +} + +static int msm_mi2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + pr_debug("%s: Num of channels = %d Sample rate = %d\n", __func__, + msm_pri_mi2s_rx_ch, mi2s_rx_sample_rate); + rate->min = rate->max = mi2s_rx_sample_rate; + channels->min = channels->max = msm_pri_mi2s_rx_ch; + + return 0; +} + +static int msm_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + pr_debug("%s(), channel:%d\n", __func__, msm_ter_mi2s_tx_ch); + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + SNDRV_PCM_FORMAT_S16_LE); + rate->min = rate->max = 48000; + channels->min = channels->max = msm_ter_mi2s_tx_ch; + + return 0; +} + +static int msm_senary_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + return 0; +} + +static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + pr_debug("%s()\n", __func__); + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + return 0; +} + +static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + rate->min = rate->max = msm_btsco_rate; + channels->min = channels->max = msm_btsco_ch; + + return 0; +} + +static int msm_proxy_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + pr_debug("%s: msm_proxy_rx_ch =%d\n", __func__, msm_proxy_rx_ch); + + if (channels->max < 2) + channels->min = channels->max = 2; + channels->min = channels->max = msm_proxy_rx_ch; + rate->min = rate->max = 48000; + return 0; +} + +static int msm_proxy_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + + rate->min = rate->max = 48000; + return 0; +} + +static int msm_mi2s_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_rx_bit_format); + else + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + SNDRV_PCM_FORMAT_S16_LE); + return 0; +} +static int msm8952_get_clk_id(int port_id) +{ + switch (port_id) { + case AFE_PORT_ID_PRIMARY_MI2S_RX: + return Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT; + case AFE_PORT_ID_SECONDARY_MI2S_RX: + return Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT; + case AFE_PORT_ID_TERTIARY_MI2S_TX: + return Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT; + case AFE_PORT_ID_QUATERNARY_MI2S_RX: + case AFE_PORT_ID_QUATERNARY_MI2S_TX: + return Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT; + case AFE_PORT_ID_QUINARY_MI2S_RX: + case AFE_PORT_ID_QUINARY_MI2S_TX: + return Q6AFE_LPASS_CLK_ID_QUI_MI2S_IBIT; + case AFE_PORT_ID_SENARY_MI2S_TX: + return Q6AFE_LPASS_CLK_ID_SEN_MI2S_IBIT; + default: + pr_err("%s: invalid port_id: 0x%x\n", __func__, port_id); + return -EINVAL; + } +} + +static int msm8952_get_port_id(int be_id) +{ + switch (be_id) { + case MSM_BACKEND_DAI_PRI_MI2S_RX: + return AFE_PORT_ID_PRIMARY_MI2S_RX; + case MSM_BACKEND_DAI_SECONDARY_MI2S_RX: + return AFE_PORT_ID_SECONDARY_MI2S_RX; + case MSM_BACKEND_DAI_TERTIARY_MI2S_TX: + return AFE_PORT_ID_TERTIARY_MI2S_TX; + case MSM_BACKEND_DAI_QUATERNARY_MI2S_RX: + return AFE_PORT_ID_QUATERNARY_MI2S_RX; + case MSM_BACKEND_DAI_QUATERNARY_MI2S_TX: + return AFE_PORT_ID_QUATERNARY_MI2S_TX; + case MSM_BACKEND_DAI_QUINARY_MI2S_RX: + return AFE_PORT_ID_QUINARY_MI2S_RX; + case MSM_BACKEND_DAI_QUINARY_MI2S_TX: + return AFE_PORT_ID_QUINARY_MI2S_TX; + case MSM_BACKEND_DAI_SENARY_MI2S_TX: + return AFE_PORT_ID_SENARY_MI2S_TX; + default: + pr_err("%s: Invalid.id: %d\n", __func__, be_id); + return -EINVAL; + } +} + +static bool is_mi2s_rx_port(int port_id) +{ + bool ret = false; + + switch (port_id) { + case AFE_PORT_ID_PRIMARY_MI2S_RX: + case AFE_PORT_ID_SECONDARY_MI2S_RX: + case AFE_PORT_ID_QUATERNARY_MI2S_RX: + case AFE_PORT_ID_QUINARY_MI2S_RX: + ret = true; + break; + default: + break; + } + return ret; +} + +static uint32_t get_mi2s_rx_clk_val(int port_id) +{ + uint32_t clk_val = 0; + + /* + * Derive clock value based on sample rate, bits per sample and + * channel count is used as 2 + */ + if (is_mi2s_rx_port(port_id)) + clk_val = (mi2s_rx_sample_rate * mi2s_rx_bits_per_sample * 2); + + pr_debug("%s: MI2S Rx bit clock value: 0x%0x\n", __func__, clk_val); + return clk_val; +} + +static int msm_mi2s_sclk_ctl(struct snd_pcm_substream *substream, bool enable) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int port_id = 0; + + port_id = msm8952_get_port_id(rtd->dai_link->id); + if (port_id < 0) { + pr_err("%s: Invalid port_id\n", __func__); + return -EINVAL; + } + if (enable) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + mi2s_rx_clk.enable = enable; + mi2s_rx_clk.clk_id = + msm8952_get_clk_id(port_id); + mi2s_rx_clk.clk_freq_in_hz = + get_mi2s_rx_clk_val(port_id); + ret = afe_set_lpass_clock_v2(port_id, + &mi2s_rx_clk); + } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + mi2s_tx_clk.enable = enable; + mi2s_tx_clk.clk_id = + msm8952_get_clk_id(port_id); + mi2s_tx_clk.clk_freq_in_hz = + Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ; + ret = afe_set_lpass_clock_v2(port_id, + &mi2s_tx_clk); + } else { + pr_err("%s:Not valid substream.\n", __func__); + } + + if (ret < 0) + pr_err("%s:afe_set_lpass_clock_v2 failed\n", __func__); + } else { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + mi2s_rx_clk.enable = enable; + mi2s_rx_clk.clk_id = + msm8952_get_clk_id(port_id); + ret = afe_set_lpass_clock_v2(port_id, + &mi2s_rx_clk); + } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + mi2s_tx_clk.enable = enable; + mi2s_tx_clk.clk_id = + msm8952_get_clk_id(port_id); + ret = afe_set_lpass_clock_v2(port_id, + &mi2s_tx_clk); + } else { + pr_err("%s:Not valid substream.\n", __func__); + } + + if (ret < 0) + pr_err("%s:afe_set_lpass_clock_v2 failed\n", __func__); + } + return ret; +} + +static int msm8952_enable_dig_cdc_clk(struct snd_soc_component *component, + int enable, bool dapm) +{ + int ret = 0; + struct msm_asoc_mach_data *pdata = NULL; + + pdata = snd_soc_card_get_drvdata(component->card); + pr_debug("%s: enable %d mclk ref counter %d\n", + __func__, enable, + atomic_read(&pdata->int_mclk0_rsc_ref)); + if (enable) { + if (!atomic_read(&pdata->int_mclk0_rsc_ref)) { + cancel_delayed_work_sync( + &pdata->disable_int_mclk0_work); + mutex_lock(&pdata->cdc_int_mclk0_mutex); + if (atomic_read(&pdata->int_mclk0_enabled) == false) { + pdata->digital_cdc_core_clk.enable = 1; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_PRIMARY_MI2S_RX, + &pdata->digital_cdc_core_clk); + if (ret < 0) { + pr_err("%s: failed to enable CCLK\n", + __func__); + mutex_unlock( + &pdata->cdc_int_mclk0_mutex); + return ret; + } + pr_debug("enabled digital codec core clk\n"); + atomic_set(&pdata->int_mclk0_enabled, true); + } + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + } + atomic_inc(&pdata->int_mclk0_rsc_ref); + } else { + cancel_delayed_work_sync(&pdata->disable_int_mclk0_work); + mutex_lock(&pdata->cdc_int_mclk0_mutex); + if (atomic_read(&pdata->int_mclk0_enabled) == true) { + pdata->digital_cdc_core_clk.clk_freq_in_hz = + DEFAULT_MCLK_RATE; + pdata->digital_cdc_core_clk.enable = 0; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_PRIMARY_MI2S_RX, + &pdata->digital_cdc_core_clk); + if (ret < 0) + pr_err("%s: failed to disable CCLK\n", + __func__); + atomic_set(&pdata->int_mclk0_enabled, false); + atomic_set(&pdata->int_mclk0_rsc_ref, 0); + } + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + } + return ret; +} + +static int msm_btsco_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_btsco_rate = %d", __func__, msm_btsco_rate); + ucontrol->value.integer.value[0] = msm_btsco_rate; + return 0; +} + +static int msm_btsco_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case RATE_8KHZ_ID: + msm_btsco_rate = BTSCO_RATE_8KHZ; + break; + case RATE_16KHZ_ID: + msm_btsco_rate = BTSCO_RATE_16KHZ; + break; + default: + msm_btsco_rate = BTSCO_RATE_8KHZ; + break; + } + + pr_debug("%s: msm_btsco_rate = %d\n", __func__, msm_btsco_rate); + return 0; +} + +static int mi2s_rx_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + switch (mi2s_rx_bit_format) { + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + + pr_debug("%s: mi2s_rx_bit_format = %d, ucontrol value = %ld\n", + __func__, mi2s_rx_bit_format, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int mi2s_rx_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 2: + mi2s_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + mi2s_rx_bits_per_sample = 32; + break; + case 1: + mi2s_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE; + mi2s_rx_bits_per_sample = 32; + break; + case 0: + default: + mi2s_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; + mi2s_rx_bits_per_sample = 16; + break; + } + return 0; +} + +static int loopback_mclk_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s\n", __func__); + return 0; +} + +static int loopback_mclk_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + struct msm_asoc_mach_data *pdata = NULL; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + pdata = snd_soc_card_get_drvdata(component->card); + pr_debug("%s: int_mclk0_rsc_ref %d enable %ld\n", + __func__, atomic_read(&pdata->int_mclk0_rsc_ref), + ucontrol->value.integer.value[0]); + switch (ucontrol->value.integer.value[0]) { + case 1: + if (pdata->mi2s_gpio_p[PRIM_MI2S]) { + ret = msm_cdc_pinctrl_select_active_state( + pdata->mi2s_gpio_p[PRIM_MI2S]); + if (ret) { + pr_err("%s: failed to enable pri gpios: %d\n", + __func__, ret); + break; + } + } + mutex_lock(&pdata->cdc_int_mclk0_mutex); + if ((!atomic_read(&pdata->int_mclk0_rsc_ref)) && + (!atomic_read(&pdata->int_mclk0_enabled))) { + pdata->digital_cdc_core_clk.enable = 1; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_PRIMARY_MI2S_RX, + &pdata->digital_cdc_core_clk); + if (ret < 0) { + pr_err("%s: failed to enable the MCLK: %d\n", + __func__, ret); + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + if (pdata->mi2s_gpio_p[PRIM_MI2S]) { + ret = + msm_cdc_pinctrl_select_sleep_state( + pdata->mi2s_gpio_p[PRIM_MI2S]); + if (ret) + pr_err("%s disable gpio fail\n", + __func__); + } + break; + } + atomic_set(&pdata->int_mclk0_enabled, true); + } + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + atomic_inc(&pdata->int_mclk0_rsc_ref); + msm_anlg_cdc_mclk_enable(component, 1, true); + break; + case 0: + if (atomic_read(&pdata->int_mclk0_rsc_ref) <= 0) + break; + msm_anlg_cdc_mclk_enable(component, 0, true); + mutex_lock(&pdata->cdc_int_mclk0_mutex); + if ((!atomic_dec_return(&pdata->int_mclk0_rsc_ref)) && + (atomic_read(&pdata->int_mclk0_enabled))) { + pdata->digital_cdc_core_clk.enable = 0; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_PRIMARY_MI2S_RX, + &pdata->digital_cdc_core_clk); + if (ret < 0) { + pr_err("%s: failed to disable the CCLK: %d\n", + __func__, ret); + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + break; + } + atomic_set(&pdata->int_mclk0_enabled, false); + } + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + if (pdata->mi2s_gpio_p[PRIM_MI2S]) { + ret = msm_cdc_pinctrl_select_sleep_state( + pdata->mi2s_gpio_p[PRIM_MI2S]); + if (ret) + pr_err("%s: failed to disable pri gpios: %d\n", + __func__, ret); + } + break; + default: + pr_err("%s: Unexpected input value\n", __func__); + break; + } + return ret; +} + +static int msm_pri_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_pri_mi2s_rx_ch = %d\n", __func__, + msm_pri_mi2s_rx_ch); + ucontrol->value.integer.value[0] = msm_pri_mi2s_rx_ch - 1; + return 0; +} + +static int msm_pri_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_pri_mi2s_rx_ch = ucontrol->value.integer.value[0] + 1; + + pr_debug("%s: msm_pri_mi2s_rx_ch = %d\n", __func__, msm_pri_mi2s_rx_ch); + return 1; +} + +static int mi2s_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate_val = 0; + + switch (mi2s_rx_sample_rate) { + case SAMPLING_RATE_96KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_192KHZ: + sample_rate_val = 2; + break; + case SAMPLING_RATE_48KHZ: + default: + sample_rate_val = 0; + break; + } + + ucontrol->value.integer.value[0] = sample_rate_val; + pr_debug("%s: sample_rate_val = %d\n", __func__, + sample_rate_val); + + return 0; +} + +static int mi2s_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 1: + mi2s_rx_sample_rate = SAMPLING_RATE_96KHZ; + break; + case 2: + mi2s_rx_sample_rate = SAMPLING_RATE_192KHZ; + break; + case 0: + default: + mi2s_rx_sample_rate = SAMPLING_RATE_48KHZ; + break; + } + pr_debug("%s: mi2s_rx_sample_rate = %d\n", __func__, + mi2s_rx_sample_rate); + return 0; +} + +static int msm_ter_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_ter_mi2s_tx_ch = %d\n", __func__, + msm_ter_mi2s_tx_ch); + ucontrol->value.integer.value[0] = msm_ter_mi2s_tx_ch - 1; + return 0; +} + +static int msm_ter_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_ter_mi2s_tx_ch = ucontrol->value.integer.value[0] + 1; + + pr_debug("%s: msm_ter_mi2s_tx_ch = %d\n", __func__, msm_ter_mi2s_tx_ch); + return 1; +} + +static int msm_vi_feed_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = (msm_vi_feed_tx_ch/2 - 1); + pr_debug("%s: msm_vi_feed_tx_ch = %ld\n", __func__, + ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_vi_feed_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_vi_feed_tx_ch = + roundup_pow_of_two(ucontrol->value.integer.value[0] + 2); + + pr_debug("%s: msm_vi_feed_tx_ch = %d\n", __func__, msm_vi_feed_tx_ch); + return 1; +} + +static const struct soc_enum msm_snd_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_bit_format_text), + rx_bit_format_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mi2s_ch_text), + mi2s_ch_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(loopback_mclk_text), + loopback_mclk_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(btsco_rate_text), + btsco_rate_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(proxy_rx_ch_text), + proxy_rx_ch_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(vi_feed_ch_text), + vi_feed_ch_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mi2s_rx_sample_rate_text), + mi2s_rx_sample_rate_text), +}; + +static const struct snd_kcontrol_new msm_snd_controls[] = { + SOC_ENUM_EXT("MI2S_RX Format", msm_snd_enum[0], + mi2s_rx_bit_format_get, mi2s_rx_bit_format_put), + SOC_ENUM_EXT("MI2S_TX Channels", msm_snd_enum[1], + msm_ter_mi2s_tx_ch_get, msm_ter_mi2s_tx_ch_put), + SOC_ENUM_EXT("MI2S_RX Channels", msm_snd_enum[1], + msm_pri_mi2s_rx_ch_get, msm_pri_mi2s_rx_ch_put), + SOC_ENUM_EXT("Loopback MCLK", msm_snd_enum[2], + loopback_mclk_get, loopback_mclk_put), + SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_snd_enum[3], + msm_btsco_rate_get, msm_btsco_rate_put), + SOC_ENUM_EXT("PROXY_RX Channels", msm_snd_enum[4], + msm_proxy_rx_ch_get, msm_proxy_rx_ch_put), + SOC_ENUM_EXT("VI_FEED_TX Channels", msm_snd_enum[5], + msm_vi_feed_tx_ch_get, msm_vi_feed_tx_ch_put), + SOC_ENUM_EXT("MI2S_RX SampleRate", msm_snd_enum[6], + mi2s_rx_sample_rate_get, mi2s_rx_sample_rate_put), +}; + +static int msm8952_enable_wsa_mclk(struct snd_soc_card *card, bool enable) +{ + int ret = 0; + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + + mutex_lock(&pdata->wsa_mclk_mutex); + if (enable) { + if (!atomic_read(&pdata->wsa_int_mclk0_rsc_ref)) { + wsa_ana_clk.enable = enable; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_PRIMARY_MI2S_RX, + &wsa_ana_clk); + if (ret < 0) { + pr_err("%s: failed to enable mclk %d\n", + __func__, ret); + goto done; + } + } + atomic_inc(&pdata->wsa_int_mclk0_rsc_ref); + } else { + if (!atomic_read(&pdata->wsa_int_mclk0_rsc_ref)) + goto done; + if (!atomic_dec_return(&pdata->wsa_int_mclk0_rsc_ref)) { + wsa_ana_clk.enable = enable; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_PRIMARY_MI2S_RX, + &wsa_ana_clk); + if (ret < 0) { + pr_err("%s: failed to disable mclk %d\n", + __func__, ret); + goto done; + } + } + } + +done: + mutex_unlock(&pdata->wsa_mclk_mutex); + return ret; +} + +static int msm_mi2s_snd_startup(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 *cpu_dai = rtd->cpu_dai; + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + int ret = 0, val = 0; + + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + + if (!q6core_is_adsp_ready()) { + pr_err("%s(): adsp not ready\n", __func__); + return -EINVAL; + } + + /* + * configure the slave select to + * invalid state for internal codec + */ + if (pdata->vaddr_gpio_mux_spkr_ctl) { + val = ioread32(pdata->vaddr_gpio_mux_spkr_ctl); + val = val | 0x00010000; + iowrite32(val, pdata->vaddr_gpio_mux_spkr_ctl); + } + + if (pdata->vaddr_gpio_mux_mic_ctl) { + val = ioread32(pdata->vaddr_gpio_mux_mic_ctl); + val = val | 0x00200000; + iowrite32(val, pdata->vaddr_gpio_mux_mic_ctl); + } + + ret = msm_mi2s_sclk_ctl(substream, true); + if (ret < 0) { + pr_err("%s: failed to enable sclk %d\n", + __func__, ret); + return ret; + } + if (card->aux_dev && substream->stream == + SNDRV_PCM_STREAM_PLAYBACK) { + ret = msm8952_enable_wsa_mclk(card, true); + if (ret < 0) { + pr_err("%s: failed to enable mclk for wsa %d\n", + __func__, ret); + return ret; + } + } + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + pr_err("%s: set fmt cpu dai failed; ret=%d\n", __func__, ret); + + return ret; +} + +static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream) +{ + int ret; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + + ret = msm_mi2s_sclk_ctl(substream, false); + if (ret < 0) + pr_err("%s:clock disable failed; ret=%d\n", __func__, + ret); + if (card->aux_dev && substream->stream == + SNDRV_PCM_STREAM_PLAYBACK) { + ret = msm8952_enable_wsa_mclk(card, false); + if (ret < 0) { + pr_err("%s: failed to disable mclk for wsa %d\n", + __func__, ret); + } + } +} + +static int msm_prim_auxpcm_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *dig_cdc = NULL; + struct snd_soc_card *card = rtd->card; + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + int ret = 0, val = 0; + + pr_debug("%s(): substream = %s\n", + __func__, substream->name); + + if (!q6core_is_adsp_ready()) { + pr_err("%s(): adsp not ready\n", __func__); + return -EINVAL; + } + + if (pdata->snd_card_val == INT_DIG_SND_CARD) + dig_cdc = snd_soc_rtdcom_lookup(rtd, "msm_digital_codec"); + else + dig_cdc = rtd->codec_dais[DIG_CDC]->component; + + /* mux config to route the AUX MI2S */ + if (pdata->vaddr_gpio_mux_mic_ctl) { + val = ioread32(pdata->vaddr_gpio_mux_mic_ctl); + val = val | 0x2; + iowrite32(val, pdata->vaddr_gpio_mux_mic_ctl); + } + if (pdata->vaddr_gpio_mux_pcm_ctl) { + val = ioread32(pdata->vaddr_gpio_mux_pcm_ctl); + val = val | 0x1; + iowrite32(val, pdata->vaddr_gpio_mux_pcm_ctl); + } + msm8952_enable_dig_cdc_clk(dig_cdc, 1, true); + atomic_inc(&auxpcm_mi2s_clk_ref); + + /* enable the gpio's used for the external AUXPCM interface */ + if (pdata->mi2s_gpio_p[QUAT_MI2S]) { + ret = msm_cdc_pinctrl_select_active_state( + pdata->mi2s_gpio_p[QUAT_MI2S]); + if (ret < 0) + pr_err("%s(): configure gpios failed = %s\n", + __func__, "quat_i2s"); + } + return ret; +} + +static void msm_prim_auxpcm_shutdown(struct snd_pcm_substream *substream) +{ + int ret; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct snd_soc_component *dig_cdc = NULL; + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + + pr_debug("%s(): substream = %s\n", + __func__, substream->name); + + if (pdata->snd_card_val == INT_DIG_SND_CARD) + dig_cdc = snd_soc_rtdcom_lookup(rtd, "msm_digital_codec"); + else + dig_cdc = rtd->codec_dais[DIG_CDC]->component; + + if (atomic_read(&pdata->int_mclk0_rsc_ref) > 0) { + atomic_dec(&pdata->int_mclk0_rsc_ref); + pr_debug("%s: decrementing mclk_res_ref %d\n", + __func__, atomic_read(&pdata->int_mclk0_rsc_ref)); + } + if (atomic_read(&auxpcm_mi2s_clk_ref) > 0) + atomic_dec(&auxpcm_mi2s_clk_ref); + if ((atomic_read(&auxpcm_mi2s_clk_ref) == 0) && + (atomic_read(&pdata->int_mclk0_rsc_ref) == 0)) { + msm8952_enable_dig_cdc_clk(dig_cdc, 0, true); + } + if (pdata->mi2s_gpio_p[QUAT_MI2S]) { + ret = msm_cdc_pinctrl_select_sleep_state( + pdata->mi2s_gpio_p[QUAT_MI2S]); + if (ret < 0) + pr_err("%s(): configure gpios failed = %s\n", + __func__, "quat_i2s"); + } +} + +static int msm_sec_mi2s_snd_startup(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 *cpu_dai = rtd->cpu_dai; + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + int ret = 0, val = 0; + + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + pr_info("%s: Secondary Mi2s does not support capture\n", + __func__); + return 0; + } + + if (!q6core_is_adsp_ready()) { + pr_err("%s(): adsp not ready\n", __func__); + return -EINVAL; + } + + if ((pdata->ext_pa & SEC_MI2S_ID) == SEC_MI2S_ID) { + if (pdata->vaddr_gpio_mux_spkr_ctl) { + val = ioread32(pdata->vaddr_gpio_mux_spkr_ctl); + val = val | 0x0004835c; + iowrite32(val, pdata->vaddr_gpio_mux_spkr_ctl); + } + ret = msm_mi2s_sclk_ctl(substream, true); + if (ret < 0) { + pr_err("failed to enable sclk\n"); + return ret; + } + pr_debug("%s(): SEC I2S gpios turned on = %s\n", __func__, + "sec_i2s"); + if (pdata->mi2s_gpio_p[SEC_MI2S]) { + ret = msm_cdc_pinctrl_select_active_state( + pdata->mi2s_gpio_p[SEC_MI2S]); + if (ret < 0) { + pr_err("%s: gpio set cannot be activated %sd", + __func__, "sec_i2s"); + goto err; + } + } + } else { + pr_err("%s: error codec type\n", __func__); + } + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) { + pr_err("%s: set fmt cpu dai failed\n", __func__); + if (pdata->mi2s_gpio_p[SEC_MI2S]) { + ret = msm_cdc_pinctrl_select_sleep_state( + pdata->mi2s_gpio_p[SEC_MI2S]); + if (ret < 0) { + pr_err("%s: gpio de-activate error %s", + __func__, "sec_i2s"); + goto err; + } + } + } + return ret; +err: + ret = msm_mi2s_sclk_ctl(substream, false); + if (ret < 0) + pr_err("failed to disable sclk\n"); + return ret; +} + +static void msm_sec_mi2s_snd_shutdown(struct snd_pcm_substream *substream) +{ + int ret; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + if ((pdata->ext_pa & SEC_MI2S_ID) == SEC_MI2S_ID) { + if (pdata->mi2s_gpio_p[SEC_MI2S]) { + ret = msm_cdc_pinctrl_select_sleep_state( + pdata->mi2s_gpio_p[SEC_MI2S]); + if (ret < 0) { + pr_err("%s: gpio set cannot be de-activated: %sd", + __func__, "sec_i2s"); + return; + } + } + ret = msm_mi2s_sclk_ctl(substream, false); + if (ret < 0) + pr_err("%s:clock disable failed\n", __func__); + } +} + +static int msm_quat_mi2s_snd_startup(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 *cpu_dai = rtd->cpu_dai; + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + int ret = 0, val = 0; + + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + + if (!q6core_is_adsp_ready()) { + pr_err("%s(): adsp not ready\n", __func__); + return -EINVAL; + } + + if (pdata->vaddr_gpio_mux_mic_ctl) { + val = ioread32(pdata->vaddr_gpio_mux_mic_ctl); + val = val | 0x02020002; + iowrite32(val, pdata->vaddr_gpio_mux_mic_ctl); + } + ret = msm_mi2s_sclk_ctl(substream, true); + if (ret < 0) { + pr_err("failed to enable sclk\n"); + return ret; + } + if (pdata->mi2s_gpio_p[QUAT_MI2S]) { + ret = msm_cdc_pinctrl_select_active_state( + pdata->mi2s_gpio_p[QUAT_MI2S]); + if (ret < 0) { + pr_err("failed to enable codec gpios\n"); + goto err; + } + } + if (atomic_inc_return(&quat_mi2s_clk_ref) == 1) { + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + pr_err("%s: set fmt cpu dai failed\n", __func__); + } + return ret; +err: + ret = msm_mi2s_sclk_ctl(substream, false); + if (ret < 0) + pr_err("failed to disable sclk\n"); + return ret; +} + +static void msm_quat_mi2s_snd_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + int ret = 0; + + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + ret = msm_mi2s_sclk_ctl(substream, false); + if (ret < 0) + pr_err("%s:clock disable failed\n", __func__); + if (atomic_read(&quat_mi2s_clk_ref) > 0) + atomic_dec(&quat_mi2s_clk_ref); + if (pdata->mi2s_gpio_p[QUAT_MI2S]) { + ret = msm_cdc_pinctrl_select_sleep_state( + pdata->mi2s_gpio_p[QUAT_MI2S]); + if (ret < 0) { + pr_err("%s: gpio set cannot be de-activated %sd", + __func__, "quat_i2s"); + return; + } + } +} + +static int msm_quin_mi2s_snd_startup(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 *cpu_dai = rtd->cpu_dai; + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + int ret = 0, val = 0; + + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + + if (!q6core_is_adsp_ready()) { + pr_err("%s(): adsp not ready\n", __func__); + return -EINVAL; + } + + if (pdata->vaddr_gpio_mux_quin_ctl) { + val = ioread32(pdata->vaddr_gpio_mux_quin_ctl); + val = val | 0x00000001; + iowrite32(val, pdata->vaddr_gpio_mux_quin_ctl); + } else { + return -EINVAL; + } + ret = msm_mi2s_sclk_ctl(substream, true); + if (ret < 0) { + pr_err("failed to enable sclk\n"); + return ret; + } + if (pdata->mi2s_gpio_p[QUIN_MI2S]) { + ret = msm_cdc_pinctrl_select_active_state( + pdata->mi2s_gpio_p[QUIN_MI2S]); + if (ret < 0) { + pr_err("failed to enable codec gpios\n"); + goto err; + } + } + if (atomic_inc_return(&quin_mi2s_clk_ref) == 1) { + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + pr_err("%s: set fmt cpu dai failed\n", __func__); + } + return ret; +err: + ret = msm_mi2s_sclk_ctl(substream, false); + if (ret < 0) + pr_err("failed to disable sclk\n"); + return ret; +} + +static void msm_quin_mi2s_snd_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + int ret = 0; + + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + ret = msm_mi2s_sclk_ctl(substream, false); + if (ret < 0) + pr_err("%s:clock disable failed\n", __func__); + if (atomic_read(&quin_mi2s_clk_ref) > 0) + atomic_dec(&quin_mi2s_clk_ref); + if (pdata->mi2s_gpio_p[QUIN_MI2S]) { + ret = msm_cdc_pinctrl_select_sleep_state( + pdata->mi2s_gpio_p[QUIN_MI2S]); + if (ret < 0) { + pr_err("%s: gpio set cannot be de-activated %sd", + __func__, "quin_i2s"); + return; + } + } +} + +static void *def_msm8952_wcd_mbhc_cal(void) +{ + void *msm8952_wcd_cal; + struct wcd_mbhc_btn_detect_cfg *btn_cfg; + u16 *btn_low, *btn_high; + + msm8952_wcd_cal = kzalloc(WCD_MBHC_CAL_SIZE(WCD_MBHC_DEF_BUTTONS, + WCD_MBHC_DEF_RLOADS), GFP_KERNEL); + if (!msm8952_wcd_cal) + return NULL; + +#define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(msm8952_wcd_cal)->X) = (Y)) + S(v_hs_max, 1500); +#undef S +#define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(msm8952_wcd_cal)->X) = (Y)) + S(num_btn, WCD_MBHC_DEF_BUTTONS); +#undef S + + + btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(msm8952_wcd_cal); + btn_low = btn_cfg->_v_btn_low; + btn_high = ((void *)&btn_cfg->_v_btn_low) + + (sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn); + + /* + * In SW we are maintaining two sets of threshold register + * one for current source and another for Micbias. + * all btn_low corresponds to threshold for current source + * all bt_high corresponds to threshold for Micbias + * Below thresholds are based on following resistances + * 0-70 == Button 0 + * 110-180 == Button 1 + * 210-290 == Button 2 + * 360-680 == Button 3 + */ + btn_low[0] = 75; + btn_high[0] = 75; + btn_low[1] = 150; + btn_high[1] = 150; + btn_low[2] = 225; + btn_high[2] = 225; + btn_low[3] = 450; + btn_high[3] = 450; + btn_low[4] = 500; + btn_high[4] = 500; + + return msm8952_wcd_cal; +} + +static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *dig_cdc = + snd_soc_rtdcom_lookup(rtd, "msm_digital_codec"); + struct snd_soc_component *ana_cdc = + snd_soc_rtdcom_lookup(rtd, "pmic_analog_codec"); + struct snd_soc_dapm_context *dapm; + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(rtd->card); + struct snd_card *card; + int ret = -ENOMEM; + + if (!dig_cdc || !ana_cdc) { + pr_err("%s: component is NULL\n", __func__); + return -EINVAL; + } + dapm = snd_soc_component_get_dapm(ana_cdc); + ret = snd_soc_add_component_controls(ana_cdc, msm_snd_controls, + ARRAY_SIZE(msm_snd_controls)); + if (ret < 0) { + pr_err("%s: add_codec_controls failed: %d\n", + __func__, ret); + return ret; + } + + snd_soc_dapm_new_controls(dapm, msm8952_dapm_widgets, + ARRAY_SIZE(msm8952_dapm_widgets)); + + snd_soc_dapm_ignore_suspend(dapm, "Handset Mic"); + snd_soc_dapm_ignore_suspend(dapm, "Headset Mic"); + snd_soc_dapm_ignore_suspend(dapm, "Secondary Mic"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2"); + + snd_soc_dapm_ignore_suspend(dapm, "EAR"); + snd_soc_dapm_ignore_suspend(dapm, "HEADPHONE"); + snd_soc_dapm_ignore_suspend(dapm, "SPK_OUT"); + snd_soc_dapm_ignore_suspend(dapm, "AMIC1"); + snd_soc_dapm_ignore_suspend(dapm, "AMIC2"); + snd_soc_dapm_ignore_suspend(dapm, "AMIC3"); + snd_soc_dapm_sync(dapm); + + dapm = snd_soc_component_get_dapm(dig_cdc); + snd_soc_dapm_ignore_suspend(dapm, "DMIC1"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC2"); + snd_soc_dapm_ignore_suspend(dapm, "WSA_SPK OUT"); + snd_soc_dapm_ignore_suspend(dapm, "LINEOUT"); + + snd_soc_dapm_sync(dapm); + + msm_anlg_cdc_spk_ext_pa_cb(enable_spk_ext_pa, ana_cdc); + msm_dig_cdc_hph_comp_cb(config_hph_compander_gpio, dig_cdc); + + mbhc_cfg.calibration = def_msm8952_wcd_mbhc_cal(); + if (mbhc_cfg.calibration) { + ret = msm_anlg_cdc_hs_detect(ana_cdc, &mbhc_cfg); + if (ret) { + kfree(mbhc_cfg.calibration); + return ret; + } + } + card = rtd->card->snd_card; + if (!codec_root) + codec_root = snd_info_create_subdir(card->module, "codecs", + card->proc_root); + if (!codec_root) { + pr_debug("%s: Cannot create codecs module entry\n", __func__); + goto done; + } + pdata->codec_root = codec_root; + msm_dig_codec_info_create_codec_entry(codec_root, dig_cdc); + msm_anlg_codec_info_create_codec_entry(codec_root, ana_cdc); +done: + return 0; +} + +static int msm_dig_audrx_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *dig_cdc = + snd_soc_rtdcom_lookup(rtd, "msm_digital_codec"); + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(dig_cdc); + struct snd_card *card = NULL; + + snd_soc_add_component_controls(dig_cdc, msm_snd_controls, + ARRAY_SIZE(msm_snd_controls)); + snd_soc_dapm_new_controls(dapm, msm8952_dig_dapm_widgets, + ARRAY_SIZE(msm8952_dig_dapm_widgets)); + + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2"); + + snd_soc_dapm_ignore_suspend(dapm, "DMIC1"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC2"); + + snd_soc_dapm_sync(dapm); + + card = rtd->card->snd_card; + if (!codec_root) { + codec_root = snd_info_create_subdir(card->module, "codecs", + card->proc_root); + pr_debug("%s: Cannot create codecs module entry\n", __func__); + goto done; + } + pdata->codec_root = codec_root; + msm_dig_codec_info_create_codec_entry(codec_root, dig_cdc); +done: + return 0; +} + +static struct snd_soc_ops msm8952_quat_mi2s_be_ops = { + .startup = msm_quat_mi2s_snd_startup, + .hw_params = msm_mi2s_snd_hw_params, + .shutdown = msm_quat_mi2s_snd_shutdown, +}; + +static struct snd_soc_ops msm8952_quin_mi2s_be_ops = { + .startup = msm_quin_mi2s_snd_startup, + .hw_params = msm_mi2s_snd_hw_params, + .shutdown = msm_quin_mi2s_snd_shutdown, +}; + +static struct snd_soc_ops msm8952_sec_mi2s_be_ops = { + .startup = msm_sec_mi2s_snd_startup, + .hw_params = msm_mi2s_snd_hw_params, + .shutdown = msm_sec_mi2s_snd_shutdown, +}; + +static struct snd_soc_ops msm8952_mi2s_be_ops = { + .startup = msm_mi2s_snd_startup, + .hw_params = msm_mi2s_snd_hw_params, + .shutdown = msm_mi2s_snd_shutdown, +}; + +static struct snd_soc_ops msm_pri_auxpcm_be_ops = { + .startup = msm_prim_auxpcm_startup, + .shutdown = msm_prim_auxpcm_shutdown, +}; + +struct snd_soc_dai_link_component dlc_rx1[] = { + { + .of_node = NULL, + .dai_name = "msm_dig_cdc_dai_rx1", + }, + { + .of_node = NULL, + .dai_name = "msm_anlg_cdc_i2s_rx1", + }, +}; + +struct snd_soc_dai_link_component dlc_tx1[] = { + { + .of_node = NULL, + .dai_name = "msm_dig_cdc_dai_tx1", + }, + { + .of_node = NULL, + .dai_name = "msm_anlg_cdc_i2s_tx1", + }, +}; + +struct snd_soc_dai_link_component dlc_vifeed[] = { + { + .of_node = NULL, + .dai_name = "msm_dig_cdc_dai_vifeed", + }, + { + .of_node = NULL, + .dai_name = "msm_anlg_vifeedback", + }, +}; + +/* Digital audio interface glue - connects codec <---> CPU */ +static struct snd_soc_dai_link msm8952_dai[] = { + /* FrontEnd DAI Links */ + {/* hw:x,0 */ + .name = "MSM8952 Media1", + .stream_name = "MultiMedia1", + .cpu_dai_name = "MultiMedia1", + .platform_name = "msm-pcm-dsp.0", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA1 + }, + {/* hw:x,1 */ + .name = "MSM8952 Media2", + .stream_name = "MultiMedia2", + .cpu_dai_name = "MultiMedia2", + .platform_name = "msm-pcm-dsp.0", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA2, + }, + {/* hw:x,2 */ + .name = "Circuit-Switch Voice", + .stream_name = "CS-Voice", + .cpu_dai_name = "VoiceMMode1", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_CS_VOICE, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + {/* hw:x,3 */ + .name = "MSM VoIP", + .stream_name = "VoIP", + .cpu_dai_name = "VoIP", + .platform_name = "msm-voip-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_VOIP, + }, + {/* hw:x,4 */ + .name = "MSM8X16 ULL", + .stream_name = "ULL", + .cpu_dai_name = "MultiMedia3", + .platform_name = "msm-pcm-dsp.2", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA3, + }, + /* Hostless PCM purpose */ + {/* hw:x,5 */ + .name = "Primary MI2S_RX Hostless", + .stream_name = "Primary MI2S_RX Hostless", + .cpu_dai_name = "PRI_MI2S_RX_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dailink has playback support */ + .ignore_pmdown_time = 1, + /* This dainlink has MI2S support */ + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + {/* hw:x,6 */ + .name = "INT_FM Hostless", + .stream_name = "INT_FM Hostless", + .cpu_dai_name = "INT_FM_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + {/* hw:x,7 */ + .name = "MSM AFE-PCM RX", + .stream_name = "AFE-PROXY RX", + .cpu_dai_name = "msm-dai-q6-dev.241", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .platform_name = "msm-pcm-afe", + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + }, + {/* hw:x,8 */ + .name = "MSM AFE-PCM TX", + .stream_name = "AFE-PROXY TX", + .cpu_dai_name = "msm-dai-q6-dev.240", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .platform_name = "msm-pcm-afe", + .ignore_suspend = 1, + }, + {/* hw:x,9 */ + .name = "MSM8952 Compress1", + .stream_name = "Compress1", + .cpu_dai_name = "MultiMedia4", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_HW_PARAMS, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA4, + }, + {/* hw:x,10 */ + .name = "AUXPCM Hostless", + .stream_name = "AUXPCM Hostless", + .cpu_dai_name = "AUXPCM_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + {/* hw:x,11 */ + .name = "Tertiary MI2S_TX Hostless", + .stream_name = "Tertiary MI2S_TX Hostless", + .cpu_dai_name = "TERT_MI2S_TX_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, /* dai link has playback support */ + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + {/* hw:x,12 */ + .name = "MSM8x16 LowLatency", + .stream_name = "MultiMedia5", + .cpu_dai_name = "MultiMedia5", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE | + ASYNC_DPCM_SND_SOC_HW_PARAMS, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA5, + }, + {/* hw:x,13 */ + .name = "Voice2", + .stream_name = "Voice2", + .cpu_dai_name = "VoiceMMode1", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_VOICE2, + }, + {/* hw:x,14 */ + .name = "MSM8x16 Media9", + .stream_name = "MultiMedia9", + .cpu_dai_name = "MultiMedia9", + .platform_name = "msm-pcm-dsp.0", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* This dailink has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA9, + }, + { /* hw:x,15 */ + .name = "VoLTE", + .stream_name = "VoLTE", + .cpu_dai_name = "VoiceMMode1", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_VOLTE, + }, + { /* hw:x,16 */ + .name = "VoWLAN", + .stream_name = "VoWLAN", + .cpu_dai_name = "VoiceMMode1", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_VOWLAN, + }, + {/* hw:x,17 */ + .name = "INT_HFP_BT Hostless", + .stream_name = "INT_HFP_BT Hostless", + .cpu_dai_name = "INT_HFP_BT_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + {/* hw:x,18 */ + .name = "MSM8916 HFP", + .stream_name = "MultiMedia6", + .cpu_dai_name = "MultiMedia6", + .platform_name = "msm-pcm-loopback", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA6, + }, + /* LSM FE */ + {/* hw:x,19 */ + .name = "Listen 1 Audio Service", + .stream_name = "Listen 1 Audio Service", + .cpu_dai_name = "LSM1", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_LSM1, + }, + {/* hw:x,20 */ + .name = "Listen 2 Audio Service", + .stream_name = "Listen 2 Audio Service", + .cpu_dai_name = "LSM2", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_LSM2, + }, + {/* hw:x,21 */ + .name = "Listen 3 Audio Service", + .stream_name = "Listen 3 Audio Service", + .cpu_dai_name = "LSM3", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_LSM3, + }, + {/* hw:x,22 */ + .name = "Listen 4 Audio Service", + .stream_name = "Listen 4 Audio Service", + .cpu_dai_name = "LSM4", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_LSM4, + }, + {/* hw:x,23 */ + .name = "Listen 5 Audio Service", + .stream_name = "Listen 5 Audio Service", + .cpu_dai_name = "LSM5", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_LSM5, + }, + { /* hw:x,24 */ + .name = "MSM8X16 Compress2", + .stream_name = "Compress2", + .cpu_dai_name = "MultiMedia7", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA7, + }, + { /* hw:x,25 */ + .name = "Quaternary MI2S_RX Hostless", + .stream_name = "Quaternary MI2S_RX Hostless", + .cpu_dai_name = "QUAT_MI2S_RX_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + {/* hw:x,26 */ + .name = LPASS_BE_SENARY_MI2S_TX, + .stream_name = "Senary_mi2s Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.6", + .platform_name = "msm-pcm-hostless", + .codecs = dlc_vifeed, + .num_codecs = CODECS_MAX, + .id = MSM_BACKEND_DAI_SENARY_MI2S_TX, + .be_hw_params_fixup = msm_senary_tx_be_hw_params_fixup, + .ops = &msm8952_mi2s_be_ops, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .dpcm_capture = 1, + .ignore_pmdown_time = 1, + }, + {/* hw:x,27 */ + .name = "MSM8X16 Compress3", + .stream_name = "Compress3", + .cpu_dai_name = "MultiMedia10", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dai link has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA10, + }, + {/* hw:x,28 */ + .name = "MSM8X16 Compress4", + .stream_name = "Compress4", + .cpu_dai_name = "MultiMedia11", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dai link has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA11, + }, + {/* hw:x,29 */ + .name = "MSM8X16 Compress5", + .stream_name = "Compress5", + .cpu_dai_name = "MultiMedia12", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dai link has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA12, + }, + {/* hw:x,30 */ + .name = "MSM8X16 Compress6", + .stream_name = "Compress6", + .cpu_dai_name = "MultiMedia13", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dai link has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA13, + }, + {/* hw:x,31 */ + .name = "MSM8X16 Compress7", + .stream_name = "Compress7", + .cpu_dai_name = "MultiMedia14", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dai link has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA14, + }, + {/* hw:x,32 */ + .name = "MSM8X16 Compress8", + .stream_name = "Compress8", + .cpu_dai_name = "MultiMedia15", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dai link has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA15, + }, + { /*hw:x,33 */ + .name = "MSM8X16 Compress9", + .stream_name = "Compress9", + .cpu_dai_name = "MultiMedia16", + .platform_name = "msm-pcm-dsp-noirq", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /*this dai link has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA16, + }, + {/* hw:x,34 */ + .name = "VoiceMMode1", + .stream_name = "VoiceMMode1", + .cpu_dai_name = "VoiceMMode1", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_VOICEMMODE1, + }, + {/* hw:x,35 */ + .name = "VoiceMMode2", + .stream_name = "VoiceMMode2", + .cpu_dai_name = "VoiceMMode2", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_VOICEMMODE2, + }, + {/* hw:x,36 */ + .name = "MSM8916 HFP Loopback2", + .stream_name = "MultiMedia8", + .cpu_dai_name = "MultiMedia8", + .platform_name = "msm-pcm-loopback", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA8, + }, + {/* hw:x,37 */ + .name = "QCHAT", + .stream_name = "QCHAT", + .cpu_dai_name = "QCHAT", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + /* this dai link has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_QCHAT, + }, + {/* hw:x,38 */ + .name = "MSM8X16 Compress10", + .stream_name = "Compress10", + .cpu_dai_name = "MultiMedia17", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA17, + }, + {/* hw:x,39 */ + .name = "MSM8X16 Compress11", + .stream_name = "Compress11", + .cpu_dai_name = "MultiMedia18", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA18, + }, + {/* hw:x,40 */ + .name = "MSM8X16 Compress12", + .stream_name = "Compress12", + .cpu_dai_name = "MultiMedia19", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA19, + }, + { + .name = LPASS_BE_SEC_MI2S_RX, + .stream_name = "Secondary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.1", + .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_SECONDARY_MI2S_RX, + .be_hw_params_fixup = msm_mi2s_rx_be_hw_params_fixup, + .ops = &msm8952_sec_mi2s_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_QUAT_MI2S_TX, + .stream_name = "Quaternary MI2S Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.3", + .platform_name = "msm-pcm-routing", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm8952_quat_mi2s_be_ops, + .ignore_suspend = 1, + }, + /* Primary AUX PCM Backend DAI Links */ + { + .name = LPASS_BE_AUXPCM_RX, + .stream_name = "AUX PCM Playback", + .cpu_dai_name = "msm-dai-q6-auxpcm.1", + .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_AUXPCM_RX, + .be_hw_params_fixup = msm_auxpcm_be_params_fixup, + .ops = &msm_pri_auxpcm_be_ops, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_AUXPCM_TX, + .stream_name = "AUX PCM Capture", + .cpu_dai_name = "msm-dai-q6-auxpcm.1", + .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_AUXPCM_TX, + .be_hw_params_fixup = msm_auxpcm_be_params_fixup, + .ops = &msm_pri_auxpcm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_INT_BT_SCO_RX, + .stream_name = "Internal BT-SCO Playback", + .cpu_dai_name = "msm-dai-q6-dev.12288", + .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_INT_BT_SCO_RX, + .be_hw_params_fixup = msm_btsco_be_hw_params_fixup, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_INT_BT_SCO_TX, + .stream_name = "Internal BT-SCO Capture", + .cpu_dai_name = "msm-dai-q6-dev.12289", + .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_INT_BT_SCO_TX, + .be_hw_params_fixup = msm_btsco_be_hw_params_fixup, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_INT_FM_RX, + .stream_name = "Internal FM Playback", + .cpu_dai_name = "msm-dai-q6-dev.12292", + .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_INT_FM_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_INT_FM_TX, + .stream_name = "Internal FM Capture", + .cpu_dai_name = "msm-dai-q6-dev.12293", + .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_INT_FM_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_AFE_PCM_RX, + .stream_name = "AFE Playback", + .cpu_dai_name = "msm-dai-q6-dev.224", + .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_AFE_PCM_RX, + .be_hw_params_fixup = msm_proxy_rx_be_hw_params_fixup, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_AFE_PCM_TX, + .stream_name = "AFE Capture", + .cpu_dai_name = "msm-dai-q6-dev.225", + .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_AFE_PCM_TX, + .be_hw_params_fixup = msm_proxy_tx_be_hw_params_fixup, + .ignore_suspend = 1, + }, + /* 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, + }, + /* 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, + }, + + { + .name = LPASS_BE_QUIN_MI2S_TX, + .stream_name = "Quinary MI2S Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.4", + .platform_name = "msm-pcm-routing", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_QUINARY_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm8952_quin_mi2s_be_ops, + .ignore_suspend = 1, + }, +}; +static struct snd_soc_dai_link msm8952_hdmi_dba_dai_link[] = { + { + .name = LPASS_BE_QUIN_MI2S_RX, + .stream_name = "Quinary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.4", + .platform_name = "msm-pcm-routing", + .codec_dai_name = "msm_hdmi_audio_codec_rx_dai", + .codec_name = "msm-ext-disp-audio-codec-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_QUINARY_MI2S_RX, + .be_hw_params_fixup = msm_mi2s_rx_be_hw_params_fixup, + .ops = &msm8952_quin_mi2s_be_ops, + .ignore_pmdown_time = 1, /* dai link has playback support */ + .ignore_suspend = 1, + }, +}; +static struct snd_soc_dai_link msm8952_quin_dai_link[] = { + { + .name = LPASS_BE_QUIN_MI2S_RX, + .stream_name = "Quinary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.4", + .platform_name = "msm-pcm-routing", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_QUINARY_MI2S_RX, + .be_hw_params_fixup = msm_mi2s_rx_be_hw_params_fixup, + .ops = &msm8952_quin_mi2s_be_ops, + .ignore_pmdown_time = 1, /* dai link has playback support */ + .ignore_suspend = 1, + }, +}; + +static struct snd_soc_dai_link msm8952_split_a2dp_dai_link[] = { + { + .name = LPASS_BE_INT_BT_A2DP_RX, + .stream_name = "Internal BT-A2DP Playback", + .cpu_dai_name = "msm-dai-q6-dev.12290", + .platform_name = "msm-pcm-routing", + .codec_dai_name = "msm-stub-rx", + .codec_name = "msm-stub-codec.1", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_INT_BT_A2DP_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, /* dai link has playback support */ + .ignore_suspend = 1, + }, +}; + +static struct snd_soc_dai_link msm_int_be_dai[] = { + /* Backend I2S DAI Links */ + { + .name = LPASS_BE_PRI_MI2S_RX, + .stream_name = "Primary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.0", + .platform_name = "msm-pcm-routing", + .codecs = dlc_rx1, + .num_codecs = CODECS_MAX, + .no_pcm = 1, + .dpcm_playback = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE | + ASYNC_DPCM_SND_SOC_HW_PARAMS, + .id = MSM_BACKEND_DAI_PRI_MI2S_RX, + .init = &msm_audrx_init, + .be_hw_params_fixup = msm_mi2s_rx_be_hw_params_fixup, + .ops = &msm8952_mi2s_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_TERT_MI2S_TX, + .stream_name = "Tertiary MI2S Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.2", + .platform_name = "msm-pcm-routing", + .codecs = dlc_tx1, + .num_codecs = CODECS_MAX, + .no_pcm = 1, + .dpcm_capture = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE | + ASYNC_DPCM_SND_SOC_HW_PARAMS, + .id = MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + .be_hw_params_fixup = msm_tx_be_hw_params_fixup, + .ops = &msm8952_mi2s_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_QUAT_MI2S_RX, + .stream_name = "Quaternary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.3", + .platform_name = "msm-pcm-routing", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + .be_hw_params_fixup = msm_mi2s_rx_be_hw_params_fixup, + .ops = &msm8952_quat_mi2s_be_ops, + .ignore_pmdown_time = 1, /* dai link has playback support */ + .ignore_suspend = 1, + }, +}; + +static struct snd_soc_dai_link msm_int_dig_be_dai[] = { + /* DIG Codec Backend DAI Links */ + { + .name = LPASS_BE_PRI_MI2S_RX, + .stream_name = "Primary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.0", + .platform_name = "msm-pcm-routing", + .codec_dai_name = "msm_dig_cdc_dai_rx1", + .no_pcm = 1, + .dpcm_playback = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE | + ASYNC_DPCM_SND_SOC_HW_PARAMS, + .id = MSM_BACKEND_DAI_PRI_MI2S_RX, + .init = &msm_dig_audrx_init, + .be_hw_params_fixup = msm_mi2s_rx_be_hw_params_fixup, + .ops = &msm8952_mi2s_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_TERT_MI2S_TX, + .stream_name = "Tertiary MI2S Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.2", + .platform_name = "msm-pcm-routing", + .codec_dai_name = "msm_dig_cdc_dai_tx1", + .no_pcm = 1, + .dpcm_capture = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE | + ASYNC_DPCM_SND_SOC_HW_PARAMS, + .id = MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + .be_hw_params_fixup = msm_tx_be_hw_params_fixup, + .ops = &msm8952_mi2s_be_ops, + .ignore_suspend = 1, + }, +}; + +static struct snd_soc_dai_link msm_tfa98xx_dig_be_dai_link[] = { + { + .name = LPASS_BE_QUAT_MI2S_RX, + .stream_name = "Quaternary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.3", + .platform_name = "msm-pcm-routing", + .codec_dai_name = "tfa98xx-aif-2-34", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .dpcm_playback = 1, + .no_pcm = 1, + .id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + .be_hw_params_fixup = msm_mi2s_rx_be_hw_params_fixup, + .ops = &msm8952_quat_mi2s_be_ops, + .ignore_pmdown_time = 1, /* dai link has playback support */ + .ignore_suspend = 1, + }, +}; + +static struct snd_soc_dai_link msm8952_dai_links[ +ARRAY_SIZE(msm8952_dai) + +ARRAY_SIZE(msm_int_be_dai) + +ARRAY_SIZE(msm8952_hdmi_dba_dai_link) + +ARRAY_SIZE(msm8952_split_a2dp_dai_link) + +ARRAY_SIZE(msm_tfa98xx_dig_be_dai_link)]; + +static int msm8952_wsa881x_init(struct snd_soc_component *component) +{ + return 0; +} + +static struct snd_soc_aux_dev msm8952_aux_dev[] = { + { + .name = "wsa881x.0", + .codec_name = NULL, + .init = msm8952_wsa881x_init, + }, + { + .name = "wsa881x.0", + .codec_name = NULL, + .init = msm8952_wsa881x_init, + }, +}; + +static struct snd_soc_codec_conf msm8952_codec_conf[] = { + { + .dev_name = NULL, + .name_prefix = NULL, + }, + { + .dev_name = NULL, + .name_prefix = NULL, + }, +}; +static struct snd_soc_card bear_card = { + /* snd_soc_card_msm8952 */ + .name = "msm8952-snd-card", + .dai_link = msm8952_dai, + .num_links = ARRAY_SIZE(msm8952_dai), +}; + +void msm8952_disable_mclk(struct work_struct *work) +{ + struct msm_asoc_mach_data *pdata = NULL; + struct delayed_work *dwork; + int ret = 0; + + dwork = to_delayed_work(work); + pdata = container_of(dwork, struct msm_asoc_mach_data, + disable_int_mclk0_work); + mutex_lock(&pdata->cdc_int_mclk0_mutex); + pr_debug("%s: int_mclk0_enabled %d int_mclk0_rsc_ref %d\n", __func__, + atomic_read(&pdata->int_mclk0_enabled), + atomic_read(&pdata->int_mclk0_rsc_ref)); + + if (atomic_read(&pdata->int_mclk0_enabled) == true + && atomic_read(&pdata->int_mclk0_rsc_ref) == 0) { + pr_debug("Disable the mclk\n"); + pdata->digital_cdc_core_clk.enable = 0; + pdata->digital_cdc_core_clk.clk_freq_in_hz = + DEFAULT_MCLK_RATE; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_PRIMARY_MI2S_RX, + &pdata->digital_cdc_core_clk); + if (ret < 0) + pr_err("%s failed to disable the CCLK\n", __func__); + atomic_set(&pdata->int_mclk0_enabled, false); + } + mutex_unlock(&pdata->cdc_int_mclk0_mutex); +} + +static void msm8952_dt_parse_cap_info(struct platform_device *pdev, + struct msm_asoc_mach_data *pdata) +{ + const char *ext1_cap = "qcom,msm-micbias1-ext-cap"; + const char *ext2_cap = "qcom,msm-micbias2-ext-cap"; + + pdata->micbias1_cap_mode = + (of_property_read_bool(pdev->dev.of_node, ext1_cap) ? + MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP); + + pdata->micbias2_cap_mode = + (of_property_read_bool(pdev->dev.of_node, ext2_cap) ? + MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP); +} + +static int msm8952_populate_dai_link_component_of_node( + struct msm_asoc_mach_data *pdata, + struct snd_soc_card *card) +{ + int i, index, ret = 0; + struct device *cdev = card->dev; + struct snd_soc_dai_link *dai_link = card->dai_link; + struct device_node *phandle; + + 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].platform_of_node && dai_link[i].cpu_of_node) + continue; + + /* populate platform_of_node for snd card dai links */ + if (dai_link[i].platform_name && + !dai_link[i].platform_of_node) { + index = of_property_match_string(cdev->of_node, + "asoc-platform-names", + dai_link[i].platform_name); + if (index < 0) { + pr_err("%s: No match found for platform name: %s\n", + __func__, dai_link[i].platform_name); + ret = index; + goto cpu_dai; + } + phandle = of_parse_phandle(cdev->of_node, + "asoc-platform", + index); + if (!phandle) { + pr_err("%s: retrieving phandle for platform %s, index %d failed\n", + __func__, dai_link[i].platform_name, + index); + ret = -ENODEV; + goto err; + } + dai_link[i].platform_of_node = phandle; + dai_link[i].platform_name = NULL; + } +cpu_dai: + /* populate cpu_of_node for snd card dai links */ + if (dai_link[i].cpu_dai_name && !dai_link[i].cpu_of_node) { + index = of_property_match_string(cdev->of_node, + "asoc-cpu-names", + dai_link[i].cpu_dai_name); + if (index < 0) + goto codec_dai; + phandle = of_parse_phandle(cdev->of_node, "asoc-cpu", + index); + if (!phandle) { + pr_err("%s: retrieving phandle for cpu dai %s failed\n", + __func__, dai_link[i].cpu_dai_name); + ret = -ENODEV; + goto err; + } + dai_link[i].cpu_of_node = phandle; + dai_link[i].cpu_dai_name = NULL; + } +codec_dai: + /* populate codec_of_node for snd card dai links */ + if (dai_link[i].codec_name && !dai_link[i].codec_of_node) { + index = of_property_match_string(cdev->of_node, + "asoc-codec-names", + dai_link[i].codec_name); + if (index < 0) + continue; + phandle = of_parse_phandle(cdev->of_node, "asoc-codec", + index); + if (!phandle) { + pr_err("%s: retrieving phandle for codec dai %s failed\n", + __func__, dai_link[i].codec_name); + ret = -ENODEV; + goto err; + } + dai_link[i].codec_of_node = phandle; + dai_link[i].codec_name = NULL; + } + if ((dai_link[i].id == MSM_BACKEND_DAI_PRI_MI2S_RX) || + (dai_link[i].id == MSM_BACKEND_DAI_TERTIARY_MI2S_TX) || + (dai_link[i].id == MSM_BACKEND_DAI_SENARY_MI2S_TX)) { + if (pdata->snd_card_val == INT_SND_CARD) { + index = of_property_match_string( + cdev->of_node, + "asoc-codec-names", + MSM_INT_DIGITAL_CODEC); + + phandle = of_parse_phandle( + cdev->of_node, + "asoc-codec", index); + dai_link[i].codecs[DIG_CDC].of_node = phandle; + + index = of_property_match_string( + cdev->of_node, + "asoc-codec-names", + PMIC_INT_ANALOG_CODEC); + + phandle = of_parse_phandle( + cdev->of_node, + "asoc-codec", index); + dai_link[i].codecs[ANA_CDC].of_node = phandle; + } + if (pdata->snd_card_val == INT_DIG_SND_CARD) { + /* + * When only digital codec is enabled it results in + * crash due to NULL ptr exception as senary DAI has + * both analog and digital DAI info. Update + * codec_dai_name for digital codec to avoid the crash + */ + if (dai_link[i].id == + MSM_BACKEND_DAI_SENARY_MI2S_TX) { + dai_link[i].codecs = NULL; + dai_link[i].num_codecs = 1; + dai_link[i].codec_dai_name = + "msm_dig_cdc_dai_vifeed"; + } + index = of_property_match_string( + cdev->of_node, + "asoc-codec-names", + MSM_INT_DIGITAL_CODEC); + + phandle = of_parse_phandle( + cdev->of_node, + "asoc-codec", index); + dai_link[i].codec_of_node = phandle; + } + } + if ((dai_link[i].id == MSM_BACKEND_DAI_QUATERNARY_MI2S_RX) && + (of_property_read_bool( + cdev->of_node, "ext_pa_tfa98xx"))) { + index = of_property_match_string( + cdev->of_node, + "asoc-codec-names", + EXT_SMART_PA); + + phandle = of_parse_phandle( + cdev->of_node, + "asoc-codec", index); + dai_link[i].codec_of_node = phandle; + } + } +err: + return ret; +} + +int msm8952_init_wsa_switch_supply(struct platform_device *pdev, + struct msm_asoc_mach_data *pdata) +{ + const char *switch_supply_str = "msm-vdd-wsa-switch"; + char prop_name[MSM_DT_MAX_PROP_SIZE]; + struct device_node *regnode = NULL; + struct device *dev = &pdev->dev; + u32 prop_val; + int ret = 0; + + snprintf(prop_name, MSM_DT_MAX_PROP_SIZE, "%s-supply", + switch_supply_str); + regnode = of_parse_phandle(dev->of_node, prop_name, 0); + if (!regnode) { + dev_err(dev, "Looking up %s property in node %s failed\n", + prop_name, dev->of_node->full_name); + return -ENODEV; + } + + pdata->wsa_switch_supply.supply = devm_regulator_get(dev, + switch_supply_str); + if (IS_ERR(pdata->wsa_switch_supply.supply)) { + ret = PTR_ERR(pdata->wsa_switch_supply.supply); + dev_err(dev, "Failed to get wsa switch supply: err = %d\n", + ret); + return ret; + } + + snprintf(prop_name, MSM_DT_MAX_PROP_SIZE, + "qcom,%s-voltage", switch_supply_str); + ret = of_property_read_u32(dev->of_node, prop_name, + &prop_val); + if (ret) { + dev_err(dev, "Looking up %s property in node %s failed", + prop_name, dev->of_node->full_name); + return -EFAULT; + } + ret = regulator_set_voltage(pdata->wsa_switch_supply.supply, + prop_val, prop_val); + if (ret) { + dev_err(dev, "Setting voltage failed for %s err = %d\n", + switch_supply_str, ret); + pdata->wsa_switch_supply.supply = NULL; + return ret; + } + ret = regulator_set_load(pdata->wsa_switch_supply.supply, + prop_val); + if (ret < 0) { + dev_err(dev, "Setting voltage failed for %s err = %d\n", + switch_supply_str, ret); + pdata->wsa_switch_supply.supply = NULL; + return ret; + } + + snprintf(prop_name, MSM_DT_MAX_PROP_SIZE, + "qcom,%s-current", switch_supply_str); + ret = of_property_read_u32(dev->of_node, prop_name, + &prop_val); + if (ret) { + dev_err(dev, "Looking up %s property in node %s failed", + prop_name, dev->of_node->full_name); + return -EFAULT; + } + atomic_set(&pdata->wsa_switch_supply.ref, 0); + return ret; +} + +static struct snd_soc_card *msm8952_populate_sndcard_dailinks( + struct device *dev, int snd_card_val) +{ + struct snd_soc_card *card = &bear_card; + struct snd_soc_dai_link *dailink; + int len1; + + card->name = dev_name(dev); + len1 = ARRAY_SIZE(msm8952_dai); + memcpy(msm8952_dai_links, msm8952_dai, sizeof(msm8952_dai)); + dailink = msm8952_dai_links; + + if (snd_card_val == INT_SND_CARD) { + memcpy(dailink + len1, msm_int_be_dai, sizeof(msm_int_be_dai)); + len1 += ARRAY_SIZE(msm_int_be_dai); + } else { + memcpy(dailink + len1, msm_int_dig_be_dai, + sizeof(msm_int_dig_be_dai)); + len1 += ARRAY_SIZE(msm_int_dig_be_dai); + } + + if (of_property_read_bool(dev->of_node, + "qcom,hdmi-dba-codec-rx")) { + dev_dbg(dev, "%s(): hdmi audio support present\n", + __func__); + memcpy(dailink + len1, msm8952_hdmi_dba_dai_link, + sizeof(msm8952_hdmi_dba_dai_link)); + len1 += ARRAY_SIZE(msm8952_hdmi_dba_dai_link); + } else { + dev_dbg(dev, "%s(): No hdmi dba present, add quin dai\n", + __func__); + memcpy(dailink + len1, msm8952_quin_dai_link, + sizeof(msm8952_quin_dai_link)); + len1 += ARRAY_SIZE(msm8952_quin_dai_link); + } + if (of_property_read_bool(dev->of_node, + "qcom,split-a2dp")) { + dev_dbg(dev, "%s(): split a2dp support present\n", + __func__); + memcpy(dailink + len1, msm8952_split_a2dp_dai_link, + sizeof(msm8952_split_a2dp_dai_link)); + len1 += ARRAY_SIZE(msm8952_split_a2dp_dai_link); + } + + if (of_property_read_bool(dev->of_node, + "ext_pa_tfa98xx")) { + memcpy(dailink + len1, msm_tfa98xx_dig_be_dai_link, + sizeof(msm_tfa98xx_dig_be_dai_link)); + len1 += ARRAY_SIZE(msm_tfa98xx_dig_be_dai_link); + } + + card->dai_link = dailink; + card->num_links = len1; + return card; +} + +static const struct of_device_id msm8952_asoc_machine_of_match[] = { + { .compatible = "qcom,msm8952-audio-codec", + .data = "internal_codec"}, + { .compatible = "qcom,msm8952-dig-asoc-snd", + .data = "digital_codec"}, + {}, +}; + +static int msm8952_asoc_machine_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card; + struct msm_asoc_mach_data *pdata = NULL; + const char *hs_micbias_type = "qcom,msm-hs-micbias-type"; + const char *ext_pa = "qcom,msm-ext-pa"; + const char *mclk = "qcom,msm-mclk-freq"; + const char *wsa = "asoc-wsa-codec-names"; + const char *wsa_prefix = "asoc-wsa-codec-prefixes"; + const char *type = NULL; + const char *ext_pa_str = NULL; + const char *wsa_str = NULL; + const char *wsa_prefix_str = NULL; + const char *spk_ext_pa = "qcom,msm-spk-ext-pa"; + int num_strings; + int id, i, val; + int ret = 0; + struct resource *muxsel; + char *temp_str = NULL; + const struct of_device_id *match; + + pdata = devm_kzalloc(&pdev->dev, + sizeof(struct msm_asoc_mach_data), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + match = of_match_node(msm8952_asoc_machine_of_match, + pdev->dev.of_node); + if (!match) + goto err1; + + if (!strcmp(match->data, "internal_codec")) { + pdata->snd_card_val = INT_SND_CARD; + } else if (!strcmp(match->data, "digital_codec")) { + pdata->snd_card_val = INT_DIG_SND_CARD; + } else { + dev_err(&pdev->dev, + "%s: Not a matching DT sound node\n", __func__); + goto err1; + } + + muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "csr_gp_io_mux_mic_ctl"); + if (!muxsel) { + dev_err(&pdev->dev, "MUX addr invalid for MI2S\n"); + ret = -ENODEV; + goto err1; + } + pdata->vaddr_gpio_mux_mic_ctl = + ioremap(muxsel->start, resource_size(muxsel)); + if (pdata->vaddr_gpio_mux_mic_ctl == NULL) { + pr_err("%s ioremap failure for muxsel virt addr\n", + __func__); + ret = -ENOMEM; + goto err1; + } + + muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "csr_gp_io_mux_spkr_ctl"); + if (!muxsel) { + dev_err(&pdev->dev, "MUX addr invalid for MI2S\n"); + ret = -ENODEV; + goto err; + } + pdata->vaddr_gpio_mux_spkr_ctl = + ioremap(muxsel->start, resource_size(muxsel)); + if (pdata->vaddr_gpio_mux_spkr_ctl == NULL) { + pr_err("%s ioremap failure for muxsel virt addr\n", + __func__); + ret = -ENOMEM; + goto err; + } + + muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel"); + if (!muxsel) { + dev_err(&pdev->dev, "MUX addr invalid for MI2S\n"); + ret = -ENODEV; + goto err; + } + pdata->vaddr_gpio_mux_pcm_ctl = + ioremap(muxsel->start, resource_size(muxsel)); + if (pdata->vaddr_gpio_mux_pcm_ctl == NULL) { + pr_err("%s ioremap failure for muxsel virt addr\n", + __func__); + ret = -ENOMEM; + goto err; + } + + muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "csr_gp_io_mux_quin_ctl"); + if (!muxsel) { + dev_dbg(&pdev->dev, "MUX addr invalid for MI2S\n"); + goto parse_mclk_freq; + } + pdata->vaddr_gpio_mux_quin_ctl = + ioremap(muxsel->start, resource_size(muxsel)); + if (pdata->vaddr_gpio_mux_quin_ctl == NULL) { + pr_err("%s ioremap failure for muxsel virt addr\n", + __func__); + ret = -ENOMEM; + goto err; + } +parse_mclk_freq: + ret = of_property_read_u32(pdev->dev.of_node, mclk, &id); + if (ret) { + dev_err(&pdev->dev, + "%s: missing %s in dt node\n", __func__, mclk); + id = DEFAULT_MCLK_RATE; + } + pdata->mclk_freq = id; + + /*reading the gpio configurations from dtsi file*/ + num_strings = of_property_count_strings(pdev->dev.of_node, + wsa); + + if (num_strings > 0) { + if (wsa881x_get_probing_count() < 2) { + ret = -EPROBE_DEFER; + goto err; + } else if (wsa881x_get_presence_count() == num_strings) { + bear_card.aux_dev = msm8952_aux_dev; + bear_card.num_aux_devs = num_strings; + bear_card.codec_conf = msm8952_codec_conf; + bear_card.num_configs = num_strings; + + for (i = 0; i < num_strings; i++) { + ret = of_property_read_string_index( + pdev->dev.of_node, wsa, + i, &wsa_str); + if (ret) { + dev_err(&pdev->dev, + "%s:of read string %s i %d error %d\n", + __func__, wsa, i, ret); + goto err; + } + temp_str = kstrdup(wsa_str, GFP_KERNEL); + if (!temp_str) { + ret = -ENOMEM; + goto err; + } + msm8952_aux_dev[i].codec_name = temp_str; + temp_str = NULL; + + temp_str = kstrdup(wsa_str, GFP_KERNEL); + if (!temp_str) { + ret = -ENOMEM; + goto err; + } + msm8952_codec_conf[i].dev_name = temp_str; + temp_str = NULL; + + ret = of_property_read_string_index( + pdev->dev.of_node, wsa_prefix, + i, &wsa_prefix_str); + if (ret) { + dev_err(&pdev->dev, + "%s:of read string %s i %d error %d\n", + __func__, wsa_prefix, i, ret); + goto err; + } + temp_str = kstrdup(wsa_prefix_str, GFP_KERNEL); + if (!temp_str) { + ret = -ENOMEM; + goto err; + } + msm8952_codec_conf[i].name_prefix = temp_str; + temp_str = NULL; + } + + ret = msm8952_init_wsa_switch_supply(pdev, pdata); + if (ret < 0) { + pr_err("%s: failed to init wsa_switch vdd supply %d\n", + __func__, ret); + goto err; + } + wsa881x_set_mclk_callback(msm8952_enable_wsa_mclk); + /* update the internal speaker boost usage */ + msm_anlg_cdc_update_int_spk_boost(false); + } + } + + card = msm8952_populate_sndcard_dailinks(&pdev->dev, + pdata->snd_card_val); + dev_dbg(&pdev->dev, "default codec configured\n"); + num_strings = of_property_count_strings(pdev->dev.of_node, + ext_pa); + if (num_strings < 0) { + dev_err(&pdev->dev, + "%s: missing %s in dt node or length is incorrect\n", + __func__, ext_pa); + goto err; + } + for (i = 0; i < num_strings; i++) { + ret = of_property_read_string_index(pdev->dev.of_node, + ext_pa, i, &ext_pa_str); + if (ret) { + dev_err(&pdev->dev, "%s:of read string %s i %d error %d\n", + __func__, ext_pa, i, ret); + goto err; + } + dev_err(&pdev->dev, "%s:of read string %s i %d ret %d\n", + __func__, ext_pa, i, ret); + if (!strcmp(ext_pa_str, "primary")) + pdata->ext_pa = (pdata->ext_pa | PRI_MI2S_ID); + else if (!strcmp(ext_pa_str, "secondary")) + pdata->ext_pa = (pdata->ext_pa | SEC_MI2S_ID); + else if (!strcmp(ext_pa_str, "tertiary")) + pdata->ext_pa = (pdata->ext_pa | TER_MI2S_ID); + else if (!strcmp(ext_pa_str, "quaternary")) + pdata->ext_pa = (pdata->ext_pa | QUAT_MI2S_ID); + else if (!strcmp(ext_pa_str, "quinary")) + pdata->ext_pa = (pdata->ext_pa | QUIN_MI2S_ID); + } + pr_debug("%s: ext_pa = %d\n", __func__, pdata->ext_pa); + pdata->spk_ext_pa_gpio = of_get_named_gpio(pdev->dev.of_node, + spk_ext_pa, 0); + if (pdata->spk_ext_pa_gpio < 0) { + dev_err(&pdev->dev, "%s: missing %s in dt node\n", + __func__, spk_ext_pa); + } + + pdata->spk_ext_pa_gpio_p = of_parse_phandle(pdev->dev.of_node, + spk_ext_pa, 0); + ret = is_us_eu_switch_gpio_support(pdev, pdata); + if (ret < 0) { + pr_err("%s: failed to is_us_eu_switch_gpio_support %d\n", + __func__, ret); + goto err; + } + + pdata->dmic_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,cdc-dmic-gpios", 0); + + ret = is_ext_spk_gpio_support(pdev, pdata); + if (ret < 0) + pr_err("%s: doesn't support external speaker pa\n", + __func__); + + pdata->comp_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,cdc-comp-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); + pdata->mi2s_gpio_p[QUIN_MI2S] = of_parse_phandle(pdev->dev.of_node, + "qcom,quin-mi2s-gpios", 0); + + ret = of_property_read_string(pdev->dev.of_node, + hs_micbias_type, &type); + if (ret) { + dev_err(&pdev->dev, "%s: missing %s in dt node\n", + __func__, hs_micbias_type); + goto err; + } + if (!strcmp(type, "external")) { + dev_err(&pdev->dev, "Headset is using external micbias\n"); + mbhc_cfg.hs_ext_micbias = true; + } else { + dev_err(&pdev->dev, "Headset is using internal micbias\n"); + mbhc_cfg.hs_ext_micbias = false; + } + + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,msm-afe-clk-ver", &val); + if (ret) + pdata->afe_clk_ver = AFE_CLK_VERSION_V2; + else + pdata->afe_clk_ver = val; + /* initialize the mclk */ + pdata->digital_cdc_clk.i2s_cfg_minor_version = + AFE_API_VERSION_I2S_CONFIG; + pdata->digital_cdc_clk.clk_val = pdata->mclk_freq; + pdata->digital_cdc_clk.clk_root = 5; + pdata->digital_cdc_clk.reserved = 0; + /* initialize the digital codec core clk */ + pdata->digital_cdc_core_clk.clk_set_minor_version = + AFE_API_VERSION_I2S_CONFIG; + pdata->digital_cdc_core_clk.clk_id = + Q6AFE_LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE; + pdata->digital_cdc_core_clk.clk_freq_in_hz = + pdata->mclk_freq; + pdata->digital_cdc_core_clk.clk_attri = + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO; + pdata->digital_cdc_core_clk.clk_root = + Q6AFE_LPASS_CLK_ROOT_DEFAULT; + pdata->digital_cdc_core_clk.enable = 1; + + /* Initialize loopback mode to false */ + pdata->lb_mode = false; + msm8952_dt_parse_cap_info(pdev, pdata); + + 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) + goto err; + /* initialize timer */ + INIT_DELAYED_WORK(&pdata->disable_int_mclk0_work, msm8952_disable_mclk); + mutex_init(&pdata->cdc_int_mclk0_mutex); + atomic_set(&pdata->int_mclk0_rsc_ref, 0); + if (card->aux_dev) { + mutex_init(&pdata->wsa_mclk_mutex); + atomic_set(&pdata->wsa_int_mclk0_rsc_ref, 0); + } + atomic_set(&pdata->int_mclk0_enabled, false); + atomic_set(&quat_mi2s_clk_ref, 0); + atomic_set(&quin_mi2s_clk_ref, 0); + atomic_set(&auxpcm_mi2s_clk_ref, 0); + + ret = snd_soc_of_parse_audio_routing(card, + "qcom,audio-routing"); + if (ret) + goto err; + + ret = msm8952_populate_dai_link_component_of_node(pdata, card); + if (ret) { + ret = -EPROBE_DEFER; + goto err; + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + goto err; + } + + return 0; +err: + if (pdata->vaddr_gpio_mux_spkr_ctl) + iounmap(pdata->vaddr_gpio_mux_spkr_ctl); + if (pdata->vaddr_gpio_mux_mic_ctl) + iounmap(pdata->vaddr_gpio_mux_mic_ctl); + if (pdata->vaddr_gpio_mux_pcm_ctl) + iounmap(pdata->vaddr_gpio_mux_pcm_ctl); + if (pdata->vaddr_gpio_mux_quin_ctl) + iounmap(pdata->vaddr_gpio_mux_quin_ctl); + if (bear_card.num_aux_devs > 0) { + for (i = 0; i < bear_card.num_aux_devs; i++) { + kfree(msm8952_aux_dev[i].codec_name); + kfree(msm8952_codec_conf[i].dev_name); + kfree(msm8952_codec_conf[i].name_prefix); + } + } +err1: + devm_kfree(&pdev->dev, pdata); + return ret; +} + +static int msm8952_asoc_machine_remove(struct platform_device *pdev) +{ + int i; + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + + if (pdata->vaddr_gpio_mux_spkr_ctl) + iounmap(pdata->vaddr_gpio_mux_spkr_ctl); + if (pdata->vaddr_gpio_mux_mic_ctl) + iounmap(pdata->vaddr_gpio_mux_mic_ctl); + if (pdata->vaddr_gpio_mux_pcm_ctl) + iounmap(pdata->vaddr_gpio_mux_pcm_ctl); + if (pdata->vaddr_gpio_mux_quin_ctl) + iounmap(pdata->vaddr_gpio_mux_quin_ctl); + if (bear_card.num_aux_devs > 0) { + for (i = 0; i < bear_card.num_aux_devs; i++) { + kfree(msm8952_aux_dev[i].codec_name); + kfree(msm8952_codec_conf[i].dev_name); + kfree(msm8952_codec_conf[i].name_prefix); + } + mutex_destroy(&pdata->wsa_mclk_mutex); + } + snd_soc_unregister_card(card); + mutex_destroy(&pdata->cdc_int_mclk0_mutex); + return 0; +} + + +static struct platform_driver msm8952_asoc_machine_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = msm8952_asoc_machine_of_match, + }, + .probe = msm8952_asoc_machine_probe, + .remove = msm8952_asoc_machine_remove, +}; + +static int __init msm8952_machine_init(void) +{ + return platform_driver_register(&msm8952_asoc_machine_driver); +} +module_init(msm8952_machine_init); + +static void __exit msm8952_machine_exit(void) +{ + return platform_driver_unregister(&msm8952_asoc_machine_driver); +} +module_exit(msm8952_machine_exit); + +MODULE_DESCRIPTION("ALSA SoC msm"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, msm8952_asoc_machine_of_match); diff --git a/asoc/msm8952.h b/asoc/msm8952.h new file mode 100644 index 000000000000..0cc692e08967 --- /dev/null +++ b/asoc/msm8952.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018-2019, 2021, The Linux Foundation. All rights reserved. + */ + +#ifndef __MSM8953_H +#define __MSM8953_H + +#include +#include +#include +#include "codecs/sdm660_cdc/msm-analog-cdc.h" +#include "codecs/sdm660_cdc/msm-digital-cdc.h" +#include "codecs/wsa881x-analog.h" +#include +#include + + +#define BTSCO_RATE_8KHZ 8000 +#define BTSCO_RATE_16KHZ 16000 + +#define SAMPLING_RATE_48KHZ 48000 +#define SAMPLING_RATE_96KHZ 96000 +#define SAMPLING_RATE_192KHZ 192000 + +#define PRI_MI2S_ID (1 << 0) +#define SEC_MI2S_ID (1 << 1) +#define TER_MI2S_ID (1 << 2) +#define QUAT_MI2S_ID (1 << 3) +#define QUIN_MI2S_ID (1 << 4) + +#define DEFAULT_MCLK_RATE 9600000 + +#define WCD_MBHC_DEF_RLOADS 5 +#define MAX_WSA_CODEC_NAME_LENGTH 80 +#define MSM_DT_MAX_PROP_SIZE 80 + +enum { + DIG_CDC, + ANA_CDC, + CODECS_MAX, +}; + +enum { + PRIM_MI2S = 0, + SEC_MI2S, + TERT_MI2S, + QUAT_MI2S, + QUIN_MI2S, + MI2S_MAX, +}; + +enum { + INT_SND_CARD, + INT_DIG_SND_CARD, + INT_MAX_SND_CARD = INT_DIG_SND_CARD, + EXT_SND_CARD_TASHA, + EXT_SND_CARD_TAVIL, +}; + +struct msm_asoc_mach_data { + int codec_type; + int ext_pa; + int us_euro_gpio; + int spk_ext_pa_gpio; + int mclk_freq; + bool native_clk_set; + int lb_mode; + int afe_clk_ver; + int snd_card_val; + u8 micbias1_cap_mode; + u8 micbias2_cap_mode; + atomic_t int_mclk0_rsc_ref; + atomic_t int_mclk0_enabled; + atomic_t wsa_int_mclk0_rsc_ref; + struct mutex cdc_int_mclk0_mutex; + struct mutex wsa_mclk_mutex; + struct delayed_work disable_int_mclk0_work; + struct afe_digital_clk_cfg digital_cdc_clk; + struct afe_clk_set digital_cdc_core_clk; + void __iomem *vaddr_gpio_mux_spkr_ctl; + void __iomem *vaddr_gpio_mux_mic_ctl; + void __iomem *vaddr_gpio_mux_quin_ctl; + void __iomem *vaddr_gpio_mux_pcm_ctl; + struct on_demand_supply wsa_switch_supply; + struct device_node *spk_ext_pa_gpio_p; + struct device_node *us_euro_gpio_p; + struct device_node *comp_gpio_p; + struct device_node *mi2s_gpio_p[MI2S_MAX]; + struct device_node *dmic_gpio_p; /* used by pinctrl API */ + struct snd_soc_codec *codec; + struct snd_info_entry *codec_root; +}; + +#endif/*__MSM8953_H*/ diff --git a/config/sdm450auto.conf b/config/sdm450auto.conf new file mode 100644 index 000000000000..33e48952fc1c --- /dev/null +++ b/config/sdm450auto.conf @@ -0,0 +1,40 @@ +CONFIG_PINCTRL_WCD=m +CONFIG_AUDIO_EXT_CLK=m +CONFIG_SND_SOC_WCD9XXX_V2=m +CONFIG_SND_SOC_WCD_MBHC=m +CONFIG_SND_SOC_WCD_CPE=m +CONFIG_SND_SOC_CPE=m +CONFIG_SND_SOC_WSA881X=m +CONFIG_SND_SOC_WSA881X_ANALOG=m +CONFIG_SND_SOC_WCD9335=m +CONFIG_MSM_QDSP6V2_CODECS=m +CONFIG_MSM_ULTRASOUND=m +CONFIG_MSM_QDSP6_APRV2_RPMSG=m +CONFIG_MSM_ADSP_LOADER=m +CONFIG_REGMAP_SWR=m +CONFIG_MSM_QDSP6_SSR=m +CONFIG_MSM_QDSP6_NOTIFIER=m +CONFIG_SND_SOC_MSM_HOSTLESS_PCM=m +CONFIG_SND_SOC_MSM_QDSP6V2_INTF=m +CONFIG_SND_SOC_SDM450=m +CONFIG_SND_SOC_EXT_CODEC_SDM450=m +CONFIG_SOUNDWIRE=m +CONFIG_SOUNDWIRE_WCD_CTRL=m +CONFIG_SND_SOC_QDSP6V2=m +CONFIG_SND_SOC_MSM_QDSP6V2_INTF=m +CONFIG_WCD9XXX_CODEC_CORE=m +CONFIG_MSM_CDC_PINCTRL=m +CONFIG_SND_SOC_WCD_MBHC_LEGACY=m +CONFIG_QTI_PP=m +CONFIG_QTI_PP_AUDIOSPHERE=m +CONFIG_SND_HWDEP_ROUTING=m +CONFIG_DTS_EAGLE=m +CONFIG_DOLBY_DS2=m +CONFIG_DOLBY_LICENSE=m +CONFIG_DTS_SRS_TM=m +CONFIG_SND_SOC_MSM_STUB=m +CONFIG_SND_SOC_SDM660_CDC=m +CONFIG_SND_SOC_ANALOG_CDC=m +CONFIG_SND_SOC_DIGITAL_CDC_LEGACY=m +CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=m +CONFIG_WCD_DSP_GLINK=m diff --git a/config/sdm450autoconf.h b/config/sdm450autoconf.h new file mode 100644 index 000000000000..f671dfd89c7f --- /dev/null +++ b/config/sdm450autoconf.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018, 2020-2021, The Linux Foundation. All rights reserved. + */ + +#define CONFIG_PINCTRL_WCD 1 +#define CONFIG_AUDIO_EXT_CLK 1 +#define CONFIG_SND_SOC_WCD9XXX_V2 1 +#define CONFIG_SND_SOC_WCD_CPE 1 +#define CONFIG_SND_SOC_CPE 1 +#define CONFIG_SND_SOC_WCD_MBHC 1 +#define CONFIG_SND_SOC_WSA881X 1 +#define CONFIG_SND_SOC_WSA881X_ANALOG 1 +#define CONFIG_SND_SOC_WCD9335 1 +#define CONFIG_MSM_QDSP6V2_CODECS 1 +#define CONFIG_MSM_ULTRASOUND 1 +#define CONFIG_MSM_QDSP6_APRV2_RPMSG 1 +#define CONFIG_MSM_ADSP_LOADER 1 +#define CONFIG_REGMAP_SWR 1 +#define CONFIG_MSM_QDSP6_SSR 1 +#define CONFIG_MSM_QDSP6_NOTIFIER 1 +#define CONFIG_SND_SOC_MSM_HOSTLESS_PCM 1 +#define CONFIG_SND_SOC_MSM_QDSP6V2_INTF 1 +#define CONFIG_SND_SOC_SDM450 1 +#define CONFIG_SND_SOC_EXT_CODEC_SDM450 1 +#define CONFIG_SOUNDWIRE 1 +#define CONFIG_SOUNDWIRE_WCD_CTRL 1 +#define CONFIG_SND_SOC_WCD_MBHC_LEGACY 1 +#define CONFIG_SND_SOC_QDSP6V2 1 +#define CONFIG_QTI_PP 1 +#define CONFIG_QTI_PP_AUDIOSPHERE 1 +#define CONFIG_SND_HWDEP_ROUTING 1 +#define CONFIG_DTS_EAGLE 1 +#define CONFIG_DOLBY_DS2 1 +#define CONFIG_DOLBY_LICENSE 1 +#define CONFIG_DTS_SRS_TM 1 +#define CONFIG_WCD9XXX_CODEC_CORE 1 +#define CONFIG_MSM_CDC_PINCTRL 1 +#define CONFIG_SND_SOC_MSM_STUB 1 +#define CONFIG_SND_SOC_EXT_CODEC 1 +#define CONFIG_SND_SOC_INT_CODEC 1 +#define CONFIG_SND_SOC_SDM660_CDC 1 +#define CONFIG_SND_SOC_ANALOG_CDC 1 +#define CONFIG_SND_SOC_DIGITAL_CDC_LEGACY 1 +#define CONFIG_SND_SOC_MSM_HDMI_CODEC_RX 1 +#define CONFIG_COMMON_CLK 1 +#define CONFIG_WCD_DSP_GLINK 1 diff --git a/dsp/Android.mk b/dsp/Android.mk index 90a486e46fc7..8a1a0293d80d 100644 --- a/dsp/Android.mk +++ b/dsp/Android.mk @@ -35,9 +35,13 @@ ifeq ($(call is-board-platform,sdm660),true) AUDIO_SELECT := CONFIG_SND_SOC_SDM660=m endif +ifeq ($(call is-board-platform-in-list,msm8953 msm8937),true) +AUDIO_SELECT := CONFIG_SND_SOC_SDM450=m +endif + AUDIO_CHIPSET := audio # Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660),true) +ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937),true) LOCAL_PATH := $(call my-dir) diff --git a/dsp/Kbuild b/dsp/Kbuild index 490b458bfc2b..dd3c886ec647 100644 --- a/dsp/Kbuild +++ b/dsp/Kbuild @@ -81,6 +81,21 @@ ifeq ($(KERNEL_BUILD), 0) export INCS += -include $(AUDIO_ROOT)/config/sdm660autoconf.h endif + ifeq ($(CONFIG_ARCH_SDM450), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif + ifeq ($(CONFIG_ARCH_SDM439), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif + ifeq ($(CONFIG_ARCH_MSM8917), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif endif diff --git a/dsp/audio_notifier.c b/dsp/audio_notifier.c index 7a8249dc3d0a..cdb80fbdcf5e 100644 --- a/dsp/audio_notifier.c +++ b/dsp/audio_notifier.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, 2021, The Linux Foundation. All rights reserved. */ #include @@ -629,7 +629,7 @@ static int __init audio_notifier_init(void) static int __init audio_notifier_init(void) { audio_notifier_subsys_init(); - audio_notifier_disable_service(AUDIO_NOTIFIER_PDR_SERVICE); + audio_notifer_disable_service(AUDIO_NOTIFIER_PDR_SERVICE); audio_notifier_late_init(); diff --git a/dsp/codecs/Android.mk b/dsp/codecs/Android.mk index a27f1b06d5a6..ceb1c8f2490b 100644 --- a/dsp/codecs/Android.mk +++ b/dsp/codecs/Android.mk @@ -27,9 +27,13 @@ ifeq ($(call is-board-platform,sdm660),true) AUDIO_SELECT := CONFIG_SND_SOC_SDM660=m endif +ifeq ($(call is-board-platform-in-list,msm8953 msm8937),true) +AUDIO_SELECT := CONFIG_SND_SOC_SDM450=m +endif + AUDIO_CHIPSET := audio # Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660),true) +ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937),true) LOCAL_PATH := $(call my-dir) diff --git a/dsp/codecs/Kbuild b/dsp/codecs/Kbuild index 808bfe22a076..039064da91aa 100644 --- a/dsp/codecs/Kbuild +++ b/dsp/codecs/Kbuild @@ -63,6 +63,21 @@ ifeq ($(KERNEL_BUILD), 0) export INCS += -include $(AUDIO_ROOT)/config/sdm660autoconf.h endif + ifeq ($(CONFIG_ARCH_SDM450), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif + ifeq ($(CONFIG_ARCH_SDM439), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif + ifeq ($(CONFIG_ARCH_MSM8917), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif endif # As per target team, build is done as follows: diff --git a/include/asoc/sdm660-common.h b/include/asoc/sdm660-common.h index a8c815c330f1..36abdb2a9543 100644 --- a/include/asoc/sdm660-common.h +++ b/include/asoc/sdm660-common.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2019, 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2019, 2020-2021, The Linux Foundation. All rights reserved. */ #ifndef __MSM_COMMON @@ -86,6 +86,8 @@ struct sdm660_codec { enum { INT_SND_CARD, + INT_DIG_SND_CARD, + INT_MAX_SND_CARD = INT_DIG_SND_CARD, EXT_SND_CARD_TASHA, EXT_SND_CARD_TAVIL, }; diff --git a/ipc/Android.mk b/ipc/Android.mk index 99ffc3076a1c..6364ed7d8102 100644 --- a/ipc/Android.mk +++ b/ipc/Android.mk @@ -35,9 +35,13 @@ ifeq ($(call is-board-platform,sdm660),true) AUDIO_SELECT := CONFIG_SND_SOC_SDM660=m endif +ifeq ($(call is-board-platform-in-list, msm8953 msm8937),true) +AUDIO_SELECT := CONFIG_SND_SOC_SDM450=m +endif + AUDIO_CHIPSET := audio # Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660),true) +ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937),true) LOCAL_PATH := $(call my-dir) diff --git a/ipc/Kbuild b/ipc/Kbuild index 755d6d8eacd5..05b71ce9ad43 100644 --- a/ipc/Kbuild +++ b/ipc/Kbuild @@ -82,6 +82,21 @@ ifeq ($(KERNEL_BUILD), 0) export INCS += -include $(AUDIO_ROOT)/config/sdm660autoconf.h endif + ifeq ($(CONFIG_ARCH_SDM450), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif + ifeq ($(CONFIG_ARCH_SDM439), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif + ifeq ($(CONFIG_ARCH_MSM8917), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif endif # As per target team, build is done as follows: diff --git a/soc/Android.mk b/soc/Android.mk index d6a1203c1c75..858be88c455b 100644 --- a/soc/Android.mk +++ b/soc/Android.mk @@ -35,9 +35,13 @@ ifeq ($(call is-board-platform,sdm660),true) AUDIO_SELECT := CONFIG_SND_SOC_SDM660=m endif +ifeq ($(call is-board-platform-in-list,msm8953 msm8937),true) +AUDIO_SELECT := CONFIG_SND_SOC_SDM450=m +endif + AUDIO_CHIPSET := audio # Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660),true) +ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937),true) LOCAL_PATH := $(call my-dir) @@ -76,7 +80,7 @@ include $(DLKM_DIR)/AndroidKernelModule.mk endif endif ########################################################### -ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) kona sdm660), true) +ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) kona sdm660 msm8953 msm8937), true) ifneq ($(TARGET_BOARD_AUTO),true) include $(CLEAR_VARS) LOCAL_MODULE := $(AUDIO_CHIPSET)_pinctrl_wcd.ko diff --git a/soc/Kbuild b/soc/Kbuild index 4fedbddcf460..956fd4772197 100644 --- a/soc/Kbuild +++ b/soc/Kbuild @@ -81,6 +81,21 @@ ifeq ($(KERNEL_BUILD), 0) export INCS += -include $(AUDIO_ROOT)/config/sdm660autoconf.h endif + ifeq ($(CONFIG_ARCH_SDM450), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif + ifeq ($(CONFIG_ARCH_SDM439), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif + ifeq ($(CONFIG_ARCH_MSM8917), y) + include $(AUDIO_ROOT)/config/sdm450auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h + endif endif # As per target team, build is done as follows: