diff --git a/Makefile b/Makefile index f59920d2c2..1d16c10993 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,9 @@ endif ifeq ($(CONFIG_ARCH_LAHAINA), y) include $(srctree)/techpack/audio/config/lahainaauto.conf endif +ifeq ($(CONFIG_ARCH_HOLI), y) +include $(srctree)/techpack/audio/config/holiauto.conf +endif endif # Use USERINCLUDE when you must reference the UAPI directories only. @@ -51,6 +54,10 @@ ifeq ($(CONFIG_ARCH_LAHAINA), y) LINUXINCLUDE += \ -include $(srctree)/techpack/audio/config/lahainaautoconf.h endif +ifeq ($(CONFIG_ARCH_HOLI), y) +LINUXINCLUDE += \ + -include $(srctree)/techpack/audio/config/holiautoconf.h +endif obj-y += soc/ obj-y += dsp/ diff --git a/Makefile.am b/Makefile.am index a1b2fcd1d8..cbcf781d9b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,6 +18,8 @@ ifeq ($(TARGET_SUPPORT), sdmsteppe) KBUILD_OPTIONS += CONFIG_ARCH_SM6150=y endif +subdir-ccflags-y += -I$(AUDIO_ROOT)/include/uapi/ + obj-m := ipc/ obj-m += dsp/ obj-m += soc/ @@ -50,6 +52,10 @@ KBUILD_OPTIONS += CONFIG_SND_SOC_SA6155=m endif endif +define PROCESS_HEADERS + $(foreach name,$(1),$(shell cd $(KERNEL_BINARY_DIR) && $(KERNEL_SRC)/scripts/headers_install.sh $(2)$(name) $(3)$(name))) +endef + all: $(shell rm -fr $(shell pwd)/soc/core.h) $(shell ln -s $(KERNEL_SRC)/drivers/pinctrl/core.h $(shell pwd)/soc/core.h) @@ -61,15 +67,17 @@ all: $(shell mkdir $(shell pwd)/sound) $(shell mkdir $(shell pwd)/linux/mfd) $(shell mkdir $(shell pwd)/linux/mfd/wcd9xxx) - $(shell cd $(KERNEL_BINARY_DIR) && $(KERNEL_SRC)/scripts/headers_install.sh $(UAPI_OUT)/linux/ $(AUDIO_ROOT)/include/uapi/audio/linux/ $(notdir $(AUDIO_KERNEL_HEADERS_PATH1))) - $(shell cd $(KERNEL_BINARY_DIR) && $(KERNEL_SRC)/scripts/headers_install.sh $(UAPI_OUT)/linux/mfd/wcd9xxx/ $(AUDIO_ROOT)/include/uapi/audio/linux/mfd/wcd9xxx/ $(notdir $(AUDIO_KERNEL_HEADERS_PATH2))) - $(shell cd $(KERNEL_BINARY_DIR) && $(KERNEL_SRC)/scripts/headers_install.sh $(UAPI_OUT)/sound/ $(AUDIO_ROOT)/include/uapi/audio/sound/ $(notdir $(AUDIO_KERNEL_HEADERS_PATH3))) - $(shell mkdir $(KERNEL_BINARY_DIR)/usr/include/sound) - $(shell mkdir $(KERNEL_BINARY_DIR)/usr/include/linux/mfd) - $(shell mkdir $(KERNEL_BINARY_DIR)/usr/include/linux/mfd/wcd9xxx) - $(shell cd $(KERNEL_BINARY_DIR) && $(KERNEL_SRC)/scripts/headers_install.sh $(KERNEL_BINARY_DIR)/usr/include/linux/ $(AUDIO_ROOT)/include/uapi/audio/linux/ $(notdir $(AUDIO_KERNEL_HEADERS_PATH1))) - $(shell cd $(KERNEL_BINARY_DIR) && $(KERNEL_SRC)/scripts/headers_install.sh $(KERNEL_BINARY_DIR)/usr/include/linux/mfd/wcd9xxx/ $(AUDIO_ROOT)/include/uapi/audio/linux/mfd/wcd9xxx/ $(notdir $(AUDIO_KERNEL_HEADERS_PATH2))) - $(shell cd $(KERNEL_BINARY_DIR) && $(KERNEL_SRC)/scripts/headers_install.sh $(KERNEL_BINARY_DIR)/usr/include/sound/ $(AUDIO_ROOT)/include/uapi/audio/sound/ $(notdir $(AUDIO_KERNEL_HEADERS_PATH3))) + $(call PROCESS_HEADERS, $(notdir $(shell ls $(AUDIO_ROOT)/include/uapi/audio/linux/*.h)), $(AUDIO_ROOT)/include/uapi/audio/linux/, $(UAPI_OUT)/linux/) + $(call PROCESS_HEADERS, $(notdir $(shell ls $(AUDIO_ROOT)/include/uapi/audio/linux/mfd/wcd9xxx/*.h)), $(AUDIO_ROOT)/include/uapi/audio/linux/mfd/wcd9xxx/, $(UAPI_OUT)/linux/mfd/wcd9xxx/) + $(call PROCESS_HEADERS, $(notdir $(shell ls $(AUDIO_ROOT)/include/uapi/audio/sound/*.h)), $(AUDIO_ROOT)/include/uapi/audio/sound/, $(UAPI_OUT)/sound/) + $(shell mkdir $(KERNEL_BINARY_DIR)/usr/include/audio) + $(shell mkdir $(KERNEL_BINARY_DIR)/usr/include/audio/sound) + $(shell mkdir $(KERNEL_BINARY_DIR)/usr/include/audio/linux) + $(shell mkdir $(KERNEL_BINARY_DIR)/usr/include/audio/linux/mfd) + $(shell mkdir $(KERNEL_BINARY_DIR)/usr/include/audio/linux/mfd/wcd9xxx) + $(call PROCESS_HEADERS, $(notdir $(shell ls $(AUDIO_ROOT)/include/uapi/audio/linux/*.h)), $(AUDIO_ROOT)/include/uapi/audio/linux/, $(KERNEL_BINARY_DIR)/usr/include/audio/linux/) + $(call PROCESS_HEADERS, $(notdir $(shell ls $(AUDIO_ROOT)/include/uapi/audio/linux/mfd/wcd9xxx/*.h)), $(AUDIO_ROOT)/include/uapi/audio/linux/mfd/wcd9xxx/, $(KERNEL_BINARY_DIR)/usr/include/audio/linux/mfd/wcd9xxx/) + $(call PROCESS_HEADERS, $(notdir $(shell ls $(AUDIO_ROOT)/include/uapi/audio/sound/*.h)), $(AUDIO_ROOT)/include/uapi/audio/sound/, $(KERNEL_BINARY_DIR)/usr/include/audio/sound/) $(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS) modules_install: diff --git a/asoc/Kbuild b/asoc/Kbuild index b40f2c2a0e..c14dcdd090 100644 --- a/asoc/Kbuild +++ b/asoc/Kbuild @@ -138,6 +138,11 @@ ifdef CONFIG_SND_SOC_LAHAINA MACHINE_OBJS += lahaina.o endif +# for HOLI sound card driver +ifdef CONFIG_SND_SOC_HOLI + MACHINE_OBJS += holi.o +endif + ifdef CONFIG_SND_SOC_LITO MACHINE_OBJS += kona.o endif @@ -219,6 +224,9 @@ machine_dlkm-y := $(MACHINE_OBJS) obj-$(CONFIG_SND_SOC_LAHAINA) += machine_dlkm.o machine_dlkm-y := $(MACHINE_OBJS) +obj-$(CONFIG_SND_SOC_HOLI) += machine_dlkm.o +machine_dlkm-y := $(MACHINE_OBJS) + obj-$(CONFIG_SND_SOC_LITO) += machine_dlkm.o machine_dlkm-y := $(MACHINE_OBJS) diff --git a/asoc/codecs/bolero/bolero-cdc-regmap.c b/asoc/codecs/bolero/bolero-cdc-regmap.c index 1e4fa15cfd..84bbd78a16 100644 --- a/asoc/codecs/bolero/bolero-cdc-regmap.c +++ b/asoc/codecs/bolero/bolero-cdc-regmap.c @@ -805,6 +805,8 @@ static bool bolero_is_volatile_register(struct device *dev, case BOLERO_CDC_TX_TOP_CSR_SWR_DMIC1_CTL: case BOLERO_CDC_TX_TOP_CSR_SWR_DMIC2_CTL: case BOLERO_CDC_TX_TOP_CSR_SWR_DMIC3_CTL: + case BOLERO_CDC_TX_TOP_CSR_SWR_MIC0_CTL: + case BOLERO_CDC_TX_TOP_CSR_SWR_MIC1_CTL: case BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_MON_VAL: case BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_ST: case BOLERO_CDC_WSA_INTR_CTRL_PIN1_STATUS0: diff --git a/asoc/codecs/bolero/bolero-cdc.c b/asoc/codecs/bolero/bolero-cdc.c index 08cb07f7f9..4f73007027 100644 --- a/asoc/codecs/bolero/bolero-cdc.c +++ b/asoc/codecs/bolero/bolero-cdc.c @@ -232,6 +232,27 @@ static int bolero_cdc_update_wcd_event(void *handle, u16 event, u32 data) priv->component, BOLERO_MACRO_EVT_BCS_CLK_OFF, data); break; + case WCD_BOLERO_EVT_RX_PA_GAIN_UPDATE: + /* Update PA Gain only for bolero version 2.1 */ + if (priv->version == BOLERO_VERSION_2_1) + if (priv->macro_params[RX_MACRO].event_handler) + priv->macro_params[RX_MACRO].event_handler( + priv->component, + BOLERO_MACRO_EVT_RX_PA_GAIN_UPDATE, + data); + break; + case WCD_BOLERO_EVT_HPHL_HD2_ENABLE: + if (priv->macro_params[RX_MACRO].event_handler) + priv->macro_params[RX_MACRO].event_handler( + priv->component, + BOLERO_MACRO_EVT_HPHL_HD2_ENABLE, data); + break; + case WCD_BOLERO_EVT_HPHR_HD2_ENABLE: + if (priv->macro_params[RX_MACRO].event_handler) + priv->macro_params[RX_MACRO].event_handler( + priv->component, + BOLERO_MACRO_EVT_HPHR_HD2_ENABLE, data); + break; default: dev_err(priv->dev, "%s: Invalid event %d trigger from wcd\n", __func__, event); @@ -755,7 +776,7 @@ void bolero_unregister_macro(struct device *dev, u16 macro_id) } EXPORT_SYMBOL(bolero_unregister_macro); -void bolero_wsa_pa_on(struct device *dev) +void bolero_wsa_pa_on(struct device *dev, bool adie_lb) { struct bolero_priv *priv; @@ -773,8 +794,12 @@ void bolero_wsa_pa_on(struct device *dev) dev_err(dev, "%s: priv is null\n", __func__); return; } - - bolero_cdc_notifier_call(priv, BOLERO_WCD_EVT_PA_ON_POST_FSCLK); + if (adie_lb) + bolero_cdc_notifier_call(priv, + BOLERO_WCD_EVT_PA_ON_POST_FSCLK_ADIE_LB); + else + bolero_cdc_notifier_call(priv, + BOLERO_WCD_EVT_PA_ON_POST_FSCLK); } EXPORT_SYMBOL(bolero_wsa_pa_on); diff --git a/asoc/codecs/bolero/bolero-cdc.h b/asoc/codecs/bolero/bolero-cdc.h index eee4c0c2a7..fe0aa64c0a 100644 --- a/asoc/codecs/bolero/bolero-cdc.h +++ b/asoc/codecs/bolero/bolero-cdc.h @@ -50,6 +50,9 @@ enum { BOLERO_MACRO_EVT_BCS_CLK_OFF, BOLERO_MACRO_EVT_SSR_GFMUX_UP, BOLERO_MACRO_EVT_PRE_SSR_UP, + BOLERO_MACRO_EVT_RX_PA_GAIN_UPDATE, + BOLERO_MACRO_EVT_HPHL_HD2_ENABLE, /* Enable HD2 cfg for HPHL */ + BOLERO_MACRO_EVT_HPHR_HD2_ENABLE, /* Enable HD2 cfg for HPHR */ }; enum { @@ -99,7 +102,7 @@ int bolero_runtime_suspend(struct device *dev); int bolero_set_port_map(struct snd_soc_component *component, u32 size, void *data); int bolero_register_event_listener(struct snd_soc_component *component, bool enable); -void bolero_wsa_pa_on(struct device *dev); +void bolero_wsa_pa_on(struct device *dev, bool adie_lb); bool bolero_check_core_votes(struct device *dev); int bolero_tx_mclk_enable(struct snd_soc_component *c, bool enable); int bolero_get_version(struct device *dev); @@ -176,7 +179,7 @@ static inline int bolero_register_event_listener( return 0; } -static void bolero_wsa_pa_on(struct device *dev) +static void bolero_wsa_pa_on(struct device *dev, bool adie_lb) { } diff --git a/asoc/codecs/bolero/internal.h b/asoc/codecs/bolero/internal.h index 503443158c..cf132bdd2c 100644 --- a/asoc/codecs/bolero/internal.h +++ b/asoc/codecs/bolero/internal.h @@ -16,6 +16,7 @@ enum { BOLERO_WCD_EVT_SSR_DOWN, BOLERO_WCD_EVT_SSR_UP, BOLERO_WCD_EVT_PA_ON_POST_FSCLK, + BOLERO_WCD_EVT_PA_ON_POST_FSCLK_ADIE_LB, }; enum { @@ -32,6 +33,9 @@ enum { WCD_BOLERO_EVT_IMPED_FALSE, /* for imped false */ WCD_BOLERO_EVT_RX_COMPANDER_SOFT_RST, WCD_BOLERO_EVT_BCS_CLK_OFF, + WCD_BOLERO_EVT_RX_PA_GAIN_UPDATE, + WCD_BOLERO_EVT_HPHL_HD2_ENABLE, /* to enable hd2 config for hphl */ + WCD_BOLERO_EVT_HPHR_HD2_ENABLE, /* to enable hd2 config for hphr */ }; struct wcd_ctrl_platform_data { diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c index e425d09489..48f596e20c 100644 --- a/asoc/codecs/bolero/rx-macro.c +++ b/asoc/codecs/bolero/rx-macro.c @@ -78,6 +78,11 @@ static const struct snd_kcontrol_new name##_mux = \ #define RX_MACRO_EC_MIX_TX1_MASK 0x0f #define RX_MACRO_EC_MIX_TX2_MASK 0x0f +#define RX_MACRO_GAIN_MAX_VAL 0x28 +#define RX_MACRO_GAIN_VAL_UNITY 0x0 +/* Define macros to increase PA Gain by half */ +#define RX_MACRO_MOD_GAIN (RX_MACRO_GAIN_VAL_UNITY + 6) + #define COMP_MAX_COEFF 25 struct wcd_imped_val { @@ -454,6 +459,8 @@ struct rx_macro_priv { struct rx_macro_bcl_pmic_params bcl_pmic_params; u16 clk_id; u16 default_clk_id; + int8_t rx0_gain_val; + int8_t rx1_gain_val; }; static struct snd_soc_dai_driver rx_macro_dai[]; @@ -1460,6 +1467,56 @@ static int rx_macro_event_handler(struct snd_soc_component *component, case BOLERO_MACRO_EVT_CLK_RESET: bolero_rsc_clk_reset(rx_dev, RX_CORE_CLK); break; + case BOLERO_MACRO_EVT_RX_PA_GAIN_UPDATE: + rx_priv->rx0_gain_val = snd_soc_component_read32(component, + BOLERO_CDC_RX_RX0_RX_VOL_CTL); + rx_priv->rx1_gain_val = snd_soc_component_read32(component, + BOLERO_CDC_RX_RX1_RX_VOL_CTL); + if (data) { + /* Reduce gain by half only if its greater than -6DB */ + if ((rx_priv->rx0_gain_val >= RX_MACRO_GAIN_VAL_UNITY) + && (rx_priv->rx0_gain_val <= RX_MACRO_GAIN_MAX_VAL)) + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX0_RX_VOL_CTL, 0xFF, + (rx_priv->rx0_gain_val - + RX_MACRO_MOD_GAIN)); + if ((rx_priv->rx1_gain_val >= RX_MACRO_GAIN_VAL_UNITY) + && (rx_priv->rx1_gain_val <= RX_MACRO_GAIN_MAX_VAL)) + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX1_RX_VOL_CTL, 0xFF, + (rx_priv->rx1_gain_val - + RX_MACRO_MOD_GAIN)); + } + else { + /* Reset gain value to default */ + if ((rx_priv->rx0_gain_val >= + (RX_MACRO_GAIN_VAL_UNITY - RX_MACRO_MOD_GAIN)) && + (rx_priv->rx0_gain_val <= (RX_MACRO_GAIN_MAX_VAL - + RX_MACRO_MOD_GAIN))) + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX0_RX_VOL_CTL, 0xFF, + (rx_priv->rx0_gain_val + + RX_MACRO_MOD_GAIN)); + if ((rx_priv->rx1_gain_val >= + (RX_MACRO_GAIN_VAL_UNITY - RX_MACRO_MOD_GAIN)) && + (rx_priv->rx1_gain_val <= (RX_MACRO_GAIN_MAX_VAL - + RX_MACRO_MOD_GAIN))) + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX1_RX_VOL_CTL, 0xFF, + (rx_priv->rx1_gain_val + + RX_MACRO_MOD_GAIN)); + } + break; + case BOLERO_MACRO_EVT_HPHL_HD2_ENABLE: + /* Enable hd2 config for hphl*/ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX0_RX_PATH_CFG0, 0x04, data); + break; + case BOLERO_MACRO_EVT_HPHR_HD2_ENABLE: + /* Enable hd2 config for hphr*/ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX1_RX_PATH_CFG0, 0x04, data); + break; } done: return ret; @@ -3877,6 +3934,8 @@ static int rx_macro_init(struct snd_soc_component *component) return ret; } rx_priv->dev_up = true; + rx_priv->rx0_gain_val = 0; + rx_priv->rx1_gain_val = 0; snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF1 Playback"); snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF2 Playback"); snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF3 Playback"); @@ -4106,6 +4165,8 @@ static int rx_macro_probe(struct platform_device *pdev) __func__); return -EPROBE_DEFER; } + msm_cdc_pinctrl_set_wakeup_capable( + rx_priv->rx_swr_gpio_p, false); rx_io_base = devm_ioremap(&pdev->dev, rx_base_addr, RX_MACRO_MAX_OFFSET); diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c index 4270d977cd..cddd07477a 100644 --- a/asoc/codecs/bolero/tx-macro.c +++ b/asoc/codecs/bolero/tx-macro.c @@ -177,6 +177,8 @@ struct tx_macro_priv { bool bcs_clk_en; bool hs_slow_insert_complete; int amic_sample_rate; + bool lpi_enable; + bool register_event_listener; }; static bool tx_macro_get_data(struct snd_soc_component *component, @@ -235,11 +237,11 @@ static int tx_macro_mclk_enable(struct tx_macro_priv *tx_priv, } bolero_clk_rsc_fs_gen_request(tx_priv->dev, true); + regcache_mark_dirty(regmap); + regcache_sync_region(regmap, + TX_START_OFFSET, + TX_MAX_OFFSET); if (tx_priv->tx_mclk_users == 0) { - regcache_mark_dirty(regmap); - regcache_sync_region(regmap, - TX_START_OFFSET, - TX_MAX_OFFSET); /* 9.6MHz MCLK, set value 0x00 if other frequency */ regmap_update_bits(regmap, BOLERO_CDC_TX_TOP_CSR_FREQ_MCLK, 0x01, 0x01); @@ -330,6 +332,45 @@ static int tx_macro_tx_swr_clk_event(struct snd_soc_dapm_widget *w, return 0; } +static int tx_macro_swr_pwr_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + int ret = 0; + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + dev_dbg(tx_dev, "%s: event = %d, lpi_enable = %d\n", + __func__, event, tx_priv->lpi_enable); + + if (!tx_priv->lpi_enable) + return ret; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (tx_priv->lpi_enable) { + bolero_register_event_listener(component, true); + tx_priv->register_event_listener = true; + } + break; + case SND_SOC_DAPM_POST_PMD: + if (tx_priv->register_event_listener) { + tx_priv->register_event_listener = false; + bolero_register_event_listener(component, false); + } + break; + default: + dev_err(tx_priv->dev, + "%s: invalid DAPM event %d\n", __func__, event); + ret = -EINVAL; + } + return ret; +} + static int tx_macro_mclk_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -784,6 +825,38 @@ static int tx_macro_dec_mode_put(struct snd_kcontrol *kcontrol, return 0; } +static int tx_macro_lpi_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = tx_priv->lpi_enable; + + return 0; +} + +static int tx_macro_lpi_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + tx_priv->lpi_enable = ucontrol->value.integer.value[0]; + + return 0; +} + static int tx_macro_bcs_ch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1675,6 +1748,10 @@ static const struct snd_soc_dapm_widget tx_macro_dapm_widgets_common[] = { SND_SOC_DAPM_SUPPLY_S("TX_MCLK", 0, SND_SOC_NOPM, 0, 0, tx_macro_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("TX_SWR_PWR", -1, SND_SOC_NOPM, 0, 0, + tx_macro_swr_pwr_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), }; static const struct snd_soc_dapm_widget tx_macro_dapm_widgets_v2[] = { @@ -2144,6 +2221,19 @@ static const struct snd_soc_dapm_route tx_audio_map_v3[] = { {"TX SMIC MUX5", NULL, "TX_SWR_CLK"}, {"TX SMIC MUX6", NULL, "TX_SWR_CLK"}, {"TX SMIC MUX7", NULL, "TX_SWR_CLK"}, + + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, }; static const struct snd_soc_dapm_route tx_audio_map[] = { @@ -2406,6 +2496,9 @@ static const struct snd_kcontrol_new tx_macro_snd_controls_common[] = { BOLERO_CDC_TX3_TX_VOL_CTL, -84, 40, digital_gain), + SOC_SINGLE_EXT("TX LPI Enable", 0, 0, 1, 0, + tx_macro_lpi_get, tx_macro_lpi_put), + SOC_ENUM_EXT("DEC0 MODE", dec_mode_mux_enum, tx_macro_dec_mode_get, tx_macro_dec_mode_put), @@ -2937,6 +3030,8 @@ static int tx_macro_init(struct snd_soc_component *component) "%s: priv is null for macro!\n", __func__); return -EINVAL; } + tx_priv->lpi_enable = false; + tx_priv->register_event_listener = false; tx_priv->version = bolero_get_version(tx_dev); if (tx_priv->version >= BOLERO_VERSION_2_0) { ret = snd_soc_dapm_new_controls(dapm, diff --git a/asoc/codecs/bolero/va-macro.c b/asoc/codecs/bolero/va-macro.c index d36f8e58f9..68d932f21c 100644 --- a/asoc/codecs/bolero/va-macro.c +++ b/asoc/codecs/bolero/va-macro.c @@ -173,6 +173,7 @@ struct va_macro_priv { bool lpi_enable; bool register_event_listener; int dec_mode[VA_MACRO_NUM_DECIMATORS]; + int disable_afe_wakeup_event_listener; }; static bool va_macro_get_data(struct snd_soc_component *component, @@ -435,7 +436,8 @@ static int va_macro_swr_pwr_event(struct snd_soc_dapm_widget *w, "%s: lpass audio hw enable failed\n", __func__); } - if (va_priv->lpi_enable) { + if (va_priv->lpi_enable && + !va_priv->disable_afe_wakeup_event_listener) { bolero_register_event_listener(component, true); va_priv->register_event_listener = true; } @@ -2992,7 +2994,10 @@ static int va_macro_probe(struct platform_device *pdev) u32 default_clk_id = 0; struct clk *lpass_audio_hw_vote = NULL; u32 is_used_va_swr_gpio = 0; + u32 disable_afe_wakeup_event_listener = 0; const char *is_used_va_swr_gpio_dt = "qcom,is-used-swr-gpio"; + const char *disable_afe_wakeup_event_listener_dt = + "qcom,disable-afe-wakeup-event-listener"; va_priv = devm_kzalloc(&pdev->dev, sizeof(struct va_macro_priv), GFP_KERNEL); @@ -3034,6 +3039,19 @@ static int va_macro_probe(struct platform_device *pdev) is_used_va_swr_gpio = 0; } } + + if (of_find_property(pdev->dev.of_node, + disable_afe_wakeup_event_listener_dt, NULL)) { + ret = of_property_read_u32(pdev->dev.of_node, + disable_afe_wakeup_event_listener_dt, + &disable_afe_wakeup_event_listener); + if (ret) + dev_dbg(&pdev->dev, "%s: error reading %s in dt\n", + __func__, disable_afe_wakeup_event_listener_dt); + } + va_priv->disable_afe_wakeup_event_listener = + disable_afe_wakeup_event_listener; + va_priv->va_swr_gpio_p = of_parse_phandle(pdev->dev.of_node, "qcom,va-swr-gpios", 0); if (!va_priv->va_swr_gpio_p && is_used_va_swr_gpio) { diff --git a/asoc/codecs/bolero/wsa-macro.c b/asoc/codecs/bolero/wsa-macro.c index 22dc5e82e2..f689d3cea5 100644 --- a/asoc/codecs/bolero/wsa-macro.c +++ b/asoc/codecs/bolero/wsa-macro.c @@ -843,6 +843,7 @@ static int wsa_macro_digital_mute(struct snd_soc_dai *dai, int mute) uint16_t j = 0, reg = 0, mix_reg = 0, dsm_reg = 0; u16 int_mux_cfg0 = 0, int_mux_cfg1 = 0; u8 int_mux_cfg0_val = 0, int_mux_cfg1_val = 0; + bool adie_lb = false; if (mute) return 0; @@ -879,7 +880,7 @@ static int wsa_macro_digital_mute(struct snd_soc_dai *dai, int mute) } } } - bolero_wsa_pa_on(wsa_dev); + bolero_wsa_pa_on(wsa_dev, adie_lb); break; default: break; @@ -1470,6 +1471,7 @@ static int wsa_macro_enable_main_path(struct snd_soc_dapm_widget *w, u16 reg = 0; struct device *wsa_dev = NULL; struct wsa_macro_priv *wsa_priv = NULL; + bool adie_lb = false; if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) return -EINVAL; @@ -1480,9 +1482,10 @@ static int wsa_macro_enable_main_path(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: if (wsa_macro_adie_lb(component, w->shift)) { + adie_lb = true; snd_soc_component_update_bits(component, reg, 0x20, 0x20); - bolero_wsa_pa_on(wsa_dev); + bolero_wsa_pa_on(wsa_dev, adie_lb); } break; default: @@ -2561,10 +2564,10 @@ static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = { SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", SND_SOC_NOPM, 0, 0, &rx1_mix_mux, wsa_macro_enable_mix_path, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("WSA_RX INT0 MIX", SND_SOC_NOPM, + SND_SOC_DAPM_PGA_E("WSA_RX INT0 MIX", SND_SOC_NOPM, 0, 0, NULL, 0, wsa_macro_enable_main_path, SND_SOC_DAPM_PRE_PMU), - SND_SOC_DAPM_MIXER_E("WSA_RX INT1 MIX", SND_SOC_NOPM, + SND_SOC_DAPM_PGA_E("WSA_RX INT1 MIX", SND_SOC_NOPM, 1, 0, NULL, 0, wsa_macro_enable_main_path, SND_SOC_DAPM_PRE_PMU), SND_SOC_DAPM_MIXER("WSA_RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), diff --git a/asoc/codecs/msm-cdc-supply.c b/asoc/codecs/msm-cdc-supply.c index 1618b83a55..e7d8680387 100644 --- a/asoc/codecs/msm-cdc-supply.c +++ b/asoc/codecs/msm-cdc-supply.c @@ -173,6 +173,52 @@ bool msm_cdc_is_ondemand_supply(struct device *dev, } EXPORT_SYMBOL(msm_cdc_is_ondemand_supply); +/* + * msm_cdc_set_supply_min_voltage: + * Set min supply voltage for particular supply + * + * @dev: pointer to codec device + * @supplies: pointer to regulator bulk data + * @cdc_vreg: pointer to platform regulator data + * @num_supplies: number of supplies + * @supply_name: Supply name to change voltage for + * @vval_min: Min voltage to be set in uV + * @override_min_vol: True if override min voltage from default + * Return error code if unable to set voltage + */ +int msm_cdc_set_supply_min_voltage(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies, char *supply_name, + int vval_min, bool override_min_vol) +{ + int rc = 0, i; + + if ((!supply_name) || (!supplies)) { + pr_err("%s: either dev or supplies or cdc_vreg is NULL\n", + __func__); + return -EINVAL; + } + /* input parameter validation */ + rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies); + if (rc) + return rc; + for (i = 0; i < num_supplies; i++) { + if (!strcmp(cdc_vreg[i].name, supply_name)) { + if (override_min_vol) + regulator_set_voltage(supplies[i].consumer, + vval_min, cdc_vreg[i].max_uV); + else + regulator_set_voltage(supplies[i].consumer, + cdc_vreg[i].min_uV, cdc_vreg[i].max_uV); + break; + } + } + + return rc; +} +EXPORT_SYMBOL(msm_cdc_set_supply_min_voltage); + /* * msm_cdc_disable_ondemand_supply: * Disable codec ondemand supply diff --git a/asoc/codecs/msm_hdmi_codec_rx.c b/asoc/codecs/msm_hdmi_codec_rx.c index 609dd45ea3..ce4faaea88 100644 --- a/asoc/codecs/msm_hdmi_codec_rx.c +++ b/asoc/codecs/msm_hdmi_codec_rx.c @@ -224,7 +224,7 @@ static int msm_ext_disp_audio_type_get(struct snd_kcontrol *kcontrol, if (!codec_data->ext_disp_ops.get_audio_edid_blk || !codec_data->ext_disp_ops.get_intf_id || rc) { - dev_err(component->dev, "%s: get_audio_edid_blk() or get_intf_id is NULL\n", + dev_err_ratelimited(component->dev, "%s: get_audio_edid_blk() or get_intf_id is NULL\n", __func__); rc = -EINVAL; goto cable_err; diff --git a/asoc/codecs/rouleur/internal.h b/asoc/codecs/rouleur/internal.h index cc1500be70..a8fc83325c 100644 --- a/asoc/codecs/rouleur/internal.h +++ b/asoc/codecs/rouleur/internal.h @@ -85,6 +85,11 @@ struct rouleur_priv { struct mutex main_bias_lock; bool dev_up; bool usbc_hs_status; + struct notifier_block psy_nb; + struct work_struct soc_eval_work; + bool low_soc; + int foundry_id_reg; + int foundry_id; }; struct rouleur_micbias_setting { @@ -102,6 +107,7 @@ struct rouleur_pdata { struct cdc_regulator *regulator; int num_supplies; int reset_reg; + int foundry_id_reg; }; struct wcd_ctrl_platform_data { @@ -131,6 +137,9 @@ enum { WCD_BOLERO_EVT_IMPED_FALSE, /* for imped false */ WCD_BOLERO_EVT_RX_COMPANDER_SOFT_RST, WCD_BOLERO_EVT_BCS_CLK_OFF, + WCD_BOLERO_EVT_RX_PA_GAIN_UPDATE, /* To reduce PA gain for low SoC */ + WCD_BOLERO_EVT_HPHL_HD2_ENABLE, /* to enable hd2 config for hphl */ + WCD_BOLERO_EVT_HPHR_HD2_ENABLE, /* to enable hd2 config for hphr */ }; enum { diff --git a/asoc/codecs/rouleur/pm2250-spmi.h b/asoc/codecs/rouleur/pm2250-spmi.h index 87c913d43d..2eaf28f02c 100644 --- a/asoc/codecs/rouleur/pm2250-spmi.h +++ b/asoc/codecs/rouleur/pm2250-spmi.h @@ -7,11 +7,16 @@ #ifdef CONFIG_PM2250_SPMI int pm2250_spmi_write(struct device *dev, int reg, int value); +int pm2250_spmi_read(struct device *dev, int reg, int *value); #else int pm2250_spmi_write(struct device *dev, int reg, int value) { return 0; } +int pm2250_spmi_read(struct device *dev, int reg, int *value); +{ + return 0; +} #endif /* CONFIG_PM2250_SPMI */ #endif diff --git a/asoc/codecs/rouleur/pm2250_spmi.c b/asoc/codecs/rouleur/pm2250_spmi.c index 1e5f70d177..10a7d109bb 100644 --- a/asoc/codecs/rouleur/pm2250_spmi.c +++ b/asoc/codecs/rouleur/pm2250_spmi.c @@ -25,6 +25,12 @@ static const struct of_device_id pm2250_id_table[] = { }; MODULE_DEVICE_TABLE(of, pm2250_id_table); +/** + * pm2250_spmi_write: Function to write to PMIC register + * @device: node for rouleur device + * @reg: PMIC register to write value + * @value: Value to be written to PMIC register + */ int pm2250_spmi_write(struct device *dev, int reg, int value) { int rc; @@ -47,6 +53,34 @@ int pm2250_spmi_write(struct device *dev, int reg, int value) } EXPORT_SYMBOL(pm2250_spmi_write); +/** + * pm2250_spmi_read: Function to read PMIC register + * @device: node for rouleur device + * @reg: PMIC register to read value + * @value: Pointer to value of reg to be read + */ +int pm2250_spmi_read(struct device *dev, int reg, int *value) +{ + int rc; + struct pm2250_spmi *spmi_dd; + + if (!of_device_is_compatible(dev->of_node, "qcom,pm2250-spmi")) { + pr_err("%s: Device node is invalid\n", __func__); + return -EINVAL; + } + + spmi_dd = dev_get_drvdata(dev); + if (!spmi_dd) + return -EINVAL; + + rc = regmap_read(spmi_dd->regmap, reg, value); + if (rc) + dev_err(dev, "%s: Read from PMIC register failed\n", __func__); + + return rc; +} +EXPORT_SYMBOL(pm2250_spmi_read); + static int pm2250_spmi_probe(struct platform_device *pdev) { struct pm2250_spmi *spmi_dd; diff --git a/asoc/codecs/rouleur/rouleur-mbhc.c b/asoc/codecs/rouleur/rouleur-mbhc.c index c7ba03cd2b..7edfe1fbdd 100644 --- a/asoc/codecs/rouleur/rouleur-mbhc.c +++ b/asoc/codecs/rouleur/rouleur-mbhc.c @@ -36,6 +36,8 @@ #define ROULEUR_HPHL_CROSS_CONN_THRESHOLD 350 #define ROULEUR_HPHR_CROSS_CONN_THRESHOLD 350 +#define IMPED_NUM_RETRY 5 + static struct wcd_mbhc_register wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = { WCD_MBHC_REGISTER("WCD_MBHC_L_DET_EN", @@ -515,6 +517,35 @@ z_right: *zr = zdet; } +static void rouleur_mbhc_impedance_fn(struct snd_soc_component *component, + int32_t *z1L, int32_t *z1R, + int32_t *zl, int32_t *zr) +{ + int i; + for (i = 0; i < IMPED_NUM_RETRY; i++) { + /* Start of left ch impedance calculation */ + rouleur_mbhc_zdet_start(component, z1L, NULL); + if ((*z1L == ROULEUR_ZDET_FLOATING_IMPEDANCE) || + (*z1L > ROULEUR_ZDET_VAL_100K)) + *zl = ROULEUR_ZDET_FLOATING_IMPEDANCE; + else + *zl = *z1L/1000; + + /* Start of right ch impedance calculation */ + rouleur_mbhc_zdet_start(component, NULL, z1R); + if ((*z1R == ROULEUR_ZDET_FLOATING_IMPEDANCE) || + (*z1R > ROULEUR_ZDET_VAL_100K)) + *zr = ROULEUR_ZDET_FLOATING_IMPEDANCE; + else + *zr = *z1R/1000; + } + + dev_dbg(component->dev, "%s: impedance on HPH_L = %d(ohms)\n", + __func__, *zl); + dev_dbg(component->dev, "%s: impedance on HPH_R = %d(ohms)\n", + __func__, *zr); +} + static void rouleur_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, uint32_t *zr) { @@ -564,27 +595,11 @@ static void rouleur_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, /* 1ms delay needed after disable surge protection */ usleep_range(1000, 1010); - /* Start of left ch impedance calculation */ - rouleur_mbhc_zdet_start(component, &z1L, NULL); - if ((z1L == ROULEUR_ZDET_FLOATING_IMPEDANCE) || - (z1L > ROULEUR_ZDET_VAL_100K)) - *zl = ROULEUR_ZDET_FLOATING_IMPEDANCE; - else - *zl = z1L/1000; - - dev_dbg(component->dev, "%s: impedance on HPH_L = %d(ohms)\n", - __func__, *zl); - - /* Start of right ch impedance calculation */ - rouleur_mbhc_zdet_start(component, NULL, &z1R); - if ((z1R == ROULEUR_ZDET_FLOATING_IMPEDANCE) || - (z1R > ROULEUR_ZDET_VAL_100K)) - *zr = ROULEUR_ZDET_FLOATING_IMPEDANCE; - else - *zr = z1R/1000; - - dev_dbg(component->dev, "%s: impedance on HPH_R = %d(ohms)\n", - __func__, *zr); + /* + * Call impedance detection routine multiple times + * in order to avoid wrong impedance values. + */ + rouleur_mbhc_impedance_fn(component, &z1L, &z1R, zl, zr); /* Mono/stereo detection */ if ((*zl == ROULEUR_ZDET_FLOATING_IMPEDANCE) && diff --git a/asoc/codecs/rouleur/rouleur-registers.h b/asoc/codecs/rouleur/rouleur-registers.h index 8cc0ae473a..d890a2ba44 100644 --- a/asoc/codecs/rouleur/rouleur-registers.h +++ b/asoc/codecs/rouleur/rouleur-registers.h @@ -48,6 +48,7 @@ enum { #define ROULEUR_ANA_MBHC_CTL_CLK (ROULEUR_ANA_BASE_ADDR+0x06D) #define ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT (ROULEUR_ANA_BASE_ADDR+0x072) #define ROULEUR_ANA_NCP_EN (ROULEUR_ANA_BASE_ADDR+0x077) +#define ROULEUR_ANA_NCP_VCTRL (ROULEUR_ANA_BASE_ADDR+0x07C) #define ROULEUR_ANA_HPHPA_CNP_CTL_1 (ROULEUR_ANA_BASE_ADDR+0x083) #define ROULEUR_ANA_HPHPA_CNP_CTL_2 (ROULEUR_ANA_BASE_ADDR+0x084) #define ROULEUR_ANA_HPHPA_PA_STATUS (ROULEUR_ANA_BASE_ADDR+0x087) @@ -58,6 +59,8 @@ enum { #define ROULEUR_SWR_HPHPA_HD2 (ROULEUR_ANA_BASE_ADDR+0x090) #define ROULEUR_ANA_SURGE_EN (ROULEUR_ANA_BASE_ADDR+0x097) #define ROULEUR_ANA_COMBOPA_CTL (ROULEUR_ANA_BASE_ADDR+0x09B) +#define ROULEUR_ANA_COMBOPA_CTL_4 (ROULEUR_ANA_BASE_ADDR+0x09F) +#define ROULEUR_ANA_COMBOPA_CTL_5 (ROULEUR_ANA_BASE_ADDR+0x0A0) #define ROULEUR_ANA_RXLDO_CTL (ROULEUR_ANA_BASE_ADDR+0x0B2) #define ROULEUR_ANA_MBIAS_EN (ROULEUR_ANA_BASE_ADDR+0x0B4) diff --git a/asoc/codecs/rouleur/rouleur-regmap.c b/asoc/codecs/rouleur/rouleur-regmap.c index 23b8ddc967..51ed46a3b2 100644 --- a/asoc/codecs/rouleur/rouleur-regmap.c +++ b/asoc/codecs/rouleur/rouleur-regmap.c @@ -41,6 +41,7 @@ static const struct reg_default rouleur_defaults[] = { { ROULEUR_ANA_MBHC_CTL_CLK, 0x30 }, { ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT, 0x00 }, { ROULEUR_ANA_NCP_EN, 0x00 }, + { ROULEUR_ANA_NCP_VCTRL, 0xA7 }, { ROULEUR_ANA_HPHPA_CNP_CTL_1, 0x54 }, { ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x2B }, { ROULEUR_ANA_HPHPA_PA_STATUS, 0x00 }, @@ -51,6 +52,8 @@ static const struct reg_default rouleur_defaults[] = { { ROULEUR_ANA_HPHPA_SPARE_CTL, 0x02 }, { ROULEUR_ANA_SURGE_EN, 0x38 }, { ROULEUR_ANA_COMBOPA_CTL, 0x35 }, + { ROULEUR_ANA_COMBOPA_CTL_4, 0x84 }, + { ROULEUR_ANA_COMBOPA_CTL_5, 0x05 }, { ROULEUR_ANA_RXLDO_CTL, 0x86 }, { ROULEUR_ANA_MBIAS_EN, 0x00 }, { ROULEUR_DIG_SWR_CHIP_ID0, 0x00 }, diff --git a/asoc/codecs/rouleur/rouleur-tables.c b/asoc/codecs/rouleur/rouleur-tables.c index 7912267dac..63604566ab 100644 --- a/asoc/codecs/rouleur/rouleur-tables.c +++ b/asoc/codecs/rouleur/rouleur-tables.c @@ -36,6 +36,7 @@ const u8 rouleur_reg_access_analog[ROULEUR_REG( [ROULEUR_REG(ROULEUR_ANA_MBHC_CTL_CLK)] = RD_WR_REG, [ROULEUR_REG(ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT)] = RD_REG, [ROULEUR_REG(ROULEUR_ANA_NCP_EN)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_NCP_VCTRL)] = RD_WR_REG, [ROULEUR_REG(ROULEUR_ANA_HPHPA_CNP_CTL_1)] = RD_WR_REG, [ROULEUR_REG(ROULEUR_ANA_HPHPA_CNP_CTL_2)] = RD_WR_REG, [ROULEUR_REG(ROULEUR_ANA_HPHPA_PA_STATUS)] = RD_REG, @@ -46,6 +47,8 @@ const u8 rouleur_reg_access_analog[ROULEUR_REG( [ROULEUR_REG(ROULEUR_SWR_HPHPA_HD2)] = RD_WR_REG, [ROULEUR_REG(ROULEUR_ANA_SURGE_EN)] = RD_WR_REG, [ROULEUR_REG(ROULEUR_ANA_COMBOPA_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_COMBOPA_CTL_4)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_COMBOPA_CTL_5)] = RD_WR_REG, [ROULEUR_REG(ROULEUR_ANA_RXLDO_CTL)] = RD_WR_REG, [ROULEUR_REG(ROULEUR_ANA_MBIAS_EN)] = RD_WR_REG, }; diff --git a/asoc/codecs/rouleur/rouleur.c b/asoc/codecs/rouleur/rouleur.c index d2cf31a510..44ec2476a8 100644 --- a/asoc/codecs/rouleur/rouleur.c +++ b/asoc/codecs/rouleur/rouleur.c @@ -26,6 +26,7 @@ #include #include #include +#include #define DRV_NAME "rouleur_codec" @@ -35,6 +36,10 @@ #define ROULEUR_VERSION_ENTRY_SIZE 32 #define NUM_ATTEMPTS 5 +#define SOC_THRESHOLD_LEVEL 25 +#define LOW_SOC_MBIAS_REG_MIN_VOLTAGE 2850000 + +#define FOUNDRY_ID_SEC 0x5 enum { CODEC_TX = 0, @@ -361,6 +366,8 @@ static int rouleur_rx_clk_enable(struct snd_soc_component *component) ROULEUR_ANA_HPHPA_FSM_CLK, 0x7F, 0x11); snd_soc_component_update_bits(component, ROULEUR_ANA_HPHPA_FSM_CLK, 0x80, 0x80); + snd_soc_component_update_bits(component, + ROULEUR_ANA_NCP_VCTRL, 0x07, 0x06); snd_soc_component_update_bits(component, ROULEUR_ANA_NCP_EN, 0x01, 0x01); usleep_range(500, 510); @@ -591,12 +598,12 @@ static int rouleur_codec_ear_lo_dac_event(struct snd_soc_dapm_widget *w, snd_soc_component_update_bits(component, ROULEUR_DIG_SWR_CDC_RX0_CTL, 0x80, 0x00); - snd_soc_component_update_bits(component, - ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL, - 0x04, 0x04); snd_soc_component_update_bits(component, ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x01, 0x01); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL, + 0x04, 0x04); break; case SND_SOC_DAPM_POST_PMD: @@ -635,7 +642,12 @@ static int rouleur_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, true); set_bit(HPH_PA_DELAY, &rouleur->status_mask); - usleep_range(5000, 5100); + usleep_range(200, 210); + /* Enable HD2 Config for HPHR if foundry id is SEC */ + if (rouleur->foundry_id == FOUNDRY_ID_SEC) + rouleur->update_wcd_event(rouleur->handle, + WCD_BOLERO_EVT_HPHR_HD2_ENABLE, + 0x04); snd_soc_component_update_bits(component, ROULEUR_DIG_SWR_PDM_WD_CTL1, 0x03, 0x03); @@ -671,9 +683,8 @@ static int rouleur_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMD: /* - * 7ms sleep is required after PA is disabled as per - * HW requirement. If compander is disabled, then - * 20ms delay is required. + * 5ms sleep is required after PA is disabled as per + * HW requirement. */ if (test_bit(HPH_PA_DELAY, &rouleur->status_mask)) { @@ -681,6 +692,10 @@ static int rouleur_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, clear_bit(HPH_PA_DELAY, &rouleur->status_mask); } + if (rouleur->foundry_id == FOUNDRY_ID_SEC) + rouleur->update_wcd_event(rouleur->handle, + WCD_BOLERO_EVT_HPHR_HD2_ENABLE, + 0x00); blocking_notifier_call_chain(&rouleur->mbhc->notifier, WCD_EVENT_POST_HPHR_PA_OFF, &rouleur->mbhc->wcd_mbhc); @@ -710,7 +725,11 @@ static int rouleur_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, rouleur->rx_swr_dev->dev_num, true); set_bit(HPH_PA_DELAY, &rouleur->status_mask); - usleep_range(5000, 5100); + usleep_range(200, 210); + if (rouleur->foundry_id == FOUNDRY_ID_SEC) + rouleur->update_wcd_event(rouleur->handle, + WCD_BOLERO_EVT_HPHL_HD2_ENABLE, + 0x04); snd_soc_component_update_bits(component, ROULEUR_DIG_SWR_PDM_WD_CTL0, 0x03, 0x03); @@ -754,6 +773,10 @@ static int rouleur_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, clear_bit(HPH_PA_DELAY, &rouleur->status_mask); } + if (rouleur->foundry_id == FOUNDRY_ID_SEC) + rouleur->update_wcd_event(rouleur->handle, + WCD_BOLERO_EVT_HPHL_HD2_ENABLE, + 0x00); blocking_notifier_call_chain(&rouleur->mbhc->notifier, WCD_EVENT_POST_HPHL_PA_OFF, &rouleur->mbhc->wcd_mbhc); @@ -783,18 +806,36 @@ static int rouleur_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev, rouleur->rx_swr_dev->dev_num, true); - usleep_range(5000, 5100); + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL_5, + 0x04, 0x00); + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL_4, + 0x0F, 0x0F); + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL, + 0x40, 0x00); + if (rouleur->foundry_id == FOUNDRY_ID_SEC) + rouleur->update_wcd_event(rouleur->handle, + WCD_BOLERO_EVT_HPHL_HD2_ENABLE, + 0x04); snd_soc_component_update_bits(component, ROULEUR_DIG_SWR_PDM_WD_CTL0, 0x03, 0x03); break; case SND_SOC_DAPM_POST_PMU: + usleep_range(5000, 5100); + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL_4, + 0x0F, 0x04); if (rouleur->update_wcd_event) rouleur->update_wcd_event(rouleur->handle, WCD_BOLERO_EVT_RX_MUTE, (WCD_RX1 << 0x10)); - wcd_enable_irq(&rouleur->irq_info, - ROULEUR_IRQ_HPHL_PDM_WD_INT); + wcd_enable_irq(&rouleur->irq_info, + ROULEUR_IRQ_HPHL_PDM_WD_INT); break; case SND_SOC_DAPM_PRE_PMD: wcd_disable_irq(&rouleur->irq_info, @@ -806,6 +847,10 @@ static int rouleur_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMD: usleep_range(5000, 5100); + if (rouleur->foundry_id == FOUNDRY_ID_SEC) + rouleur->update_wcd_event(rouleur->handle, + WCD_BOLERO_EVT_HPHL_HD2_ENABLE, + 0x00); snd_soc_component_update_bits(component, ROULEUR_DIG_SWR_PDM_WD_CTL0, 0x03, 0x00); @@ -830,24 +875,35 @@ static int rouleur_codec_enable_lo_pa(struct snd_soc_dapm_widget *w, ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev, rouleur->rx_swr_dev->dev_num, true); + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL_5, + 0x04, 0x00); + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL_4, + 0x0F, 0x0F); + usleep_range(1000, 1010); snd_soc_component_update_bits(component, ROULEUR_ANA_COMBOPA_CTL, 0x40, 0x40); - usleep_range(5000, 5100); snd_soc_component_update_bits(component, ROULEUR_DIG_SWR_PDM_WD_CTL0, 0x03, 0x03); break; case SND_SOC_DAPM_POST_PMU: + usleep_range(5000, 5100); + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL_4, + 0x0F, 0x04); if (rouleur->update_wcd_event) rouleur->update_wcd_event(rouleur->handle, WCD_BOLERO_EVT_RX_MUTE, (WCD_RX1 << 0x10)); - wcd_enable_irq(&rouleur->irq_info, - ROULEUR_IRQ_HPHL_PDM_WD_INT); + wcd_enable_irq(&rouleur->irq_info, + ROULEUR_IRQ_HPHL_PDM_WD_INT); break; case SND_SOC_DAPM_PRE_PMD: - wcd_disable_irq(&rouleur->irq_info, + wcd_disable_irq(&rouleur->irq_info, ROULEUR_IRQ_HPHL_PDM_WD_INT); if (rouleur->update_wcd_event) rouleur->update_wcd_event(rouleur->handle, @@ -1400,6 +1456,7 @@ static int rouleur_event_notify(struct notifier_block *block, rouleur_init_reg(component); regcache_mark_dirty(rouleur->regmap); regcache_sync(rouleur->regmap); + rouleur->dev_up = true; /* Initialize MBHC module */ mbhc = &rouleur->mbhc->wcd_mbhc; ret = rouleur_mbhc_post_ssr_init(rouleur->mbhc, component); @@ -1412,7 +1469,6 @@ static int rouleur_event_notify(struct notifier_block *block, mdelay(500); } rouleur->mbhc->wcd_mbhc.deinit_in_progress = false; - rouleur->dev_up = true; break; default: dev_err(component->dev, "%s: invalid event %d\n", __func__, @@ -1974,6 +2030,126 @@ done: return rc; } +static int rouleur_battery_supply_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct power_supply *psy = data; + struct rouleur_priv *rouleur = + container_of(nb, struct rouleur_priv, psy_nb); + + if (strcmp(psy->desc->name, "battery")) + return NOTIFY_OK; + queue_work(system_freezable_wq, &rouleur->soc_eval_work); + + return NOTIFY_OK; +} + +static int rouleur_read_battery_soc(struct rouleur_priv *rouleur, int *soc_val) +{ + static struct power_supply *batt_psy; + union power_supply_propval ret = {0,}; + int err = 0; + + *soc_val = 100; + if (!batt_psy) + batt_psy = power_supply_get_by_name("battery"); + if (batt_psy) { + err = power_supply_get_property(batt_psy, + POWER_SUPPLY_PROP_CAPACITY, &ret); + if (err) { + pr_err("%s: battery SoC read error:%d\n", + __func__, err); + return err; + } + *soc_val = ret.intval; + } + pr_debug("%s: soc:%d\n", __func__, *soc_val); + + return err; +} + +static void rouleur_evaluate_soc(struct work_struct *work) +{ + struct rouleur_priv *rouleur = + container_of(work, struct rouleur_priv, soc_eval_work); + int soc_val = 0, ret = 0; + struct rouleur_pdata *pdata = NULL; + + pdata = dev_get_platdata(rouleur->dev); + if (!pdata) { + dev_err(rouleur->dev, "%s: pdata is NULL\n", __func__); + return; + } + + if (rouleur_read_battery_soc(rouleur, &soc_val) < 0) { + dev_err(rouleur->dev, "%s unable to read battery SoC\n", + __func__); + return; + } + + if (soc_val < SOC_THRESHOLD_LEVEL) { + dev_dbg(rouleur->dev, + "%s battery SoC less than threshold soc_val = %d\n", + __func__, soc_val); + /* Reduce PA Gain by 6DB for low SoC */ + if (rouleur->update_wcd_event) + rouleur->update_wcd_event(rouleur->handle, + WCD_BOLERO_EVT_RX_PA_GAIN_UPDATE, + true); + rouleur->low_soc = true; + ret = msm_cdc_set_supply_min_voltage(rouleur->dev, + rouleur->supplies, + pdata->regulator, + pdata->num_supplies, + "cdc-vdd-mic-bias", + LOW_SOC_MBIAS_REG_MIN_VOLTAGE, + true); + if (ret < 0) + dev_err(rouleur->dev, + "%s unable to set mbias min voltage\n", + __func__); + } else { + if (rouleur->low_soc == true) { + /* Reset PA Gain to default for normal SoC */ + if (rouleur->update_wcd_event) + rouleur->update_wcd_event(rouleur->handle, + WCD_BOLERO_EVT_RX_PA_GAIN_UPDATE, + false); + ret = msm_cdc_set_supply_min_voltage(rouleur->dev, + rouleur->supplies, + pdata->regulator, + pdata->num_supplies, + "cdc-vdd-mic-bias", + LOW_SOC_MBIAS_REG_MIN_VOLTAGE, + false); + if (ret < 0) + dev_err(rouleur->dev, + "%s unable to set mbias min voltage\n", + __func__); + rouleur->low_soc = false; + } + } +} + +static void rouleur_get_foundry_id(struct rouleur_priv *rouleur) +{ + int ret; + + if (rouleur->foundry_id_reg == 0) { + pr_debug("%s: foundry id not defined\n", __func__); + return; + } + + ret = pm2250_spmi_read(rouleur->spmi_dev, + rouleur->foundry_id_reg, &rouleur->foundry_id); + if (ret == 0) + pr_debug("%s: rouleur foundry id = %x\n", rouleur->foundry_id, + __func__); + else + pr_debug("%s: rouleur error in spmi read ret = %d\n", + __func__, ret); +} + static int rouleur_soc_codec_probe(struct snd_soc_component *component) { struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component); @@ -2029,6 +2205,8 @@ static int rouleur_soc_codec_probe(struct snd_soc_component *component) snd_soc_dapm_sync(dapm); rouleur_init_reg(component); + /* Get rouleur foundry id */ + rouleur_get_foundry_id(rouleur); rouleur->version = ROULEUR_VERSION_1_0; /* Register event notifier */ @@ -2044,7 +2222,16 @@ static int rouleur_soc_codec_probe(struct snd_soc_component *component) return ret; } } + rouleur->low_soc = false; rouleur->dev_up = true; + /* Register notifier to change gain based on state of charge */ + INIT_WORK(&rouleur->soc_eval_work, rouleur_evaluate_soc); + rouleur->psy_nb.notifier_call = rouleur_battery_supply_cb; + if (power_supply_reg_notifier(&rouleur->psy_nb) < 0) + dev_dbg(rouleur->dev, + "%s: could not register pwr supply notifier\n", + __func__); + queue_work(system_freezable_wq, &rouleur->soc_eval_work); done: return ret; } @@ -2278,6 +2465,12 @@ struct rouleur_pdata *rouleur_populate_dt_data(struct device *dev) } pdata->reset_reg = reg; + if (of_property_read_u32(dev->of_node, "qcom,foundry-id-reg", ®)) + dev_dbg(dev, "%s: Failed to obtain foundry id\n", + __func__); + else + pdata->foundry_id_reg = reg; + /* Parse power supplies */ msm_cdc_get_power_supplies(dev, &pdata->regulator, &pdata->num_supplies); @@ -2353,6 +2546,7 @@ static int rouleur_bind(struct device *dev) rouleur->spmi_dev = &pdev->dev; rouleur->reset_reg = pdata->reset_reg; + rouleur->foundry_id_reg = pdata->foundry_id_reg; ret = msm_cdc_init_supplies(dev, &rouleur->supplies, pdata->regulator, pdata->num_supplies); if (!rouleur->supplies) { diff --git a/asoc/codecs/swr-dmic.c b/asoc/codecs/swr-dmic.c index e7269e2729..5672d58478 100644 --- a/asoc/codecs/swr-dmic.c +++ b/asoc/codecs/swr-dmic.c @@ -33,6 +33,8 @@ #define NUM_ATTEMPTS 5 #define SWRS_SCP_CONTROL 0x44 +#define MAX_NAME_LEN 40 + static int swr_master_channel_map[] = { ZERO, SWRM_TX1_CH1, @@ -94,6 +96,9 @@ const char *aif_name_list[] = { static int swr_dmic_reset(struct swr_device *pdev); static int swr_dmic_up(struct swr_device *pdev); static int swr_dmic_down(struct swr_device *pdev); +static int swr_dmic_event_notify(struct notifier_block *block, + unsigned long val, + void *data); static inline int swr_dmic_tx_get_slave_port_type_idx(const char *wname, unsigned int *port_idx) @@ -269,23 +274,41 @@ static const struct snd_kcontrol_new dmic_switch[] = { SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) }; +static const struct snd_kcontrol_new va_dmic_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + static const struct snd_soc_dapm_widget swr_dmic_dapm_widgets[] = { SND_SOC_DAPM_MIXER_E("SWR_DMIC_MIXER", SND_SOC_NOPM, 0, 0, dmic_switch, ARRAY_SIZE(dmic_switch), dmic_swr_ctrl, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("SWR_DMIC_VA_MIXER", SND_SOC_NOPM, 0, 0, + va_dmic_switch, ARRAY_SIZE(va_dmic_switch), dmic_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_INPUT("SWR_DMIC"), + SND_SOC_DAPM_INPUT("VA_SWR_DMIC"), SND_SOC_DAPM_OUT_DRV_E("SMIC_PORT_EN", SND_SOC_NOPM, 0, 0, NULL, 0, swr_dmic_port_enable, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_OUT_DRV_E("SMIC_VA_PORT_EN", SND_SOC_NOPM, 0, 0, NULL, 0, + swr_dmic_port_enable, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_OUTPUT("SWR_DMIC_OUTPUT"), + SND_SOC_DAPM_OUTPUT("SWR_DMIC_VA_OUTPUT"), }; static const struct snd_soc_dapm_route swr_dmic_audio_map[] = { {"SWR_DMIC_MIXER", "Switch", "SWR_DMIC"}, {"SMIC_PORT_EN", NULL, "SWR_DMIC_MIXER"}, {"SWR_DMIC_OUTPUT", NULL, "SMIC_PORT_EN"}, + {"SWR_DMIC_VA_MIXER", "Switch", "VA_SWR_DMIC"}, + {"SMIC_VA_PORT_EN", NULL, "SWR_DMIC_VA_MIXER"}, + {"SWR_DMIC_VA_OUTPUT", NULL, "SMIC_VA_PORT_EN"}, }; static int swr_dmic_codec_probe(struct snd_soc_component *component) @@ -294,36 +317,45 @@ static int swr_dmic_codec_probe(struct snd_soc_component *component) snd_soc_component_get_drvdata(component); struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); - char w_name[100]; + char w_name[MAX_NAME_LEN]; if (!swr_dmic) return -EINVAL; swr_dmic->component = component; - snd_soc_dapm_ignore_suspend(dapm, - swr_dmic->dai_driver->capture.stream_name); - memset(w_name, 0, 100); - strlcpy(w_name, component->name_prefix, 100); - strlcat(w_name, " SWR_DMIC", 100); + if (!component->name_prefix) { + dev_err(component->dev, "%s: component prefix is NULL\n", __func__); + return -EPROBE_DEFER; + } + + memset(w_name, 0, sizeof(w_name)); + strlcpy(w_name, component->name_prefix, sizeof(w_name)); + strlcat(w_name, " ", sizeof(w_name)); + strlcat(w_name, swr_dmic->dai_driver->capture.stream_name, + sizeof(w_name)); snd_soc_dapm_ignore_suspend(dapm, w_name); - memset(w_name, 0, 100); - strlcpy(w_name, component->name_prefix, 100); - strlcat(w_name, " SMIC_SUPPLY", 100); + memset(w_name, 0, sizeof(w_name)); + strlcpy(w_name, component->name_prefix, sizeof(w_name)); + strlcat(w_name, " SWR_DMIC", sizeof(w_name)); snd_soc_dapm_ignore_suspend(dapm, w_name); - memset(w_name, 0, 100); - strlcpy(w_name, component->name_prefix, 100); - strlcat(w_name, " SMIC_PORT_EN", 100); + memset(w_name, 0, sizeof(w_name)); + strlcpy(w_name, component->name_prefix, sizeof(w_name)); + strlcat(w_name, " SMIC_PORT_EN", sizeof(w_name)); snd_soc_dapm_ignore_suspend(dapm, w_name); - memset(w_name, 0, 100); - strlcpy(w_name, component->name_prefix, 100); - strlcat(w_name, " SWR_DMIC_OUTPUT", 100); + memset(w_name, 0, sizeof(w_name)); + strlcpy(w_name, component->name_prefix, sizeof(w_name)); + strlcat(w_name, " SWR_DMIC_OUTPUT", sizeof(w_name)); snd_soc_dapm_ignore_suspend(dapm, w_name); snd_soc_dapm_sync(dapm); + swr_dmic->nblock.notifier_call = swr_dmic_event_notify; + wcd938x_swr_dmic_register_notifier(swr_dmic->supply_component, + &swr_dmic->nblock, true); + return 0; } @@ -472,6 +504,8 @@ static int swr_dmic_probe(struct swr_device *pdev) ret = enable_wcd_codec_supply(swr_dmic, true); if (ret) { ret = -EPROBE_DEFER; + swr_dmic->is_wcd_supply = false; + swr_dmic->wcd_handle = NULL; goto err; } ++swr_dmic->is_en_supply; @@ -516,11 +550,17 @@ static int swr_dmic_probe(struct swr_device *pdev) "%s get devnum %d for dev addr %llx failed\n", __func__, swr_devnum, pdev->addr); ret = -EPROBE_DEFER; - goto dev_err; + + if (swr_dmic->is_en_supply == 1) { + enable_wcd_codec_supply(swr_dmic, false); + --swr_dmic->is_en_supply; + } + swr_dmic->is_wcd_supply = false; + swr_dmic->wcd_handle = NULL; + goto err; } pdev->dev_num = swr_devnum; - swr_dmic->driver = devm_kzalloc(&pdev->dev, sizeof(struct snd_soc_component_driver), GFP_KERNEL); if (!swr_dmic->driver) { @@ -586,10 +626,6 @@ static int swr_dmic_probe(struct swr_device *pdev) strlen(swr_dmic_name_prefix_of) + 1); component->name_prefix = prefix_name; - swr_dmic->nblock.notifier_call = swr_dmic_event_notify; - wcd938x_swr_dmic_register_notifier(swr_dmic->supply_component, - &swr_dmic->nblock, true); - return 0; dev_err: diff --git a/asoc/codecs/swr-haptics.c b/asoc/codecs/swr-haptics.c index 4e1a576930..dcfeb39dd0 100644 --- a/asoc/codecs/swr-haptics.c +++ b/asoc/codecs/swr-haptics.c @@ -456,48 +456,33 @@ static int swr_haptics_device_down(struct swr_device *sdev) static int swr_haptics_suspend(struct device *dev) { struct swr_haptics_dev *swr_hap; - int rc; + int rc = 0; swr_hap = swr_get_dev_data(to_swr_device(dev)); if (!swr_hap) { dev_err(dev, "%s: no data for swr_hap\n", __func__); return -ENODEV; } + trace_printk("%s: suspended\n", __func__); - /* Put SWR slave into reset */ - rc = regulator_disable(swr_hap->vdd); - if (rc < 0) { - dev_err(swr_hap->dev, "%s: disable swr-slave failed, rc=%d\n", - __func__, rc); - return rc; - } - - return 0; + return rc; } static int swr_haptics_resume(struct device *dev) { struct swr_haptics_dev *swr_hap; - int rc; + int rc = 0; swr_hap = swr_get_dev_data(to_swr_device(dev)); if (!swr_hap) { dev_err(dev, "%s: no data for swr_hap\n", __func__); return -ENODEV; } + trace_printk("%s: resumed\n", __func__); - /* Take SWR slave out of reset */ - rc = regulator_enable(swr_hap->vdd); - if (rc < 0) { - dev_err(swr_hap->dev, "%s: enable swr-slave failed, rc=%d\n", - __func__, rc); - return rc; - } - - return 0; + return rc; } - static const struct of_device_id swr_haptics_match_table[] = { { .compatible = "qcom,swr-haptics", }, { .compatible = "qcom,pm8350b-swr-haptics", }, diff --git a/asoc/codecs/wcd937x/wcd937x.c b/asoc/codecs/wcd937x/wcd937x.c index daf7a3d7a2..0023351156 100644 --- a/asoc/codecs/wcd937x/wcd937x.c +++ b/asoc/codecs/wcd937x/wcd937x.c @@ -26,8 +26,6 @@ #include "wcd937x.h" #include "internal.h" -#define DRV_NAME "wcd937x_codec" - #define WCD9370_VARIANT 0 #define WCD9375_VARIANT 5 #define WCD937X_VARIANT_ENTRY_SIZE 32 @@ -40,6 +38,18 @@ #define NUM_ATTEMPTS 5 +#define WCD937X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\ + SNDRV_PCM_RATE_384000) +/* Fractional Rates */ +#define WCD937X_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800) + +#define WCD937X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) + enum { CODEC_TX = 0, CODEC_RX, @@ -91,12 +101,39 @@ static struct regmap_irq_chip wcd937x_regmap_irq_chip = { .mask_base = WCD937X_DIGITAL_INTR_MASK_0, .ack_base = WCD937X_DIGITAL_INTR_CLEAR_0, .use_ack = 1, +#if IS_ENABLED(CONFIG_AUDIO_QGKI) .clear_ack = 1, +#endif .type_base = WCD937X_DIGITAL_INTR_LEVEL_0, .runtime_pm = false, .handle_post_irq = wcd937x_handle_post_irq, .irq_drv_data = NULL, }; + +static struct snd_soc_dai_driver wcd937x_dai[] = { + { + .name = "wcd937x_cdc", + .playback = { + .stream_name = "WCD937X_AIF Playback", + .rates = WCD937X_RATES | WCD937X_FRAC_RATES, + .formats = WCD937X_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .capture = { + .stream_name = "WCD937X_AIF Capture", + .rates = WCD937X_RATES, + .formats = WCD937X_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + }, +}; + static int wcd937x_handle_post_irq(void *data) { struct wcd937x_priv *wcd937x = data; @@ -278,7 +315,7 @@ static int wcd937x_tx_connect_port(struct snd_soc_component *component, u8 ch_mask; u32 ch_rate; u8 ch_type = 0; - int slave_port_idx; + int slave_ch_idx; u8 num_port = 1; int ret = 0; @@ -2195,6 +2232,14 @@ static const struct snd_soc_dapm_widget wcd937x_dapm_widgets[] = { SND_SOC_DAPM_INPUT("IN2_HPHR"), SND_SOC_DAPM_INPUT("IN3_AUX"), + /* + * These dummy widgets are null connected to WCD937x dapm input and + * output widgets which are not actual path endpoints. This ensures + * dapm doesnt set these dapm input and output widgets as endpoints. + */ + SND_SOC_DAPM_INPUT("WCD_TX_DUMMY"), + SND_SOC_DAPM_OUTPUT("WCD_RX_DUMMY"), + /*tx widgets*/ SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0, wcd937x_codec_enable_adc, @@ -2224,15 +2269,15 @@ static const struct snd_soc_dapm_widget wcd937x_dapm_widgets[] = { SND_SOC_DAPM_POST_PMD), /* micbias widgets*/ - SND_SOC_DAPM_MICBIAS_E("MIC BIAS1", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, 0, 0, wcd937x_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MICBIAS_E("MIC BIAS2", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, 0, 0, wcd937x_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MICBIAS_E("MIC BIAS3", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, 0, 0, wcd937x_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), @@ -2316,15 +2361,15 @@ static const struct snd_soc_dapm_widget wcd937x_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("HPHR"), /* micbias pull up widgets*/ - SND_SOC_DAPM_MICBIAS_E("VA MIC BIAS1", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, 0, 0, wcd937x_codec_enable_micbias_pullup, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MICBIAS_E("VA MIC BIAS2", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_SUPPLY("VA MIC BIAS2", SND_SOC_NOPM, 0, 0, wcd937x_codec_enable_micbias_pullup, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MICBIAS_E("VA MIC BIAS3", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_SUPPLY("VA MIC BIAS3", SND_SOC_NOPM, 0, 0, wcd937x_codec_enable_micbias_pullup, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), @@ -2405,6 +2450,7 @@ static const struct snd_soc_dapm_widget wcd9375_dapm_widgets[] = { }; static const struct snd_soc_dapm_route wcd937x_audio_map[] = { + {"WCD_TX_DUMMY", NULL, "WCD_TX_OUTPUT"}, {"WCD_TX_OUTPUT", NULL, "ADC1_MIXER"}, {"ADC1_MIXER", "Switch", "ADC1 REQ"}, {"ADC1 REQ", NULL, "ADC1"}, @@ -2417,6 +2463,7 @@ static const struct snd_soc_dapm_route wcd937x_audio_map[] = { {"ADC2 MUX", "INP3", "AMIC3"}, {"ADC2 MUX", "INP2", "AMIC2"}, + {"IN1_HPHL", NULL, "WCD_RX_DUMMY"}, {"IN1_HPHL", NULL, "VDD_BUCK"}, {"IN1_HPHL", NULL, "CLS_H_PORT"}, {"RX1", NULL, "IN1_HPHL"}, @@ -2425,6 +2472,7 @@ static const struct snd_soc_dapm_route wcd937x_audio_map[] = { {"HPHL PGA", NULL, "HPHL_RDAC"}, {"HPHL", NULL, "HPHL PGA"}, + {"IN2_HPHR", NULL, "WCD_RX_DUMMY"}, {"IN2_HPHR", NULL, "VDD_BUCK"}, {"IN2_HPHR", NULL, "CLS_H_PORT"}, {"RX2", NULL, "IN2_HPHR"}, @@ -2433,6 +2481,7 @@ static const struct snd_soc_dapm_route wcd937x_audio_map[] = { {"HPHR PGA", NULL, "HPHR_RDAC"}, {"HPHR", NULL, "HPHR PGA"}, + {"IN3_AUX", NULL, "WCD_RX_DUMMY"}, {"IN3_AUX", NULL, "VDD_BUCK"}, {"IN3_AUX", NULL, "CLS_H_PORT"}, {"RX3", NULL, "IN3_AUX"}, @@ -2451,6 +2500,7 @@ static const struct snd_soc_dapm_route wcd937x_audio_map[] = { static const struct snd_soc_dapm_route wcd9375_audio_map[] = { + {"WCD_TX_DUMMY", NULL, "WCD_TX_OUTPUT"}, {"WCD_TX_OUTPUT", NULL, "ADC3_MIXER"}, {"ADC3_OUTPUT", NULL, "ADC3_MIXER"}, {"ADC3_MIXER", "Switch", "ADC3 REQ"}, @@ -2576,19 +2626,25 @@ int wcd937x_info_create_codec_entry(struct snd_info_entry *codec_root, return 0; } card = component->card; - priv->entry = snd_info_create_subdir(codec_root->module, + priv->entry = snd_info_create_module_entry(codec_root->module, "wcd937x", codec_root); if (!priv->entry) { dev_dbg(component->dev, "%s: failed to create wcd937x entry\n", __func__); return -ENOMEM; } + priv->entry->mode = S_IFDIR | 0555; + if (snd_info_register(priv->entry) < 0) { + snd_info_free_entry(priv->entry); + return -ENOMEM; + } version_entry = snd_info_create_card_entry(card->snd_card, "version", priv->entry); if (!version_entry) { dev_dbg(component->dev, "%s: failed to create wcd937x version entry\n", __func__); + snd_info_free_entry(priv->entry); return -ENOMEM; } @@ -2599,6 +2655,7 @@ int wcd937x_info_create_codec_entry(struct snd_info_entry *codec_root, if (snd_info_register(version_entry) < 0) { snd_info_free_entry(version_entry); + snd_info_free_entry(priv->entry); return -ENOMEM; } priv->version_entry = version_entry; @@ -2610,6 +2667,8 @@ int wcd937x_info_create_codec_entry(struct snd_info_entry *codec_root, dev_dbg(component->dev, "%s: failed to create wcd937x variant entry\n", __func__); + snd_info_free_entry(version_entry); + snd_info_free_entry(priv->entry); return -ENOMEM; } @@ -2620,6 +2679,8 @@ int wcd937x_info_create_codec_entry(struct snd_info_entry *codec_root, if (snd_info_register(variant_entry) < 0) { snd_info_free_entry(variant_entry); + snd_info_free_entry(version_entry); + snd_info_free_entry(priv->entry); return -ENOMEM; } priv->variant_entry = variant_entry; @@ -2713,6 +2774,8 @@ static int wcd937x_soc_codec_probe(struct snd_soc_component *component) snd_soc_dapm_ignore_suspend(dapm, "AUX"); snd_soc_dapm_ignore_suspend(dapm, "HPHL"); snd_soc_dapm_ignore_suspend(dapm, "HPHR"); + snd_soc_dapm_ignore_suspend(dapm, "WCD_TX_DUMMY"); + snd_soc_dapm_ignore_suspend(dapm, "WCD_RX_DUMMY"); snd_soc_dapm_sync(dapm); wcd_cls_h_init(&wcd937x->clsh_info); @@ -2781,7 +2844,7 @@ static void wcd937x_soc_codec_remove(struct snd_soc_component *component) } static const struct snd_soc_component_driver soc_codec_dev_wcd937x = { - .name = DRV_NAME, + .name = WCD937X_DRV_NAME, .probe = wcd937x_soc_codec_probe, .remove = wcd937x_soc_codec_remove, .controls = wcd937x_snd_controls, @@ -3185,7 +3248,7 @@ static int wcd937x_bind(struct device *dev) wcd_disable_irq(&wcd937x->irq_info, WCD937X_IRQ_AUX_PDM_WD_INT); ret = snd_soc_register_component(dev, &soc_codec_dev_wcd937x, - NULL, 0); + wcd937x_dai, ARRAY_SIZE(wcd937x_dai)); if (ret) { dev_err(dev, "%s: Codec registration failed\n", __func__); diff --git a/asoc/codecs/wcd937x/wcd937x.h b/asoc/codecs/wcd937x/wcd937x.h index 3d35f82f18..5ec1ac204f 100644 --- a/asoc/codecs/wcd937x/wcd937x.h +++ b/asoc/codecs/wcd937x/wcd937x.h @@ -10,12 +10,14 @@ #define WCD937X_MAX_SLAVE_CH_TYPES 10 #define ZERO 0 -struct swr_slave_ch_map { +#define WCD937X_DRV_NAME "wcd937x_codec" + +struct wcd937x_swr_slave_ch_map { u8 ch_type; u8 index; }; -static const struct swr_slave_ch_map swr_slv_tx_ch_idx[] = { +static const struct wcd937x_swr_slave_ch_map wcd937x_swr_slv_tx_ch_idx[] = { {ADC1, 0}, {ADC2, 1}, {ADC3, 2}, @@ -28,7 +30,7 @@ static const struct swr_slave_ch_map swr_slv_tx_ch_idx[] = { {DMIC5, 9}, }; -static int swr_master_ch_map[] = { +static int wcd937x_swr_master_ch_map[] = { ZERO, SWRM_TX1_CH1, SWRM_TX1_CH2, @@ -54,14 +56,14 @@ static inline int wcd937x_slave_get_master_ch_val(int ch) int i; for (i = 0; i < WCD937X_MAX_SLAVE_CH_TYPES; i++) - if (ch == swr_master_ch_map[i]) + if (ch == wcd937x_swr_master_ch_map[i]) return i; return 0; } static inline int wcd937x_slave_get_master_ch(int idx) { - return swr_master_ch_map[idx]; + return wcd937x_swr_master_ch_map[idx]; } static inline int wcd937x_slave_get_slave_ch_val(int ch) @@ -69,8 +71,8 @@ static inline int wcd937x_slave_get_slave_ch_val(int ch) int i; for (i = 0; i < WCD937X_MAX_SLAVE_CH_TYPES; i++) - if (ch == swr_slv_tx_ch_idx[i].ch_type) - return swr_slv_tx_ch_idx[i].index; + if (ch == wcd937x_swr_slv_tx_ch_idx[i].ch_type) + return wcd937x_swr_slv_tx_ch_idx[i].index; return -EINVAL; } diff --git a/asoc/codecs/wcd938x/internal.h b/asoc/codecs/wcd938x/internal.h index dc668e95a0..db5d33da17 100644 --- a/asoc/codecs/wcd938x/internal.h +++ b/asoc/codecs/wcd938x/internal.h @@ -69,6 +69,7 @@ struct wcd938x_priv { u32 hph_mode; u32 tx_mode[TX_ADC_MAX]; + s32 adc_count; bool comp1_enable; bool comp2_enable; bool ldoh; diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c index fbea986e18..5880ecff29 100644 --- a/asoc/codecs/wcd938x/wcd938x.c +++ b/asoc/codecs/wcd938x/wcd938x.c @@ -105,6 +105,7 @@ static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); static int wcd938x_handle_post_irq(void *data); static int wcd938x_reset(struct device *dev); static int wcd938x_reset_low(struct device *dev); +static int wcd938x_get_adc_mode(int val); static const struct regmap_irq wcd938x_irqs[WCD938X_NUM_IRQS] = { REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x01), @@ -1412,8 +1413,7 @@ static int wcd938x_codec_enable_dmic(struct snd_soc_dapm_widget *w, true); break; case SND_SOC_DAPM_POST_PMD: - ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev, - wcd938x->tx_swr_dev->dev_num, + wcd938x_tx_connect_port(component, DMIC0 + (w->shift), 0, false); snd_soc_component_update_bits(component, WCD938X_DIGITAL_CDC_AMIC_CTL, @@ -1542,8 +1542,47 @@ static int wcd938x_tx_swr_ctrl(struct snd_soc_dapm_widget *w, bank = (wcd938x_swr_slv_get_current_bank(wcd938x->tx_swr_dev, wcd938x->tx_swr_dev->dev_num) ? 0 : 1); + /* power mode is applicable only to analog mics */ + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + /* Get channel rate */ + rate = wcd938x_get_clk_rate(wcd938x->tx_mode[w->shift - ADC1]); + } + switch (event) { case SND_SOC_DAPM_PRE_PMU: + /* Check AMIC2 is connected to ADC2 to take an action on BCS */ + if (w->shift == ADC2 && !(snd_soc_component_read32(component, + WCD938X_TX_NEW_AMIC_MUX_CFG) & 0x80)) { + if (!wcd938x->bcs_dis) + wcd938x_tx_connect_port(component, MBHC, + SWR_CLK_RATE_4P8MHZ, true); + set_bit(AMIC2_BCS_ENABLE, &wcd938x->status_mask); + } + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + set_bit(w->shift - ADC1, &wcd938x->status_mask); + wcd938x_tx_connect_port(component, w->shift, rate, + true); + } else { + wcd938x_tx_connect_port(component, w->shift, + SWR_CLK_RATE_2P4MHZ, true); + } + break; + case SND_SOC_DAPM_POST_PMD: + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + if (strnstr(w->name, "ADC1", sizeof("ADC1"))) { + clear_bit(WCD_ADC1, &wcd938x->status_mask); + clear_bit(WCD_ADC1_MODE, &wcd938x->status_mask); + } else if (strnstr(w->name, "ADC2", sizeof("ADC2"))) { + clear_bit(WCD_ADC2, &wcd938x->status_mask); + clear_bit(WCD_ADC2_MODE, &wcd938x->status_mask); + } else if (strnstr(w->name, "ADC3", sizeof("ADC3"))) { + clear_bit(WCD_ADC3, &wcd938x->status_mask); + clear_bit(WCD_ADC3_MODE, &wcd938x->status_mask); + } else if (strnstr(w->name, "ADC4", sizeof("ADC4"))) { + clear_bit(WCD_ADC4, &wcd938x->status_mask); + clear_bit(WCD_ADC4_MODE, &wcd938x->status_mask); + } + } if (strnstr(w->name, "ADC", sizeof("ADC"))) { if (test_bit(WCD_ADC1, &wcd938x->status_mask) || test_bit(WCD_ADC1_MODE, &wcd938x->status_mask)) @@ -1567,49 +1606,19 @@ static int wcd938x_tx_swr_ctrl(struct snd_soc_dapm_widget *w, } } rate = wcd938x_get_clk_rate(i); + if (wcd938x->adc_count) { + rate = (wcd938x->adc_count * rate); + if (rate > SWR_CLK_RATE_9P6MHZ) + rate = SWR_CLK_RATE_9P6MHZ; + } wcd938x_set_swr_clk_rate(component, rate, bank); } - if (w->shift == ADC2 && !(snd_soc_component_read32(component, - WCD938X_TX_NEW_AMIC_MUX_CFG) & 0x80)) { - if (!wcd938x->bcs_dis) - wcd938x_tx_connect_port(component, MBHC, - SWR_CLK_RATE_4P8MHZ, true); - set_bit(AMIC2_BCS_ENABLE, &wcd938x->status_mask); - } - if (strnstr(w->name, "ADC", sizeof("ADC"))) { - wcd938x_tx_connect_port(component, w->shift, rate, - true); - /* Copy clk settings to active bank */ - wcd938x_set_swr_clk_rate(component, rate, !bank); - } else { - wcd938x_tx_connect_port(component, w->shift, - SWR_CLK_RATE_2P4MHZ, true); - } - break; - case SND_SOC_DAPM_POST_PMD: - if (strnstr(w->name, "ADC", sizeof("ADC"))) { - rate = wcd938x_get_clk_rate(ADC_MODE_INVALID); - wcd938x_set_swr_clk_rate(component, rate, !bank); - } - wcd938x_tx_connect_port(component, w->shift, 0, false); - if (w->shift == ADC2 && - test_bit(AMIC2_BCS_ENABLE, &wcd938x->status_mask)) { - if (!wcd938x->bcs_dis) - wcd938x_tx_connect_port(component, MBHC, 0, - false); - clear_bit(AMIC2_BCS_ENABLE, &wcd938x->status_mask); - } + ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev, + wcd938x->tx_swr_dev->dev_num, + false); if (strnstr(w->name, "ADC", sizeof("ADC"))) - wcd938x_set_swr_clk_rate(component, rate, bank); - if (strnstr(w->name, "ADC1", sizeof("ADC1"))) - clear_bit(WCD_ADC1_MODE, &wcd938x->status_mask); - else if (strnstr(w->name, "ADC2", sizeof("ADC2"))) - clear_bit(WCD_ADC2_MODE, &wcd938x->status_mask); - else if (strnstr(w->name, "ADC3", sizeof("ADC3"))) - clear_bit(WCD_ADC3_MODE, &wcd938x->status_mask); - else if (strnstr(w->name, "ADC4", sizeof("ADC4"))) - clear_bit(WCD_ADC4_MODE, &wcd938x->status_mask); + wcd938x_set_swr_clk_rate(component, rate, !bank); break; }; @@ -1697,7 +1706,91 @@ static int wcd938x_codec_enable_adc(struct snd_soc_dapm_widget *w, snd_soc_dapm_to_component(w->dapm); struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); int clk_rate = 0, ret = 0; - int mode; + int mode = 0, i = 0, bank = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + bank = (wcd938x_swr_slv_get_current_bank(wcd938x->tx_swr_dev, + wcd938x->tx_swr_dev->dev_num) ? 0 : 1); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd938x->adc_count++; + if (test_bit(WCD_ADC1, &wcd938x->status_mask) || + test_bit(WCD_ADC1_MODE, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC1]]; + if (test_bit(WCD_ADC2, &wcd938x->status_mask) || + test_bit(WCD_ADC2_MODE, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC2]]; + if (test_bit(WCD_ADC3, &wcd938x->status_mask) || + test_bit(WCD_ADC3_MODE, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC3]]; + if (test_bit(WCD_ADC4, &wcd938x->status_mask) || + test_bit(WCD_ADC4_MODE, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC4]]; + + if (mode != 0) { + for (i = 0; i < ADC_MODE_ULP2; i++) { + if (mode & (1 << i)) { + i++; + break; + } + } + } + clk_rate = wcd938x_get_clk_rate(i); + + /* clk_rate depends on number of paths getting enabled */ + clk_rate = (wcd938x->adc_count * clk_rate); + if (clk_rate > SWR_CLK_RATE_9P6MHZ) + clk_rate = SWR_CLK_RATE_9P6MHZ; + wcd938x_set_swr_clk_rate(component, clk_rate, bank); + ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev, + wcd938x->tx_swr_dev->dev_num, + true); + wcd938x_set_swr_clk_rate(component, clk_rate, !bank); + break; + case SND_SOC_DAPM_POST_PMD: + wcd938x->adc_count--; + if (wcd938x->adc_count < 0) + wcd938x->adc_count = 0; + + wcd938x_tx_connect_port(component, ADC1 + w->shift, 0, false); + if (w->shift + ADC1 == ADC2 && + test_bit(AMIC2_BCS_ENABLE, &wcd938x->status_mask)) { + if (!wcd938x->bcs_dis) + wcd938x_tx_connect_port(component, MBHC, 0, + false); + clear_bit(AMIC2_BCS_ENABLE, &wcd938x->status_mask); + } + break; + }; + + return ret; +} + +void wcd938x_disable_bcs_before_slow_insert(struct snd_soc_component *component, + bool bcs_disable) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + if (wcd938x->update_wcd_event) { + if (bcs_disable) + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_BCS_CLK_OFF, 0); + else + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_BCS_CLK_OFF, 1); + } +} + +static int wcd938x_enable_req(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = + snd_soc_component_get_drvdata(component); + int ret = 0; + u8 mode = 0; dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, w->name, event); @@ -1708,11 +1801,12 @@ static int wcd938x_codec_enable_adc(struct snd_soc_dapm_widget *w, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x08, 0x08); snd_soc_component_update_bits(component, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10); - set_bit(w->shift, &wcd938x->status_mask); - clk_rate = wcd938x_get_clk_rate(wcd938x->tx_mode[w->shift]); - ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev, - wcd938x->tx_swr_dev->dev_num, - true); + + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_REQ_CTL, 0x02, 0x02); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_REQ_CTL, 0x01, 0x00); + ret = wcd938x_tx_channel_config(component, w->shift, 1); mode = wcd938x_get_adc_mode(wcd938x->tx_mode[w->shift]); if (mode < 0) { @@ -1788,53 +1882,9 @@ static int wcd938x_codec_enable_adc(struct snd_soc_dapm_widget *w, default: break; } - ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev, - wcd938x->tx_swr_dev->dev_num, - false); - snd_soc_component_update_bits(component, - WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x08, 0x00); - clear_bit(w->shift, &wcd938x->status_mask); - break; - }; - - return ret; -} - -void wcd938x_disable_bcs_before_slow_insert(struct snd_soc_component *component, - bool bcs_disable) -{ - struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); - - if (wcd938x->update_wcd_event) { - if (bcs_disable) - wcd938x->update_wcd_event(wcd938x->handle, - WCD_BOLERO_EVT_BCS_CLK_OFF, 0); - else - wcd938x->update_wcd_event(wcd938x->handle, - WCD_BOLERO_EVT_BCS_CLK_OFF, 1); - } -} - -static int wcd938x_enable_req(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_component *component = - snd_soc_dapm_to_component(w->dapm); - int ret = 0; - - dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, - w->name, event); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - snd_soc_component_update_bits(component, - WCD938X_DIGITAL_CDC_REQ_CTL, 0x02, 0x02); - snd_soc_component_update_bits(component, - WCD938X_DIGITAL_CDC_REQ_CTL, 0x01, 0x00); - break; - case SND_SOC_DAPM_POST_PMD: - snd_soc_component_update_bits(component, - WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00); + if (wcd938x->adc_count == 0) + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00); break; }; return ret; diff --git a/asoc/codecs/wsa881x-analog.c b/asoc/codecs/wsa881x-analog.c index a68f918c9d..690d5d1b67 100644 --- a/asoc/codecs/wsa881x-analog.c +++ b/asoc/codecs/wsa881x-analog.c @@ -35,6 +35,19 @@ #define SPK_GAIN_12DB 4 #define WIDGET_NAME_MAX_SIZE 80 +#define MAX_NAME_LEN 30 +#define WSA881X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\ + SNDRV_PCM_RATE_384000) +/* Fractional Rates */ +#define WSA881X_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800) + +#define WSA881X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) + /* * Private data Structure for wsa881x. All parameters related to * WSA881X codec needs to be defined here. @@ -66,6 +79,9 @@ struct wsa881x_pdata { struct device_node *wsa_vi_gpio_p; struct device_node *wsa_clk_gpio_p; struct device_node *wsa_reset_gpio_p; + char *wsa881x_name_prefix; + struct snd_soc_dai_driver *dai_driver; + struct snd_soc_component_driver *driver; }; enum { @@ -1130,8 +1146,6 @@ static int wsa881x_probe(struct snd_soc_component *component) struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); char *widget_name = NULL; - struct snd_soc_card *card = component->card; - struct snd_soc_codec_conf *codec_conf = card->codec_conf; client = dev_get_drvdata(component->dev); ret = wsa881x_i2c_get_client_index(client, &wsa881x_index); @@ -1155,17 +1169,17 @@ static int wsa881x_probe(struct snd_soc_component *component) INIT_DELAYED_WORK(&wsa_pdata[wsa881x_index].ocp_ctl_work, wsa881x_ocp_ctl_work); - if (codec_conf->name_prefix) { + if (component->name_prefix) { widget_name = kcalloc(WIDGET_NAME_MAX_SIZE, sizeof(char), GFP_KERNEL); if (!widget_name) return -ENOMEM; snprintf(widget_name, WIDGET_NAME_MAX_SIZE, - "%s WSA_SPKR", codec_conf->name_prefix); + "%s WSA_SPKR", component->name_prefix); snd_soc_dapm_ignore_suspend(dapm, widget_name); snprintf(widget_name, WIDGET_NAME_MAX_SIZE, - "%s WSA_IN", codec_conf->name_prefix); + "%s WSA_IN", component->name_prefix); snd_soc_dapm_ignore_suspend(dapm, widget_name); kfree(widget_name); } else { @@ -1190,7 +1204,8 @@ static void wsa881x_remove(struct snd_soc_component *component) mutex_destroy(&wsa881x->res_lock); } -static const struct snd_soc_component_driver soc_component_dev_wsa881x = { +static const struct snd_soc_component_driver soc_codec_dev_wsa881x = { + .name = "", .probe = wsa881x_probe, .remove = wsa881x_remove, @@ -1205,6 +1220,21 @@ static const struct snd_soc_component_driver soc_component_dev_wsa881x = { .num_dapm_routes = ARRAY_SIZE(wsa881x_audio_map), }; +static struct snd_soc_dai_driver wsa_dai[] = { + { + .name = "", + .playback = { + .stream_name = "", + .rates = WSA881X_RATES | WSA881X_FRAC_RATES, + .formats = WSA881X_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + }, +}; + static int wsa881x_reset(struct wsa881x_pdata *pdata, bool enable) { int ret = 0; @@ -1332,6 +1362,9 @@ static int wsa881x_i2c_probe(struct i2c_client *client, int wsa881x_index = 0; struct wsa881x_pdata *pdata = NULL; struct clk *wsa_mclk = NULL; + char buffer[MAX_NAME_LEN]; + const char *wsa881x_name_prefix_of = NULL; + struct snd_soc_component *component; ret = wsa881x_i2c_get_client_index(client, &wsa881x_index); if (ret != 0) { @@ -1454,13 +1487,84 @@ static int wsa881x_i2c_probe(struct i2c_client *client, } wsa881x_presence_count++; wsa881x_probing_count++; - ret = snd_soc_register_component(&client->dev, - &soc_component_dev_wsa881x, - NULL, 0); - if (ret < 0) + + ret = of_property_read_string(client->dev.of_node, + "qcom,wsa-prefix", &wsa881x_name_prefix_of); + if (ret) { + dev_err(&client->dev, + "%s: Looking up %s property in node %s failed\n", + __func__, "qcom,wsa-prefix", + client->dev.of_node->full_name); goto err1; + } + + pdata->driver = devm_kzalloc(&client->dev, + sizeof(struct snd_soc_component_driver), + GFP_KERNEL); + if (!pdata->driver) { + ret = -ENOMEM; + goto err1; + } + + memcpy(pdata->driver, &soc_codec_dev_wsa881x, + sizeof(struct snd_soc_component_driver)); + + pdata->dai_driver = devm_kzalloc(&client->dev, + sizeof(struct snd_soc_dai_driver), + GFP_KERNEL); + if (!pdata->dai_driver) { + ret = -ENOMEM; + goto err_mem; + } + + memcpy(pdata->dai_driver, wsa_dai, + sizeof(struct snd_soc_dai_driver)); + + snprintf(buffer, sizeof(buffer), "wsa-codec%d", wsa881x_index); + pdata->driver->name = kstrndup(buffer, + strlen(buffer), GFP_KERNEL); + + snprintf(buffer, sizeof(buffer), "wsa_rx%d", wsa881x_index); + pdata->dai_driver->name = + kstrndup(buffer, strlen(buffer), GFP_KERNEL); + + snprintf(buffer, sizeof(buffer), + "WSA881X_AIF%d Playback", wsa881x_index); + pdata->dai_driver->playback.stream_name = + kstrndup(buffer, strlen(buffer), GFP_KERNEL); + + /* Number of DAI's used is 1 */ + ret = snd_soc_register_component(&client->dev, + pdata->driver, pdata->dai_driver, 1); + + + pdata->wsa881x_name_prefix = kstrndup(wsa881x_name_prefix_of, + strlen(wsa881x_name_prefix_of), GFP_KERNEL); + + component = snd_soc_lookup_component(&client->dev, pdata->driver->name); + if (!component) { + dev_err(&client->dev, "%s: component is NULL \n", __func__); + ret = -EINVAL; + goto err_mem; + } + + component->name_prefix = pdata->wsa881x_name_prefix; + pdata->status = WSA881X_STATUS_I2C; + goto err1; } +err_mem: + kfree(pdata->wsa881x_name_prefix); + if (pdata->dai_driver) { + kfree(pdata->dai_driver->name); + kfree(pdata->dai_driver->playback.stream_name); + kfree(pdata->dai_driver); + } + if (pdata->driver) { + kfree(pdata->driver->name); + kfree(pdata->driver); + } + err1: wsa881x_reset(pdata, false); err: @@ -1472,6 +1576,16 @@ static int wsa881x_i2c_remove(struct i2c_client *client) struct wsa881x_pdata *wsa881x = client->dev.platform_data; snd_soc_unregister_component(&client->dev); + kfree(wsa881x->wsa881x_name_prefix); + if (wsa881x->dai_driver) { + kfree(wsa881x->dai_driver->name); + kfree(wsa881x->dai_driver->playback.stream_name); + kfree(wsa881x->dai_driver); + } + if (wsa881x->driver) { + kfree(wsa881x->driver->name); + kfree(wsa881x->driver); + } i2c_set_clientdata(client, NULL); kfree(wsa881x); return 0; diff --git a/asoc/codecs/wsa881x.c b/asoc/codecs/wsa881x.c index c4624f0fdc..d9330719aa 100644 --- a/asoc/codecs/wsa881x.c +++ b/asoc/codecs/wsa881x.c @@ -118,6 +118,7 @@ enum { BOLERO_WSA_EVT_SSR_DOWN, BOLERO_WSA_EVT_SSR_UP, BOLERO_WSA_EVT_PA_ON_POST_FSCLK, + BOLERO_WSA_EVT_PA_ON_POST_FSCLK_ADIE_LB, }; struct wsa_ctrl_platform_data { @@ -1403,6 +1404,7 @@ static int wsa881x_event_notify(struct notifier_block *nb, 0x80, 0x00); break; case BOLERO_WSA_EVT_PA_ON_POST_FSCLK: + case BOLERO_WSA_EVT_PA_ON_POST_FSCLK_ADIE_LB: if ((snd_soc_component_read32(wsa881x->component, WSA881X_SPKR_DAC_CTL) & 0x80) == 0x80) snd_soc_component_update_bits(wsa881x->component, diff --git a/asoc/codecs/wsa883x/internal.h b/asoc/codecs/wsa883x/internal.h index 3dc362784d..2be12f7171 100644 --- a/asoc/codecs/wsa883x/internal.h +++ b/asoc/codecs/wsa883x/internal.h @@ -66,6 +66,7 @@ enum { BOLERO_WSA_EVT_SSR_DOWN, BOLERO_WSA_EVT_SSR_UP, BOLERO_WSA_EVT_PA_ON_POST_FSCLK, + BOLERO_WSA_EVT_PA_ON_POST_FSCLK_ADIE_LB, }; struct wsa_ctrl_platform_data { diff --git a/asoc/codecs/wsa883x/wsa883x.c b/asoc/codecs/wsa883x/wsa883x.c index 8993c102b9..bf8adcac58 100644 --- a/asoc/codecs/wsa883x/wsa883x.c +++ b/asoc/codecs/wsa883x/wsa883x.c @@ -37,7 +37,7 @@ #define TEMP_INVALID 0xFFFF #define WSA883X_TEMP_RETRY 3 -#define MAX_NAME_LEN 30 +#define MAX_NAME_LEN 40 #define WSA883X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\ @@ -99,7 +99,6 @@ static const struct wsa_reg_mask_val reg_init[] = { {WSA883X_CDC_SPK_DSM_R7, 0xFF, 0x3F}, {WSA883X_DRE_CTL_0, 0xF0, 0x90}, {WSA883X_DRE_IDLE_DET_CTL, 0x10, 0x00}, - {WSA883X_PDM_WD_CTL, 0x01, 0x01}, {WSA883X_CURRENT_LIMIT, 0x78, 0x20}, {WSA883X_DRE_CTL_0, 0x07, 0x02}, {WSA883X_VAGC_TIME, 0x0F, 0x0F}, @@ -119,6 +118,7 @@ static const struct wsa_reg_mask_val reg_init[] = { {WSA883X_ADC_7, 0x04, 0x04}, {WSA883X_ADC_7, 0x02, 0x02}, {WSA883X_CKWD_CTL_0, 0x60, 0x00}, + {WSA883X_DRE_CTL_1, 0x3E, 0x20}, {WSA883X_CKWD_CTL_1, 0x1F, 0x1B}, {WSA883X_GMAMP_SUP1, 0x60, 0x60}, }; @@ -134,6 +134,7 @@ enum { enum { SPKR_STATUS = 0, WSA_SUPPLIES_LPM_MODE, + SPKR_ADIE_LB, }; enum { @@ -799,6 +800,30 @@ int wsa883x_codec_info_create_codec_entry(struct snd_info_entry *codec_root, } EXPORT_SYMBOL(wsa883x_codec_info_create_codec_entry); +/* + * wsa883x_codec_get_dev_num - returns swr device number + * @component: Codec instance + * + * Return: swr device number on success or negative error + * code on failure. + */ +int wsa883x_codec_get_dev_num(struct snd_soc_component *component) +{ + struct wsa883x_priv *wsa883x; + + if (!component) + return -EINVAL; + + wsa883x = snd_soc_component_get_drvdata(component); + if (!wsa883x) { + pr_err("%s: wsa883x component is NULL\n", __func__); + return -EINVAL; + } + + return wsa883x->swr_slave->dev_num; +} +EXPORT_SYMBOL(wsa883x_codec_get_dev_num); + static int wsa883x_get_compander(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -962,6 +987,7 @@ static int wsa883x_enable_swr_dac_port(struct snd_soc_dapm_widget *w, &port_type[0]); break; case SND_SOC_DAPM_POST_PMU: + set_bit(SPKR_STATUS, &wsa883x->status_mask); break; case SND_SOC_DAPM_PRE_PMD: wsa883x_set_port(component, SWR_DAC_PORT, @@ -1015,19 +1041,31 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w, swr_slvdev_datapath_control(wsa883x->swr_slave, wsa883x->swr_slave->dev_num, true); - wcd_enable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_PDM_WD); + /* Added delay as per HW sequence */ + usleep_range(250, 300); + snd_soc_component_update_bits(component, WSA883X_DRE_CTL_1, + 0x01, 0x01); + /* Added delay as per HW sequence */ + usleep_range(250, 300); wcd_enable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_UVLO); /* Force remove group */ swr_remove_from_group(wsa883x->swr_slave, wsa883x->swr_slave->dev_num); - set_bit(SPKR_STATUS, &wsa883x->status_mask); + if (test_bit(SPKR_ADIE_LB, &wsa883x->status_mask)) + snd_soc_component_update_bits(component, + WSA883X_PA_FSM_CTL, 0x01, 0x01); break; case SND_SOC_DAPM_PRE_PMD: + if (!test_bit(SPKR_ADIE_LB, &wsa883x->status_mask)) + wcd_disable_irq(&wsa883x->irq_info, + WSA883X_IRQ_INT_PDM_WD); snd_soc_component_update_bits(component, WSA883X_PA_FSM_CTL, 0x01, 0x00); - wcd_disable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_PDM_WD); + snd_soc_component_update_bits(component, WSA883X_PDM_WD_CTL, + 0x01, 0x00); wcd_disable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_UVLO); clear_bit(SPKR_STATUS, &wsa883x->status_mask); + clear_bit(SPKR_ADIE_LB, &wsa883x->status_mask); break; } return 0; @@ -1212,6 +1250,7 @@ static int wsa883x_get_temperature(struct snd_soc_component *component, static int wsa883x_codec_probe(struct snd_soc_component *component) { + char w_name[MAX_NAME_LEN]; struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component); struct swr_device *dev; int variant = 0, version = 0; @@ -1220,6 +1259,10 @@ static int wsa883x_codec_probe(struct snd_soc_component *component) if (!wsa883x) return -EINVAL; + + if (!component->name_prefix) + return -EINVAL; + snd_soc_component_init_regmap(component, wsa883x->regmap); dev = wsa883x->swr_slave; @@ -1236,8 +1279,28 @@ static int wsa883x_codec_probe(struct snd_soc_component *component) wsa883x_codec_init(component); wsa883x->global_pa_cnt = 0; - snd_soc_dapm_ignore_suspend(dapm, - wsa883x->dai_driver->playback.stream_name); + memset(w_name, 0, sizeof(w_name)); + strlcpy(w_name, component->name_prefix, sizeof(w_name)); + strlcat(w_name, " ", sizeof(w_name)); + strlcat(w_name, wsa883x->dai_driver->playback.stream_name, + sizeof(w_name)); + snd_soc_dapm_ignore_suspend(dapm, w_name); + + memset(w_name, 0, sizeof(w_name)); + strlcpy(w_name, component->name_prefix, sizeof(w_name)); + strlcat(w_name, " IN", sizeof(w_name)); + snd_soc_dapm_ignore_suspend(dapm, w_name); + + memset(w_name, 0, sizeof(w_name)); + strlcpy(w_name, component->name_prefix, sizeof(w_name)); + strlcat(w_name, " SWR DAC_PORT", sizeof(w_name)); + snd_soc_dapm_ignore_suspend(dapm, w_name); + + memset(w_name, 0, sizeof(w_name)); + strlcpy(w_name, component->name_prefix, sizeof(w_name)); + strlcat(w_name, " SPKR", sizeof(w_name)); + snd_soc_dapm_ignore_suspend(dapm, w_name); + snd_soc_dapm_sync(dapm); return 0; @@ -1375,10 +1438,27 @@ static int wsa883x_event_notify(struct notifier_block *nb, break; case BOLERO_WSA_EVT_PA_ON_POST_FSCLK: - if (test_bit(SPKR_STATUS, &wsa883x->status_mask)) + if (test_bit(SPKR_STATUS, &wsa883x->status_mask)) { + snd_soc_component_update_bits(wsa883x->component, + WSA883X_PDM_WD_CTL, + 0x01, 0x01); snd_soc_component_update_bits(wsa883x->component, WSA883X_PA_FSM_CTL, 0x01, 0x01); + wcd_enable_irq(&wsa883x->irq_info, + WSA883X_IRQ_INT_PDM_WD); + /* Added delay as per HW sequence */ + usleep_range(3000, 3100); + snd_soc_component_update_bits(wsa883x->component, + WSA883X_DRE_CTL_1, + 0x01, 0x00); + /* Added delay as per HW sequence */ + usleep_range(5000, 5050); + } + break; + case BOLERO_WSA_EVT_PA_ON_POST_FSCLK_ADIE_LB: + if (test_bit(SPKR_STATUS, &wsa883x->status_mask)) + set_bit(SPKR_ADIE_LB, &wsa883x->status_mask); break; default: dev_dbg(wsa883x->dev, "%s: unknown event %d\n", diff --git a/asoc/codecs/wsa883x/wsa883x.h b/asoc/codecs/wsa883x/wsa883x.h index e080134eb0..bb719831ed 100644 --- a/asoc/codecs/wsa883x/wsa883x.h +++ b/asoc/codecs/wsa883x/wsa883x.h @@ -21,6 +21,7 @@ int wsa883x_set_channel_map(struct snd_soc_component *component, int wsa883x_codec_info_create_codec_entry( struct snd_info_entry *codec_root, struct snd_soc_component *component); +int wsa883x_codec_get_dev_num(struct snd_soc_component *component); #else static int wsa883x_set_channel_map(struct snd_soc_component *component, u8 *port, u8 num_port, unsigned int *ch_mask, @@ -36,6 +37,10 @@ static int wsa883x_codec_info_create_codec_entry( return 0; } +static int wsa883x_codec_get_dev_num(struct snd_soc_component *component) +{ + return 0; +} #endif #endif /* _WSA883X_H */ diff --git a/asoc/holi-port-config.h b/asoc/holi-port-config.h new file mode 100644 index 0000000000..c2b0074318 --- /dev/null +++ b/asoc/holi-port-config.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _HOLI_PORT_CONFIG +#define _HOLI_PORT_CONFIG + +#include + +#define WSA_MSTR_PORT_MASK 0xFF +/* + * Add port configuration in the format + *{ si, off1, off2, hstart, hstop, wd_len, bp_mode, bgp_ctrl, lane_ctrl, dir, + * stream_type} + */ + +static struct port_params rx_frame_params_dsd[SWR_MSTR_PORT_LEN] = { + {3, 0, 0, 0xFF, 0xFF, 1, 0xFF, 0xFF, 1, 0x00, 0x00}, + {31, 0, 0, 3, 6, 7, 0, 0xFF, 0, 0x00, 0x00}, + {31, 11, 11, 0xFF, 0xFF, 4, 1, 0xFF, 0, 0x00, 0x00}, + {7, 9, 0, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0, 0x00, 0x00}, + {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 3, 0, 0x00, 0x00}, +}; + +/* Headset + PCM Haptics */ +static struct port_params rx_frame_params_default[SWR_MSTR_PORT_LEN] = { + {3, 0, 0, 0xFF, 0xFF, 1, 0xFF, 0xFF, 1, 0x00, 0x00}, /* HPH/EAR */ + {31, 0, 0, 3, 6, 7, 0, 0xFF, 0, 0x00, 0x00}, /* HPH_CLH */ + {31, 11, 11, 0xFF, 0xFF, 4, 1, 0xFF, 0, 0x00, 0x00}, /* HPH_CMP */ + {7, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* LO/AUX */ + {0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0x00, 0x00}, /* DSD */ + {0x18F, 0, 0, 0x8, 0x8, 0x0F, 0x00, 0, 0, 0x00, 0x01}, /* PCM_OUT */ +}; + +/* TX UC1: TX1: 1ch, TX2: 2chs, TX3: 1ch(MBHC) */ +static struct port_params tx_frame_params_default[SWR_MSTR_PORT_LEN] = { + {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX1 */ + {3, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX2 */ + {7, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX3 */ +}; + +static struct port_params tx_frame_params_wcd937x[SWR_MSTR_PORT_LEN] = { + {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX1 */ + {3, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0x00, 0x00}, /* TX2 */ + {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX3 */ +}; + +static struct swr_mstr_port_map sm_port_map[] = { + {TX_MACRO, SWR_UC0, tx_frame_params_default}, + {RX_MACRO, SWR_UC0, rx_frame_params_default}, + {RX_MACRO, SWR_UC1, rx_frame_params_dsd}, +}; + +static struct swr_mstr_port_map sm_port_map_wcd937x[] = { + {TX_MACRO, SWR_UC0, tx_frame_params_wcd937x}, + {RX_MACRO, SWR_UC0, rx_frame_params_default}, + {RX_MACRO, SWR_UC1, rx_frame_params_dsd}, +}; + +#endif /* _HOLI_PORT_CONFIG */ diff --git a/asoc/holi.c b/asoc/holi.c new file mode 100644 index 0000000000..b5fa3d0b34 --- /dev/null +++ b/asoc/holi.c @@ -0,0 +1,6813 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "device_event.h" +#include "msm-pcm-routing-v2.h" +#include "asoc/msm-cdc-pinctrl.h" +#include "asoc/wcd-mbhc-v2.h" +#include "codecs/wsa881x-analog.h" +#include "codecs/wcd937x/wcd937x-mbhc.h" +#include "codecs/wcd937x/wcd937x.h" +#include "codecs/wcd938x/wcd938x-mbhc.h" +#include "codecs/wcd938x/wcd938x.h" +#include "codecs/bolero/bolero-cdc.h" +#include +#include "holi-port-config.h" +#include "msm_holi_dailink.h" + +#define DRV_NAME "holi-asoc-snd" +#define __CHIPSET__ "HOLI " +#define MSM_DAILINK_NAME(name) (__CHIPSET__#name) + +#define SAMPLING_RATE_8KHZ 8000 +#define SAMPLING_RATE_11P025KHZ 11025 +#define SAMPLING_RATE_16KHZ 16000 +#define SAMPLING_RATE_22P05KHZ 22050 +#define SAMPLING_RATE_32KHZ 32000 +#define SAMPLING_RATE_44P1KHZ 44100 +#define SAMPLING_RATE_48KHZ 48000 +#define SAMPLING_RATE_88P2KHZ 88200 +#define SAMPLING_RATE_96KHZ 96000 +#define SAMPLING_RATE_176P4KHZ 176400 +#define SAMPLING_RATE_192KHZ 192000 +#define SAMPLING_RATE_352P8KHZ 352800 +#define SAMPLING_RATE_384KHZ 384000 + +#define IS_FRACTIONAL(x) \ +((x == SAMPLING_RATE_11P025KHZ) || (x == SAMPLING_RATE_22P05KHZ) || \ +(x == SAMPLING_RATE_44P1KHZ) || (x == SAMPLING_RATE_88P2KHZ) || \ +(x == SAMPLING_RATE_176P4KHZ) || (x == SAMPLING_RATE_352P8KHZ)) + +#define IS_MSM_INTERFACE_MI2S(x) \ +((x == PRIM_MI2S) || (x == SEC_MI2S) || (x == TERT_MI2S)) + +#define WCD9XXX_MBHC_DEF_RLOADS 5 +#define WCD9XXX_MBHC_DEF_BUTTONS 8 +#define CODEC_EXT_CLK_RATE 9600000 +#define ADSP_STATE_READY_TIMEOUT_MS 3000 +#define DEV_NAME_STR_LEN 32 +#define WCD_MBHC_HS_V_MAX 1600 + +#define TDM_CHANNEL_MAX 8 +#define DEV_NAME_STR_LEN 32 + +/* time in us to ensure LPM doesn't go in C3/C4 */ +#define MSM_LL_QOS_VALUE 300 + +#define ADSP_STATE_READY_TIMEOUT_MS 3000 + +#define WCN_CDC_SLIM_RX_CH_MAX 2 +#define WCN_CDC_SLIM_TX_CH_MAX 2 +#define WCN_CDC_SLIM_TX_CH_MAX_LITO 3 + +enum { + RX_PATH = 0, + TX_PATH, + MAX_PATH, +}; + +enum { + TDM_0 = 0, + TDM_1, + TDM_2, + TDM_3, + TDM_4, + TDM_5, + TDM_6, + TDM_7, + TDM_PORT_MAX, +}; + +#define TDM_MAX_SLOTS 8 +#define TDM_SLOT_WIDTH_BITS 32 + +enum { + TDM_PRI = 0, + TDM_SEC, + TDM_TERT, + TDM_QUAT, + TDM_INTERFACE_MAX, +}; + +enum { + PRIM_AUX_PCM = 0, + SEC_AUX_PCM, + TERT_AUX_PCM, + QUAT_AUX_PCM, + AUX_PCM_MAX, +}; + +enum { + PRIM_MI2S = 0, + SEC_MI2S, + TERT_MI2S, + QUAT_MI2S, + MI2S_MAX, +}; + +enum { + RX_CDC_DMA_RX_0 = 0, + RX_CDC_DMA_RX_1, + RX_CDC_DMA_RX_2, + RX_CDC_DMA_RX_3, + RX_CDC_DMA_RX_5, + RX_CDC_DMA_RX_6, + CDC_DMA_RX_MAX, +}; + +enum { + TX_CDC_DMA_TX_0 = 0, + TX_CDC_DMA_TX_3, + TX_CDC_DMA_TX_4, + VA_CDC_DMA_TX_0, + VA_CDC_DMA_TX_1, + VA_CDC_DMA_TX_2, + CDC_DMA_TX_MAX, +}; + +enum { + SLIM_RX_7 = 0, + SLIM_RX_MAX, +}; +enum { + SLIM_TX_7 = 0, + SLIM_TX_8, + SLIM_TX_MAX, +}; + +enum { + AFE_LOOPBACK_TX_IDX = 0, + AFE_LOOPBACK_TX_IDX_MAX, +}; + +struct msm_asoc_mach_data { + struct snd_info_entry *codec_root; + int usbc_en2_gpio; /* used by gpio driver API */ + struct device_node *dmic01_gpio_p; /* used by pinctrl API */ + struct device_node *dmic23_gpio_p; /* used by pinctrl API */ + struct device_node *dmic45_gpio_p; /* used by pinctrl API */ + struct device_node *mi2s_gpio_p[MI2S_MAX]; /* used by pinctrl API */ + atomic_t mi2s_gpio_ref_count[MI2S_MAX]; /* used by pinctrl API */ + struct device_node *us_euro_gpio_p; /* used by pinctrl API */ + struct pinctrl *usbc_en2_gpio_p; /* used by pinctrl API */ + struct device_node *hph_en1_gpio_p; /* used by pinctrl API */ + struct device_node *hph_en0_gpio_p; /* used by pinctrl API */ + bool is_afe_config_done; + struct device_node *fsa_handle; + struct clk *lpass_audio_hw_vote; + int core_audio_vote_count; + u32 wcd_disabled; +}; + +struct tdm_port { + u32 mode; + u32 channel; +}; + +struct tdm_dev_config { + unsigned int tdm_slot_offset[TDM_MAX_SLOTS]; +}; + +struct dev_config { + u32 sample_rate; + u32 bit_format; + u32 channels; +}; + +/* Default configuration of slimbus channels */ +static struct dev_config slim_rx_cfg[] = { + [SLIM_RX_7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, +}; + +static struct dev_config slim_tx_cfg[] = { + [SLIM_TX_7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_TX_8] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, +}; + +static struct dev_config usb_rx_cfg = { + .sample_rate = SAMPLING_RATE_48KHZ, + .bit_format = SNDRV_PCM_FORMAT_S16_LE, + .channels = 2, +}; + +static struct dev_config usb_tx_cfg = { + .sample_rate = SAMPLING_RATE_48KHZ, + .bit_format = SNDRV_PCM_FORMAT_S16_LE, + .channels = 1, +}; + +static struct dev_config proxy_rx_cfg = { + .sample_rate = SAMPLING_RATE_48KHZ, + .bit_format = SNDRV_PCM_FORMAT_S16_LE, + .channels = 2, +}; + +static struct afe_clk_set mi2s_clk[MI2S_MAX] = { + { + 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, + }, + { + AFE_API_VERSION_I2S_CONFIG, + Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT, + Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, + }, + { + 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, + }, + { + AFE_API_VERSION_I2S_CONFIG, + Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT, + Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, + }, +}; + +struct mi2s_conf { + struct mutex lock; + u32 ref_cnt; + u32 msm_is_mi2s_master; +}; + +static u32 mi2s_ebit_clk[MI2S_MAX] = { + Q6AFE_LPASS_CLK_ID_PRI_MI2S_EBIT, + Q6AFE_LPASS_CLK_ID_SEC_MI2S_EBIT, + Q6AFE_LPASS_CLK_ID_TER_MI2S_EBIT, +}; + +static struct mi2s_conf mi2s_intf_conf[MI2S_MAX]; + +/* Default configuration of TDM channels */ +static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { + { /* PRI TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */ + }, + { /* SEC TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */ + }, + { /* TERT TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */ + }, + { /* QUAT TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */ + }, +}; + +static struct dev_config tdm_tx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { + { /* PRI TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */ + }, + { /* SEC TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */ + }, + { /* TERT TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */ + }, + { /* QUAT TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */ + }, +}; + +/* Default configuration of AUX PCM channels */ +static struct dev_config aux_pcm_rx_cfg[] = { + [PRIM_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SEC_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [TERT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [QUAT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, +}; + +static struct dev_config aux_pcm_tx_cfg[] = { + [PRIM_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SEC_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [TERT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [QUAT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, +}; + +/* Default configuration of MI2S channels */ +static struct dev_config mi2s_rx_cfg[] = { + [PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, + [SEC_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, + [TERT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, + [QUAT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, +}; + +static struct dev_config mi2s_tx_cfg[] = { + [PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SEC_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [TERT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [QUAT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, +}; + +static struct tdm_dev_config pri_tdm_dev_config[MAX_PATH][TDM_PORT_MAX] = { + { /* PRI TDM */ + { {0, 4, 0xFFFF} }, /* RX_0 */ + { {8, 12, 0xFFFF} }, /* RX_1 */ + { {16, 20, 0xFFFF} }, /* RX_2 */ + { {24, 28, 0xFFFF} }, /* RX_3 */ + { {0xFFFF} }, /* RX_4 */ + { {0xFFFF} }, /* RX_5 */ + { {0xFFFF} }, /* RX_6 */ + { {0xFFFF} }, /* RX_7 */ + }, + { + { {0, 4, 8, 12, 0xFFFF} }, /* TX_0 */ + { {8, 12, 0xFFFF} }, /* TX_1 */ + { {16, 20, 0xFFFF} }, /* TX_2 */ + { {24, 28, 0xFFFF} }, /* TX_3 */ + { {0xFFFF} }, /* TX_4 */ + { {0xFFFF} }, /* TX_5 */ + { {0xFFFF} }, /* TX_6 */ + { {0xFFFF} }, /* TX_7 */ + }, +}; + +static struct tdm_dev_config sec_tdm_dev_config[MAX_PATH][TDM_PORT_MAX] = { + { /* SEC TDM */ + { {0, 4, 0xFFFF} }, /* RX_0 */ + { {8, 12, 0xFFFF} }, /* RX_1 */ + { {16, 20, 0xFFFF} }, /* RX_2 */ + { {24, 28, 0xFFFF} }, /* RX_3 */ + { {0xFFFF} }, /* RX_4 */ + { {0xFFFF} }, /* RX_5 */ + { {0xFFFF} }, /* RX_6 */ + { {0xFFFF} }, /* RX_7 */ + }, + { + { {0, 4, 0xFFFF} }, /* TX_0 */ + { {8, 12, 0xFFFF} }, /* TX_1 */ + { {16, 20, 0xFFFF} }, /* TX_2 */ + { {24, 28, 0xFFFF} }, /* TX_3 */ + { {0xFFFF} }, /* TX_4 */ + { {0xFFFF} }, /* TX_5 */ + { {0xFFFF} }, /* TX_6 */ + { {0xFFFF} }, /* TX_7 */ + }, +}; + +static struct tdm_dev_config tert_tdm_dev_config[MAX_PATH][TDM_PORT_MAX] = { + { /* TERT TDM */ + { {0, 4, 0xFFFF} }, /* RX_0 */ + { {8, 12, 0xFFFF} }, /* RX_1 */ + { {16, 20, 0xFFFF} }, /* RX_2 */ + { {24, 28, 0xFFFF} }, /* RX_3 */ + { {0xFFFF} }, /* RX_4 */ + { {0xFFFF} }, /* RX_5 */ + { {0xFFFF} }, /* RX_6 */ + { {0xFFFF} }, /* RX_7 */ + }, + { + { {0, 4, 0xFFFF} }, /* TX_0 */ + { {8, 12, 0xFFFF} }, /* TX_1 */ + { {16, 20, 0xFFFF} }, /* TX_2 */ + { {24, 28, 0xFFFF} }, /* TX_3 */ + { {0xFFFF} }, /* TX_4 */ + { {0xFFFF} }, /* TX_5 */ + { {0xFFFF} }, /* TX_6 */ + { {0xFFFF} }, /* TX_7 */ + }, +}; + +static struct tdm_dev_config quat_tdm_dev_config[MAX_PATH][TDM_PORT_MAX] = { + { /* QUAT TDM */ + { {0, 4, 0xFFFF} }, /* RX_0 */ + { {8, 12, 0xFFFF} }, /* RX_1 */ + { {16, 20, 0xFFFF} }, /* RX_2 */ + { {24, 28, 0xFFFF} }, /* RX_3 */ + { {0xFFFF} }, /* RX_4 */ + { {0xFFFF} }, /* RX_5 */ + { {0xFFFF} }, /* RX_6 */ + { {0xFFFF} }, /* RX_7 */ + }, + { + { {0, 4, 0xFFFF} }, /* TX_0 */ + { {8, 12, 0xFFFF} }, /* TX_1 */ + { {16, 20, 0xFFFF} }, /* TX_2 */ + { {24, 28, 0xFFFF} }, /* TX_3 */ + { {0xFFFF} }, /* TX_4 */ + { {0xFFFF} }, /* TX_5 */ + { {0xFFFF} }, /* TX_6 */ + { {0xFFFF} }, /* TX_7 */ + }, +}; + + +static void *tdm_cfg[TDM_INTERFACE_MAX] = { + pri_tdm_dev_config, + sec_tdm_dev_config, + tert_tdm_dev_config, + quat_tdm_dev_config, +}; + +/* Default configuration of Codec DMA Interface RX */ +static struct dev_config cdc_dma_rx_cfg[] = { + [RX_CDC_DMA_RX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, + [RX_CDC_DMA_RX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, + [RX_CDC_DMA_RX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, + [RX_CDC_DMA_RX_3] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, + [RX_CDC_DMA_RX_5] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, + [RX_CDC_DMA_RX_6] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, +}; + +/* Default configuration of Codec DMA Interface TX */ +static struct dev_config cdc_dma_tx_cfg[] = { + [TX_CDC_DMA_TX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, + [TX_CDC_DMA_TX_3] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, + [TX_CDC_DMA_TX_4] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, + [VA_CDC_DMA_TX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8}, + [VA_CDC_DMA_TX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8}, + [VA_CDC_DMA_TX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8}, +}; + +static struct dev_config afe_loopback_tx_cfg[] = { + [AFE_LOOPBACK_TX_IDX] = + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, +}; + +static int msm_vi_feed_tx_ch = 2; +static const char *const vi_feed_ch_text[] = {"One", "Two"}; +static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE", + "S32_LE"}; +static char const *cdc80_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"}; +static char const *ch_text[] = {"Two", "Three", "Four", "Five", + "Six", "Seven", "Eight"}; +static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025", + "KHZ_16", "KHZ_22P05", + "KHZ_32", "KHZ_44P1", "KHZ_48", + "KHZ_88P2", "KHZ_96", "KHZ_176P4", + "KHZ_192", "KHZ_352P8", "KHZ_384"}; +static const char *const usb_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", + "Eight"}; +static char const *tdm_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_32", + "KHZ_48", "KHZ_176P4", + "KHZ_352P8"}; +static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"}; +static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", "Eight"}; +static const char *const auxpcm_rate_text[] = {"KHZ_8", "KHZ_16"}; +static char const *mi2s_rate_text[] = {"KHZ_8", "KHZ_11P025", "KHZ_16", + "KHZ_22P05", "KHZ_32", "KHZ_44P1", + "KHZ_48", "KHZ_88P2", "KHZ_96", + "KHZ_176P4", "KHZ_192", "KHZ_352P8", + "KHZ_384"}; +static const char *const mi2s_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", + "Eight"}; + +static const char *const cdc_dma_rx_ch_text[] = {"One", "Two"}; +static const char *const cdc_dma_tx_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", + "Eight"}; +static char const *cdc_dma_sample_rate_text[] = {"KHZ_8", "KHZ_11P025", + "KHZ_16", "KHZ_22P05", + "KHZ_32", "KHZ_44P1", "KHZ_48", + "KHZ_88P2", "KHZ_96", + "KHZ_176P4", "KHZ_192", + "KHZ_352P8", "KHZ_384"}; +static char const *cdc80_dma_sample_rate_text[] = {"KHZ_8", "KHZ_11P025", + "KHZ_16", "KHZ_22P05", + "KHZ_32", "KHZ_44P1", "KHZ_48", + "KHZ_88P2", "KHZ_96", + "KHZ_176P4", "KHZ_192"}; +static char const *bt_sample_rate_text[] = {"KHZ_8", "KHZ_16", + "KHZ_44P1", "KHZ_48", + "KHZ_88P2", "KHZ_96"}; +static char const *bt_sample_rate_rx_text[] = {"KHZ_8", "KHZ_16", + "KHZ_44P1", "KHZ_48", + "KHZ_88P2", "KHZ_96"}; +static char const *bt_sample_rate_tx_text[] = {"KHZ_8", "KHZ_16", + "KHZ_44P1", "KHZ_48", + "KHZ_88P2", "KHZ_96"}; +static const char *const afe_loopback_tx_ch_text[] = {"One", "Two"}; + +static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_chs, usb_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(vi_feed_tx_chs, vi_feed_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(proxy_rx_chs, ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_sample_rate, tdm_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_sample_rate, tdm_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_format, tdm_bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_format, tdm_bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_chs, tdm_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_chs, tdm_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_rx_sample_rate, auxpcm_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_rx_sample_rate, auxpcm_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(tert_aux_pcm_rx_sample_rate, auxpcm_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(quat_aux_pcm_rx_sample_rate, auxpcm_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_tx_sample_rate, auxpcm_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_tx_sample_rate, auxpcm_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(tert_aux_pcm_tx_sample_rate, auxpcm_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(quat_aux_pcm_tx_sample_rate, auxpcm_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_rx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_tx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_rx_sample_rate, mi2s_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_rx_sample_rate, mi2s_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_sample_rate, mi2s_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_sample_rate, mi2s_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_tx_sample_rate, mi2s_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_tx_sample_rate, mi2s_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_sample_rate, mi2s_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_sample_rate, mi2s_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(mi2s_rx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(mi2s_tx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_rx_chs, mi2s_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_rx_chs, mi2s_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_chs, mi2s_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_chs, mi2s_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_tx_chs, mi2s_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_tx_chs, mi2s_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_chs, mi2s_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_chs, mi2s_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_0_chs, cdc_dma_rx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_1_chs, cdc_dma_rx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_2_chs, cdc_dma_rx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_3_chs, cdc_dma_rx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_5_chs, cdc_dma_rx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_6_chs, cdc_dma_rx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_0_chs, cdc_dma_tx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_3_chs, cdc_dma_tx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_4_chs, cdc_dma_tx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_0_chs, cdc_dma_tx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_1_chs, cdc_dma_tx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_2_chs, cdc_dma_tx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_0_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_3_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_4_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_0_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_1_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_2_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_0_sample_rate, + cdc_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_3_sample_rate, + cdc_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_4_sample_rate, + cdc_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_0_sample_rate, + cdc_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_1_sample_rate, + cdc_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_2_sample_rate, + cdc_dma_sample_rate_text); + +/* WCD9380 */ +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc80_dma_rx_0_format, cdc80_bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc80_dma_rx_1_format, cdc80_bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc80_dma_rx_2_format, cdc80_bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc80_dma_rx_3_format, cdc80_bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc80_dma_rx_5_format, cdc80_bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc80_dma_rx_6_format, cdc80_bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc80_dma_rx_0_sample_rate, + cdc80_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc80_dma_rx_1_sample_rate, + cdc80_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc80_dma_rx_2_sample_rate, + cdc80_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc80_dma_rx_3_sample_rate, + cdc80_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc80_dma_rx_5_sample_rate, + cdc80_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc80_dma_rx_6_sample_rate, + cdc80_dma_sample_rate_text); +/* WCD9385 */ +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc85_dma_rx_0_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc85_dma_rx_1_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc85_dma_rx_2_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc85_dma_rx_3_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc85_dma_rx_5_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc85_dma_rx_6_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc85_dma_rx_0_sample_rate, + cdc_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc85_dma_rx_1_sample_rate, + cdc_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc85_dma_rx_2_sample_rate, + cdc_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc85_dma_rx_3_sample_rate, + cdc_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc85_dma_rx_5_sample_rate, + cdc_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc85_dma_rx_6_sample_rate, + cdc_dma_sample_rate_text); + +/* WCD937x */ +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_0_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_1_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_2_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_3_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_5_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_0_sample_rate, + cdc_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_1_sample_rate, + cdc_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_2_sample_rate, + cdc_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_3_sample_rate, + cdc_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_5_sample_rate, + cdc_dma_sample_rate_text); + +static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate_rx, bt_sample_rate_rx_text); +static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate_tx, bt_sample_rate_tx_text); +static SOC_ENUM_SINGLE_EXT_DECL(afe_loopback_tx_chs, afe_loopback_tx_ch_text); + +static bool is_initial_boot; +static bool codec_reg_done; +static struct snd_soc_card snd_soc_card_holi_msm; +static int dmic_0_1_gpio_cnt; +static int dmic_2_3_gpio_cnt; +static int dmic_4_5_gpio_cnt; + +static void *def_wcd_mbhc_cal(void); + +static int msm_aux_codec_init(struct snd_soc_pcm_runtime *); +static int msm_int_audrx_init(struct snd_soc_pcm_runtime *); + +/* + * Need to report LINEIN + * if R/L channel impedance is larger than 5K ohm + */ +static struct wcd_mbhc_config wcd_mbhc_cfg = { + .read_fw_bin = false, + .calibration = NULL, + .detect_extn_cable = true, + .mono_stero_detection = false, + .swap_gnd_mic = NULL, + .hs_ext_micbias = true, + .key_code[0] = KEY_MEDIA, + .key_code[1] = KEY_VOICECOMMAND, + .key_code[2] = KEY_VOLUMEUP, + .key_code[3] = KEY_VOLUMEDOWN, + .key_code[4] = 0, + .key_code[5] = 0, + .key_code[6] = 0, + .key_code[7] = 0, + .linein_th = 5000, + .moisture_en = false, + .mbhc_micbias = MIC_BIAS_2, + .anc_micbias = MIC_BIAS_2, + .enable_anc_mic_detect = false, + .moisture_duty_cycle_en = true, +}; + +/* set audio task affinity to core 1 & 2 */ +static const unsigned int audio_core_list[] = {1, 2}; +static cpumask_t audio_cpu_map = CPU_MASK_NONE; +static struct dev_pm_qos_request *msm_audio_req = NULL; +static unsigned int qos_client_active_cnt = 0; + +static void msm_audio_add_qos_request() +{ + int i; + int cpu = 0; + + msm_audio_req = kzalloc(sizeof(struct dev_pm_qos_request) * NR_CPUS, + GFP_KERNEL); + if (!msm_audio_req) { + pr_err("%s failed to alloc mem for qos req.\n", __func__); + return; + } + + for (i = 0; i < ARRAY_SIZE(audio_core_list); i++) { + if (audio_core_list[i] >= NR_CPUS) + pr_err("%s incorrect cpu id: %d specified.\n", + __func__, audio_core_list[i]); + else + cpumask_set_cpu(audio_core_list[i], &audio_cpu_map); + } + + for_each_cpu(cpu, &audio_cpu_map) { + dev_pm_qos_add_request(get_cpu_device(cpu), + &msm_audio_req[cpu], + DEV_PM_QOS_RESUME_LATENCY, + PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE); + pr_debug("%s set cpu affinity to core %d.\n", __func__, cpu); + } +} + +static void msm_audio_remove_qos_request() +{ + int cpu = 0; + + if (msm_audio_req) { + for_each_cpu(cpu, &audio_cpu_map) { + dev_pm_qos_remove_request( + &msm_audio_req[cpu]); + pr_debug("%s remove cpu affinity of core %d.\n", + __func__, cpu); + } + kfree(msm_audio_req); + } +} + +static void msm_audio_update_qos_request(u32 latency) +{ + int cpu = 0; + + if (msm_audio_req) { + for_each_cpu(cpu, &audio_cpu_map) { + dev_pm_qos_update_request( + &msm_audio_req[cpu], latency); + pr_debug("%s update latency of core %d to %ul.\n", + __func__, cpu, latency); + } + } +} + +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 usb_audio_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate_val = 0; + + switch (usb_rx_cfg.sample_rate) { + case SAMPLING_RATE_384KHZ: + sample_rate_val = 12; + break; + case SAMPLING_RATE_352P8KHZ: + sample_rate_val = 11; + break; + case SAMPLING_RATE_192KHZ: + sample_rate_val = 10; + break; + case SAMPLING_RATE_176P4KHZ: + sample_rate_val = 9; + break; + case SAMPLING_RATE_96KHZ: + sample_rate_val = 8; + break; + case SAMPLING_RATE_88P2KHZ: + sample_rate_val = 7; + break; + case SAMPLING_RATE_48KHZ: + sample_rate_val = 6; + break; + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 5; + break; + case SAMPLING_RATE_32KHZ: + sample_rate_val = 4; + break; + case SAMPLING_RATE_22P05KHZ: + sample_rate_val = 3; + break; + case SAMPLING_RATE_16KHZ: + sample_rate_val = 2; + break; + case SAMPLING_RATE_11P025KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_8KHZ: + default: + sample_rate_val = 0; + break; + } + + ucontrol->value.integer.value[0] = sample_rate_val; + pr_debug("%s: usb_audio_rx_sample_rate = %d\n", __func__, + usb_rx_cfg.sample_rate); + return 0; +} + +static int usb_audio_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 12: + usb_rx_cfg.sample_rate = SAMPLING_RATE_384KHZ; + break; + case 11: + usb_rx_cfg.sample_rate = SAMPLING_RATE_352P8KHZ; + break; + case 10: + usb_rx_cfg.sample_rate = SAMPLING_RATE_192KHZ; + break; + case 9: + usb_rx_cfg.sample_rate = SAMPLING_RATE_176P4KHZ; + break; + case 8: + usb_rx_cfg.sample_rate = SAMPLING_RATE_96KHZ; + break; + case 7: + usb_rx_cfg.sample_rate = SAMPLING_RATE_88P2KHZ; + break; + case 6: + usb_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ; + break; + case 5: + usb_rx_cfg.sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 4: + usb_rx_cfg.sample_rate = SAMPLING_RATE_32KHZ; + break; + case 3: + usb_rx_cfg.sample_rate = SAMPLING_RATE_22P05KHZ; + break; + case 2: + usb_rx_cfg.sample_rate = SAMPLING_RATE_16KHZ; + break; + case 1: + usb_rx_cfg.sample_rate = SAMPLING_RATE_11P025KHZ; + break; + case 0: + usb_rx_cfg.sample_rate = SAMPLING_RATE_8KHZ; + break; + default: + usb_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ; + break; + } + + pr_debug("%s: control value = %ld, usb_audio_rx_sample_rate = %d\n", + __func__, ucontrol->value.integer.value[0], + usb_rx_cfg.sample_rate); + return 0; +} + +static int usb_audio_tx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate_val = 0; + + switch (usb_tx_cfg.sample_rate) { + case SAMPLING_RATE_384KHZ: + sample_rate_val = 12; + break; + case SAMPLING_RATE_352P8KHZ: + sample_rate_val = 11; + break; + case SAMPLING_RATE_192KHZ: + sample_rate_val = 10; + break; + case SAMPLING_RATE_176P4KHZ: + sample_rate_val = 9; + break; + case SAMPLING_RATE_96KHZ: + sample_rate_val = 8; + break; + case SAMPLING_RATE_88P2KHZ: + sample_rate_val = 7; + break; + case SAMPLING_RATE_48KHZ: + sample_rate_val = 6; + break; + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 5; + break; + case SAMPLING_RATE_32KHZ: + sample_rate_val = 4; + break; + case SAMPLING_RATE_22P05KHZ: + sample_rate_val = 3; + break; + case SAMPLING_RATE_16KHZ: + sample_rate_val = 2; + break; + case SAMPLING_RATE_11P025KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_8KHZ: + sample_rate_val = 0; + break; + default: + sample_rate_val = 6; + break; + } + + ucontrol->value.integer.value[0] = sample_rate_val; + pr_debug("%s: usb_audio_tx_sample_rate = %d\n", __func__, + usb_tx_cfg.sample_rate); + return 0; +} + +static int usb_audio_tx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 12: + usb_tx_cfg.sample_rate = SAMPLING_RATE_384KHZ; + break; + case 11: + usb_tx_cfg.sample_rate = SAMPLING_RATE_352P8KHZ; + break; + case 10: + usb_tx_cfg.sample_rate = SAMPLING_RATE_192KHZ; + break; + case 9: + usb_tx_cfg.sample_rate = SAMPLING_RATE_176P4KHZ; + break; + case 8: + usb_tx_cfg.sample_rate = SAMPLING_RATE_96KHZ; + break; + case 7: + usb_tx_cfg.sample_rate = SAMPLING_RATE_88P2KHZ; + break; + case 6: + usb_tx_cfg.sample_rate = SAMPLING_RATE_48KHZ; + break; + case 5: + usb_tx_cfg.sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 4: + usb_tx_cfg.sample_rate = SAMPLING_RATE_32KHZ; + break; + case 3: + usb_tx_cfg.sample_rate = SAMPLING_RATE_22P05KHZ; + break; + case 2: + usb_tx_cfg.sample_rate = SAMPLING_RATE_16KHZ; + break; + case 1: + usb_tx_cfg.sample_rate = SAMPLING_RATE_11P025KHZ; + break; + case 0: + usb_tx_cfg.sample_rate = SAMPLING_RATE_8KHZ; + break; + default: + usb_tx_cfg.sample_rate = SAMPLING_RATE_48KHZ; + break; + } + + pr_debug("%s: control value = %ld, usb_audio_tx_sample_rate = %d\n", + __func__, ucontrol->value.integer.value[0], + usb_tx_cfg.sample_rate); + return 0; +} +static int afe_loopback_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: afe_loopback_tx_ch = %d\n", __func__, + afe_loopback_tx_cfg[0].channels); + ucontrol->value.enumerated.item[0] = + afe_loopback_tx_cfg[0].channels - 1; + + return 0; +} + +static int afe_loopback_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + afe_loopback_tx_cfg[0].channels = + ucontrol->value.enumerated.item[0] + 1; + pr_debug("%s: afe_loopback_tx_ch = %d\n", __func__, + afe_loopback_tx_cfg[0].channels); + + return 1; +} + +static int usb_audio_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (usb_rx_cfg.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: usb_audio_rx_format = %d, ucontrol value = %ld\n", + __func__, usb_rx_cfg.bit_format, + ucontrol->value.integer.value[0]); + return 0; +} + +static int usb_audio_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int rc = 0; + + switch (ucontrol->value.integer.value[0]) { + case 3: + usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S32_LE; + break; + case 2: + usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: usb_audio_rx_format = %d, ucontrol value = %ld\n", + __func__, usb_rx_cfg.bit_format, + ucontrol->value.integer.value[0]); + + return rc; +} + +static int usb_audio_tx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (usb_tx_cfg.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: usb_audio_tx_format = %d, ucontrol value = %ld\n", + __func__, usb_tx_cfg.bit_format, + ucontrol->value.integer.value[0]); + return 0; +} + +static int usb_audio_tx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int rc = 0; + + switch (ucontrol->value.integer.value[0]) { + case 3: + usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S32_LE; + break; + case 2: + usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: usb_audio_tx_format = %d, ucontrol value = %ld\n", + __func__, usb_tx_cfg.bit_format, + ucontrol->value.integer.value[0]); + + return rc; +} + +static int usb_audio_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: usb_audio_rx_ch = %d\n", __func__, + usb_rx_cfg.channels); + ucontrol->value.integer.value[0] = usb_rx_cfg.channels - 1; + return 0; +} + +static int usb_audio_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + usb_rx_cfg.channels = ucontrol->value.integer.value[0] + 1; + + pr_debug("%s: usb_audio_rx_ch = %d\n", __func__, usb_rx_cfg.channels); + return 1; +} + +static int usb_audio_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: usb_audio_tx_ch = %d\n", __func__, + usb_tx_cfg.channels); + ucontrol->value.integer.value[0] = usb_tx_cfg.channels - 1; + return 0; +} + +static int usb_audio_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + usb_tx_cfg.channels = ucontrol->value.integer.value[0] + 1; + + pr_debug("%s: usb_audio_tx_ch = %d\n", __func__, usb_tx_cfg.channels); + 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 - 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 = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_vi_feed_tx_ch = %d\n", __func__, msm_vi_feed_tx_ch); + return 1; +} + + +static int proxy_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: proxy_rx channels = %d\n", + __func__, proxy_rx_cfg.channels); + ucontrol->value.integer.value[0] = proxy_rx_cfg.channels - 2; + + return 0; +} + +static int proxy_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + proxy_rx_cfg.channels = ucontrol->value.integer.value[0] + 2; + pr_debug("%s: proxy_rx channels = %d\n", + __func__, proxy_rx_cfg.channels); + + return 1; +} + +static int tdm_get_port_idx(struct snd_kcontrol *kcontrol, + struct tdm_port *port) +{ + if (port) { + if (strnstr(kcontrol->id.name, "PRI", + sizeof(kcontrol->id.name))) { + port->mode = TDM_PRI; + } else if (strnstr(kcontrol->id.name, "SEC", + sizeof(kcontrol->id.name))) { + port->mode = TDM_SEC; + } else if (strnstr(kcontrol->id.name, "TERT", + sizeof(kcontrol->id.name))) { + port->mode = TDM_TERT; + } else if (strnstr(kcontrol->id.name, "QUAT", + sizeof(kcontrol->id.name))) { + port->mode = TDM_QUAT; + } else { + pr_err("%s: unsupported mode in: %s\n", + __func__, kcontrol->id.name); + return -EINVAL; + } + + if (strnstr(kcontrol->id.name, "RX_0", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_0", + sizeof(kcontrol->id.name))) { + port->channel = TDM_0; + } else if (strnstr(kcontrol->id.name, "RX_1", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_1", + sizeof(kcontrol->id.name))) { + port->channel = TDM_1; + } else if (strnstr(kcontrol->id.name, "RX_2", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_2", + sizeof(kcontrol->id.name))) { + port->channel = TDM_2; + } else if (strnstr(kcontrol->id.name, "RX_3", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_3", + sizeof(kcontrol->id.name))) { + port->channel = TDM_3; + } else if (strnstr(kcontrol->id.name, "RX_4", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_4", + sizeof(kcontrol->id.name))) { + port->channel = TDM_4; + } else if (strnstr(kcontrol->id.name, "RX_5", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_5", + sizeof(kcontrol->id.name))) { + port->channel = TDM_5; + } else if (strnstr(kcontrol->id.name, "RX_6", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_6", + sizeof(kcontrol->id.name))) { + port->channel = TDM_6; + } else if (strnstr(kcontrol->id.name, "RX_7", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_7", + sizeof(kcontrol->id.name))) { + port->channel = TDM_7; + } else { + pr_err("%s: unsupported channel in: %s\n", + __func__, kcontrol->id.name); + return -EINVAL; + } + } else { + return -EINVAL; + } + return 0; +} + +static int tdm_get_sample_rate(int value) +{ + int sample_rate = 0; + + switch (value) { + case 0: + sample_rate = SAMPLING_RATE_8KHZ; + break; + case 1: + sample_rate = SAMPLING_RATE_16KHZ; + break; + case 2: + sample_rate = SAMPLING_RATE_32KHZ; + break; + case 3: + sample_rate = SAMPLING_RATE_48KHZ; + break; + case 4: + sample_rate = SAMPLING_RATE_176P4KHZ; + break; + case 5: + sample_rate = SAMPLING_RATE_352P8KHZ; + break; + default: + sample_rate = SAMPLING_RATE_48KHZ; + break; + } + return sample_rate; +} + +static int tdm_get_sample_rate_val(int sample_rate) +{ + int sample_rate_val = 0; + + switch (sample_rate) { + case SAMPLING_RATE_8KHZ: + sample_rate_val = 0; + break; + case SAMPLING_RATE_16KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_32KHZ: + sample_rate_val = 2; + break; + case SAMPLING_RATE_48KHZ: + sample_rate_val = 3; + break; + case SAMPLING_RATE_176P4KHZ: + sample_rate_val = 4; + break; + case SAMPLING_RATE_352P8KHZ: + sample_rate_val = 5; + break; + default: + sample_rate_val = 3; + break; + } + return sample_rate_val; +} + +static int tdm_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s\n", + __func__, kcontrol->id.name); + } else { + ucontrol->value.enumerated.item[0] = tdm_get_sample_rate_val( + tdm_rx_cfg[port.mode][port.channel].sample_rate); + + pr_debug("%s: tdm_rx_sample_rate = %d, item = %d\n", __func__, + tdm_rx_cfg[port.mode][port.channel].sample_rate, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s\n", + __func__, kcontrol->id.name); + } else { + tdm_rx_cfg[port.mode][port.channel].sample_rate = + tdm_get_sample_rate(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: tdm_rx_sample_rate = %d, item = %d\n", __func__, + tdm_rx_cfg[port.mode][port.channel].sample_rate, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_tx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s\n", + __func__, kcontrol->id.name); + } else { + ucontrol->value.enumerated.item[0] = tdm_get_sample_rate_val( + tdm_tx_cfg[port.mode][port.channel].sample_rate); + + pr_debug("%s: tdm_tx_sample_rate = %d, item = %d\n", __func__, + tdm_tx_cfg[port.mode][port.channel].sample_rate, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_tx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s\n", + __func__, kcontrol->id.name); + } else { + tdm_tx_cfg[port.mode][port.channel].sample_rate = + tdm_get_sample_rate(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: tdm_tx_sample_rate = %d, item = %d\n", __func__, + tdm_tx_cfg[port.mode][port.channel].sample_rate, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_get_format(int value) +{ + int format = 0; + + switch (value) { + case 0: + format = SNDRV_PCM_FORMAT_S16_LE; + break; + case 1: + format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 2: + format = SNDRV_PCM_FORMAT_S32_LE; + break; + default: + format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + return format; +} + +static int tdm_get_format_val(int format) +{ + int value = 0; + + switch (format) { + case SNDRV_PCM_FORMAT_S16_LE: + value = 0; + break; + case SNDRV_PCM_FORMAT_S24_LE: + value = 1; + break; + case SNDRV_PCM_FORMAT_S32_LE: + value = 2; + break; + default: + value = 0; + break; + } + return value; +} + +static int tdm_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s\n", + __func__, kcontrol->id.name); + } else { + ucontrol->value.enumerated.item[0] = tdm_get_format_val( + tdm_rx_cfg[port.mode][port.channel].bit_format); + + pr_debug("%s: tdm_rx_bit_format = %d, item = %d\n", __func__, + tdm_rx_cfg[port.mode][port.channel].bit_format, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s\n", + __func__, kcontrol->id.name); + } else { + tdm_rx_cfg[port.mode][port.channel].bit_format = + tdm_get_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: tdm_rx_bit_format = %d, item = %d\n", __func__, + tdm_rx_cfg[port.mode][port.channel].bit_format, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_tx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s\n", + __func__, kcontrol->id.name); + } else { + ucontrol->value.enumerated.item[0] = tdm_get_format_val( + tdm_tx_cfg[port.mode][port.channel].bit_format); + + pr_debug("%s: tdm_tx_bit_format = %d, item = %d\n", __func__, + tdm_tx_cfg[port.mode][port.channel].bit_format, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_tx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s\n", + __func__, kcontrol->id.name); + } else { + tdm_tx_cfg[port.mode][port.channel].bit_format = + tdm_get_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: tdm_tx_bit_format = %d, item = %d\n", __func__, + tdm_tx_cfg[port.mode][port.channel].bit_format, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s\n", + __func__, kcontrol->id.name); + } else { + + ucontrol->value.enumerated.item[0] = + tdm_rx_cfg[port.mode][port.channel].channels - 1; + + pr_debug("%s: tdm_rx_ch = %d, item = %d\n", __func__, + tdm_rx_cfg[port.mode][port.channel].channels - 1, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s\n", + __func__, kcontrol->id.name); + } else { + tdm_rx_cfg[port.mode][port.channel].channels = + ucontrol->value.enumerated.item[0] + 1; + + pr_debug("%s: tdm_rx_ch = %d, item = %d\n", __func__, + tdm_rx_cfg[port.mode][port.channel].channels, + ucontrol->value.enumerated.item[0] + 1); + } + return ret; +} + +static int tdm_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s\n", + __func__, kcontrol->id.name); + } else { + ucontrol->value.enumerated.item[0] = + tdm_tx_cfg[port.mode][port.channel].channels - 1; + + pr_debug("%s: tdm_tx_ch = %d, item = %d\n", __func__, + tdm_tx_cfg[port.mode][port.channel].channels - 1, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s\n", + __func__, kcontrol->id.name); + } else { + tdm_tx_cfg[port.mode][port.channel].channels = + ucontrol->value.enumerated.item[0] + 1; + + pr_debug("%s: tdm_tx_ch = %d, item = %d\n", __func__, + tdm_tx_cfg[port.mode][port.channel].channels, + ucontrol->value.enumerated.item[0] + 1); + } + return ret; +} + +static int tdm_slot_map_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int slot_index = 0; + int interface = ucontrol->value.integer.value[0]; + int channel = ucontrol->value.integer.value[1]; + unsigned int offset_val = 0; + unsigned int *slot_offset = NULL; + struct tdm_dev_config *config = NULL; + + if (interface < 0 || interface >= (TDM_INTERFACE_MAX * MAX_PATH)) { + pr_err("%s: incorrect interface = %d\n", __func__, interface); + return -EINVAL; + } + if (channel < 0 || channel >= TDM_PORT_MAX) { + pr_err("%s: incorrect channel = %d\n", __func__, channel); + return -EINVAL; + } + + pr_debug("%s: interface = %d, channel = %d\n", __func__, + interface, channel); + + config = ((struct tdm_dev_config *) tdm_cfg[interface / MAX_PATH]) + + ((interface % MAX_PATH) * TDM_PORT_MAX) + channel; + slot_offset = config->tdm_slot_offset; + + for (slot_index = 0; slot_index < TDM_MAX_SLOTS; slot_index++) { + offset_val = ucontrol->value.integer.value[MAX_PATH + + slot_index]; + /* Offset value can only be 0, 4, 8, ..28 */ + if (offset_val % 4 == 0 && offset_val <= 28) + slot_offset[slot_index] = offset_val; + pr_debug("%s: slot offset[%d] = %d\n", __func__, + slot_index, slot_offset[slot_index]); + } + + return 0; +} + +static int aux_pcm_get_port_idx(struct snd_kcontrol *kcontrol) +{ + int idx = 0; + + if (strnstr(kcontrol->id.name, "PRIM_AUX_PCM", + sizeof("PRIM_AUX_PCM"))) { + idx = PRIM_AUX_PCM; + } else if (strnstr(kcontrol->id.name, "SEC_AUX_PCM", + sizeof("SEC_AUX_PCM"))) { + idx = SEC_AUX_PCM; + } else if (strnstr(kcontrol->id.name, "TERT_AUX_PCM", + sizeof("TERT_AUX_PCM"))) { + idx = TERT_AUX_PCM; + } else if (strnstr(kcontrol->id.name, "QUAT_AUX_PCM", + sizeof("QUAT_AUX_PCM"))) { + idx = QUAT_AUX_PCM; + } else { + pr_err("%s: unsupported port: %s\n", + __func__, kcontrol->id.name); + idx = -EINVAL; + } + + return idx; +} + +static int aux_pcm_get_sample_rate(int value) +{ + int sample_rate = 0; + + switch (value) { + case 1: + sample_rate = SAMPLING_RATE_16KHZ; + break; + case 0: + default: + sample_rate = SAMPLING_RATE_8KHZ; + break; + } + return sample_rate; +} + +static int aux_pcm_get_sample_rate_val(int sample_rate) +{ + int sample_rate_val = 0; + + switch (sample_rate) { + case SAMPLING_RATE_16KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_8KHZ: + default: + sample_rate_val = 0; + break; + } + return sample_rate_val; +} + +static int mi2s_auxpcm_get_format(int value) +{ + int format = 0; + + switch (value) { + case 0: + format = SNDRV_PCM_FORMAT_S16_LE; + break; + case 1: + format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 2: + format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 3: + format = SNDRV_PCM_FORMAT_S32_LE; + break; + default: + format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + return format; +} + +static int mi2s_auxpcm_get_format_value(int format) +{ + int value = 0; + + switch (format) { + case SNDRV_PCM_FORMAT_S16_LE: + value = 0; + break; + case SNDRV_PCM_FORMAT_S24_LE: + value = 1; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + value = 2; + break; + case SNDRV_PCM_FORMAT_S32_LE: + value = 3; + break; + default: + value = 0; + break; + } + return value; +} + +static int aux_pcm_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = aux_pcm_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + aux_pcm_get_sample_rate_val(aux_pcm_rx_cfg[idx].sample_rate); + + pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__, + idx, aux_pcm_rx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int aux_pcm_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = aux_pcm_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + aux_pcm_rx_cfg[idx].sample_rate = + aux_pcm_get_sample_rate(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__, + idx, aux_pcm_rx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int aux_pcm_tx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = aux_pcm_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + aux_pcm_get_sample_rate_val(aux_pcm_tx_cfg[idx].sample_rate); + + pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__, + idx, aux_pcm_tx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int aux_pcm_tx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = aux_pcm_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + aux_pcm_tx_cfg[idx].sample_rate = + aux_pcm_get_sample_rate(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__, + idx, aux_pcm_tx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_aux_pcm_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = aux_pcm_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + mi2s_auxpcm_get_format_value(aux_pcm_rx_cfg[idx].bit_format); + + pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__, + idx, aux_pcm_rx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_aux_pcm_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = aux_pcm_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + aux_pcm_rx_cfg[idx].bit_format = + mi2s_auxpcm_get_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__, + idx, aux_pcm_rx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_aux_pcm_tx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = aux_pcm_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + mi2s_auxpcm_get_format_value(aux_pcm_tx_cfg[idx].bit_format); + + pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__, + idx, aux_pcm_tx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_aux_pcm_tx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = aux_pcm_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + aux_pcm_tx_cfg[idx].bit_format = + mi2s_auxpcm_get_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__, + idx, aux_pcm_tx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int mi2s_get_port_idx(struct snd_kcontrol *kcontrol) +{ + int idx = 0; + + if (strnstr(kcontrol->id.name, "PRIM_MI2S_RX", + sizeof("PRIM_MI2S_RX"))) { + idx = PRIM_MI2S; + } else if (strnstr(kcontrol->id.name, "SEC_MI2S_RX", + sizeof("SEC_MI2S_RX"))) { + idx = SEC_MI2S; + } else if (strnstr(kcontrol->id.name, "TERT_MI2S_RX", + sizeof("TERT_MI2S_RX"))) { + idx = TERT_MI2S; + } else if (strnstr(kcontrol->id.name, "QUAT_MI2S_RX", + sizeof("QUAT_MI2S_RX"))) { + idx = QUAT_MI2S; + } else if (strnstr(kcontrol->id.name, "PRIM_MI2S_TX", + sizeof("PRIM_MI2S_TX"))) { + idx = PRIM_MI2S; + } else if (strnstr(kcontrol->id.name, "SEC_MI2S_TX", + sizeof("SEC_MI2S_TX"))) { + idx = SEC_MI2S; + } else if (strnstr(kcontrol->id.name, "TERT_MI2S_TX", + sizeof("TERT_MI2S_TX"))) { + idx = TERT_MI2S; + } else if (strnstr(kcontrol->id.name, "QUAT_MI2S_TX", + sizeof("QUAT_MI2S_TX"))) { + idx = QUAT_MI2S; + } else { + pr_err("%s: unsupported channel: %s\n", + __func__, kcontrol->id.name); + idx = -EINVAL; + } + + return idx; +} + +static int mi2s_get_sample_rate(int value) +{ + int sample_rate = 0; + + switch (value) { + case 0: + sample_rate = SAMPLING_RATE_8KHZ; + break; + case 1: + sample_rate = SAMPLING_RATE_11P025KHZ; + break; + case 2: + sample_rate = SAMPLING_RATE_16KHZ; + break; + case 3: + sample_rate = SAMPLING_RATE_22P05KHZ; + break; + case 4: + sample_rate = SAMPLING_RATE_32KHZ; + break; + case 5: + sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 6: + sample_rate = SAMPLING_RATE_48KHZ; + break; + case 7: + sample_rate = SAMPLING_RATE_88P2KHZ; + break; + case 8: + sample_rate = SAMPLING_RATE_96KHZ; + break; + case 9: + sample_rate = SAMPLING_RATE_176P4KHZ; + break; + case 10: + sample_rate = SAMPLING_RATE_192KHZ; + break; + case 11: + sample_rate = SAMPLING_RATE_352P8KHZ; + break; + case 12: + sample_rate = SAMPLING_RATE_384KHZ; + break; + default: + sample_rate = SAMPLING_RATE_48KHZ; + break; + } + return sample_rate; +} + +static int mi2s_get_sample_rate_val(int sample_rate) +{ + int sample_rate_val = 0; + + switch (sample_rate) { + case SAMPLING_RATE_8KHZ: + sample_rate_val = 0; + break; + case SAMPLING_RATE_11P025KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_16KHZ: + sample_rate_val = 2; + break; + case SAMPLING_RATE_22P05KHZ: + sample_rate_val = 3; + break; + case SAMPLING_RATE_32KHZ: + sample_rate_val = 4; + break; + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 5; + break; + case SAMPLING_RATE_48KHZ: + sample_rate_val = 6; + break; + case SAMPLING_RATE_88P2KHZ: + sample_rate_val = 7; + break; + case SAMPLING_RATE_96KHZ: + sample_rate_val = 8; + break; + case SAMPLING_RATE_176P4KHZ: + sample_rate_val = 9; + break; + case SAMPLING_RATE_192KHZ: + sample_rate_val = 10; + break; + case SAMPLING_RATE_352P8KHZ: + sample_rate_val = 11; + break; + case SAMPLING_RATE_384KHZ: + sample_rate_val = 12; + break; + default: + sample_rate_val = 6; + break; + } + return sample_rate_val; +} + +static int mi2s_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + mi2s_get_sample_rate_val(mi2s_rx_cfg[idx].sample_rate); + + pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__, + idx, mi2s_rx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int mi2s_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + mi2s_rx_cfg[idx].sample_rate = + mi2s_get_sample_rate(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__, + idx, mi2s_rx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int mi2s_tx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + mi2s_get_sample_rate_val(mi2s_tx_cfg[idx].sample_rate); + + pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__, + idx, mi2s_tx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int mi2s_tx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + mi2s_tx_cfg[idx].sample_rate = + mi2s_get_sample_rate(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__, + idx, mi2s_tx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_mi2s_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + mi2s_auxpcm_get_format_value(mi2s_rx_cfg[idx].bit_format); + + pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__, + idx, mi2s_rx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_mi2s_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + mi2s_rx_cfg[idx].bit_format = + mi2s_auxpcm_get_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__, + idx, mi2s_rx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_mi2s_tx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + mi2s_auxpcm_get_format_value(mi2s_tx_cfg[idx].bit_format); + + pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__, + idx, mi2s_tx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_mi2s_tx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + mi2s_tx_cfg[idx].bit_format = + mi2s_auxpcm_get_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__, + idx, mi2s_tx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} +static int msm_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + pr_debug("%s: msm_mi2s_[%d]_rx_ch = %d\n", __func__, + idx, mi2s_rx_cfg[idx].channels); + ucontrol->value.enumerated.item[0] = mi2s_rx_cfg[idx].channels - 1; + + return 0; +} + +static int msm_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + mi2s_rx_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1; + pr_debug("%s: msm_mi2s_[%d]_rx_ch = %d\n", __func__, + idx, mi2s_rx_cfg[idx].channels); + + return 1; +} + +static int msm_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + pr_debug("%s: msm_mi2s_[%d]_tx_ch = %d\n", __func__, + idx, mi2s_tx_cfg[idx].channels); + ucontrol->value.enumerated.item[0] = mi2s_tx_cfg[idx].channels - 1; + + return 0; +} + +static int msm_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + mi2s_tx_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1; + pr_debug("%s: msm_mi2s_[%d]_tx_ch = %d\n", __func__, + idx, mi2s_tx_cfg[idx].channels); + + return 1; +} + +static int msm_get_port_id(int be_id) +{ + int afe_port_id = 0; + + switch (be_id) { + case MSM_BACKEND_DAI_PRI_MI2S_RX: + afe_port_id = AFE_PORT_ID_PRIMARY_MI2S_RX; + break; + case MSM_BACKEND_DAI_PRI_MI2S_TX: + afe_port_id = AFE_PORT_ID_PRIMARY_MI2S_TX; + break; + case MSM_BACKEND_DAI_SECONDARY_MI2S_RX: + afe_port_id = AFE_PORT_ID_SECONDARY_MI2S_RX; + break; + case MSM_BACKEND_DAI_SECONDARY_MI2S_TX: + afe_port_id = AFE_PORT_ID_SECONDARY_MI2S_TX; + break; + case MSM_BACKEND_DAI_TERTIARY_MI2S_RX: + afe_port_id = AFE_PORT_ID_TERTIARY_MI2S_RX; + break; + case MSM_BACKEND_DAI_TERTIARY_MI2S_TX: + afe_port_id = AFE_PORT_ID_TERTIARY_MI2S_TX; + break; + case MSM_BACKEND_DAI_QUATERNARY_MI2S_RX: + afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_RX; + break; + case MSM_BACKEND_DAI_QUATERNARY_MI2S_TX: + afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX; + break; + case MSM_BACKEND_DAI_VA_CDC_DMA_TX_0: + afe_port_id = AFE_PORT_ID_VA_CODEC_DMA_TX_0; + break; + case MSM_BACKEND_DAI_VA_CDC_DMA_TX_1: + afe_port_id = AFE_PORT_ID_VA_CODEC_DMA_TX_1; + break; + case MSM_BACKEND_DAI_VA_CDC_DMA_TX_2: + afe_port_id = AFE_PORT_ID_VA_CODEC_DMA_TX_2; + break; + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_0: + afe_port_id = AFE_PORT_ID_RX_CODEC_DMA_RX_0; + break; + case MSM_BACKEND_DAI_TX_CDC_DMA_TX_0: + afe_port_id = AFE_PORT_ID_TX_CODEC_DMA_TX_0; + break; + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_1: + afe_port_id = AFE_PORT_ID_RX_CODEC_DMA_RX_1; + break; + case MSM_BACKEND_DAI_TX_CDC_DMA_TX_1: + afe_port_id = AFE_PORT_ID_TX_CODEC_DMA_TX_1; + break; + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_2: + afe_port_id = AFE_PORT_ID_RX_CODEC_DMA_RX_2; + break; + case MSM_BACKEND_DAI_TX_CDC_DMA_TX_2: + afe_port_id = AFE_PORT_ID_TX_CODEC_DMA_TX_2; + break; + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_3: + afe_port_id = AFE_PORT_ID_RX_CODEC_DMA_RX_3; + break; + case MSM_BACKEND_DAI_TX_CDC_DMA_TX_3: + afe_port_id = AFE_PORT_ID_TX_CODEC_DMA_TX_3; + break; + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_4: + afe_port_id = AFE_PORT_ID_RX_CODEC_DMA_RX_4; + break; + case MSM_BACKEND_DAI_TX_CDC_DMA_TX_4: + afe_port_id = AFE_PORT_ID_TX_CODEC_DMA_TX_4; + break; + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_5: + afe_port_id = AFE_PORT_ID_RX_CODEC_DMA_RX_5; + break; + case MSM_BACKEND_DAI_TX_CDC_DMA_TX_5: + afe_port_id = AFE_PORT_ID_TX_CODEC_DMA_TX_5; + break; + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_6: + afe_port_id = AFE_PORT_ID_RX_CODEC_DMA_RX_6; + break; + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_7: + afe_port_id = AFE_PORT_ID_RX_CODEC_DMA_RX_7; + break; + default: + pr_err("%s: Invalid BE id: %d\n", __func__, be_id); + afe_port_id = -EINVAL; + } + + return afe_port_id; +} + +static u32 get_mi2s_bits_per_sample(u32 bit_format) +{ + u32 bit_per_sample = 0; + + switch (bit_format) { + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_S24_3LE: + case SNDRV_PCM_FORMAT_S24_LE: + bit_per_sample = 32; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + bit_per_sample = 16; + break; + } + + return bit_per_sample; +} + +static void update_mi2s_clk_val(int dai_id, int stream) +{ + u32 bit_per_sample = 0; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + bit_per_sample = + get_mi2s_bits_per_sample(mi2s_rx_cfg[dai_id].bit_format); + mi2s_clk[dai_id].clk_freq_in_hz = + mi2s_rx_cfg[dai_id].sample_rate * 2 * bit_per_sample; + } else { + bit_per_sample = + get_mi2s_bits_per_sample(mi2s_tx_cfg[dai_id].bit_format); + mi2s_clk[dai_id].clk_freq_in_hz = + mi2s_tx_cfg[dai_id].sample_rate * 2 * bit_per_sample; + } +} + +static int msm_mi2s_set_sclk(struct snd_pcm_substream *substream, bool enable) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int port_id = 0; + int index = cpu_dai->id; + + port_id = msm_get_port_id(rtd->dai_link->id); + if (port_id < 0) { + dev_err(rtd->card->dev, "%s: Invalid port_id\n", __func__); + ret = port_id; + goto err; + } + + if (enable) { + update_mi2s_clk_val(index, substream->stream); + dev_dbg(rtd->card->dev, "%s: clock rate %ul\n", __func__, + mi2s_clk[index].clk_freq_in_hz); + } + + mi2s_clk[index].enable = enable; + ret = afe_set_lpass_clock_v2(port_id, + &mi2s_clk[index]); + if (ret < 0) { + dev_err(rtd->card->dev, + "%s: afe lpass clock failed for port 0x%x , err:%d\n", + __func__, port_id, ret); + goto err; + } + +err: + return ret; +} + +static int cdc_dma_get_port_idx(struct snd_kcontrol *kcontrol) +{ + int idx = 0; + + if (strnstr(kcontrol->id.name, "RX_CDC_DMA_RX_0", + sizeof("RX_CDC_DMA_RX_0"))) + idx = RX_CDC_DMA_RX_0; + else if (strnstr(kcontrol->id.name, "RX_CDC_DMA_RX_1", + sizeof("RX_CDC_DMA_RX_1"))) + idx = RX_CDC_DMA_RX_1; + else if (strnstr(kcontrol->id.name, "RX_CDC_DMA_RX_2", + sizeof("RX_CDC_DMA_RX_2"))) + idx = RX_CDC_DMA_RX_2; + else if (strnstr(kcontrol->id.name, "RX_CDC_DMA_RX_3", + sizeof("RX_CDC_DMA_RX_3"))) + idx = RX_CDC_DMA_RX_3; + else if (strnstr(kcontrol->id.name, "RX_CDC_DMA_RX_5", + sizeof("RX_CDC_DMA_RX_5"))) + idx = RX_CDC_DMA_RX_5; + else if (strnstr(kcontrol->id.name, "RX_CDC_DMA_RX_6", + sizeof("RX_CDC_DMA_RX_6"))) + idx = RX_CDC_DMA_RX_6; + else if (strnstr(kcontrol->id.name, "TX_CDC_DMA_TX_0", + sizeof("TX_CDC_DMA_TX_0"))) + idx = TX_CDC_DMA_TX_0; + else if (strnstr(kcontrol->id.name, "TX_CDC_DMA_TX_3", + sizeof("TX_CDC_DMA_TX_3"))) + idx = TX_CDC_DMA_TX_3; + else if (strnstr(kcontrol->id.name, "TX_CDC_DMA_TX_4", + sizeof("TX_CDC_DMA_TX_4"))) + idx = TX_CDC_DMA_TX_4; + else if (strnstr(kcontrol->id.name, "VA_CDC_DMA_TX_0", + sizeof("VA_CDC_DMA_TX_0"))) + idx = VA_CDC_DMA_TX_0; + else if (strnstr(kcontrol->id.name, "VA_CDC_DMA_TX_1", + sizeof("VA_CDC_DMA_TX_1"))) + idx = VA_CDC_DMA_TX_1; + else if (strnstr(kcontrol->id.name, "VA_CDC_DMA_TX_2", + sizeof("VA_CDC_DMA_TX_2"))) + idx = VA_CDC_DMA_TX_2; + else { + pr_err("%s: unsupported channel: %s\n", + __func__, kcontrol->id.name); + return -EINVAL; + } + + return idx; +} + +static int cdc_dma_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = cdc_dma_get_port_idx(kcontrol); + + if (ch_num < 0 || ch_num >= CDC_DMA_RX_MAX) { + pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num); + return ch_num; + } + + pr_debug("%s: cdc_dma_rx_ch = %d\n", __func__, + cdc_dma_rx_cfg[ch_num].channels - 1); + ucontrol->value.integer.value[0] = cdc_dma_rx_cfg[ch_num].channels - 1; + return 0; +} + +static int cdc_dma_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = cdc_dma_get_port_idx(kcontrol); + + if (ch_num < 0 || ch_num >= CDC_DMA_RX_MAX) { + pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num); + return ch_num; + } + + cdc_dma_rx_cfg[ch_num].channels = ucontrol->value.integer.value[0] + 1; + + pr_debug("%s: cdc_dma_rx_ch = %d\n", __func__, + cdc_dma_rx_cfg[ch_num].channels); + return 1; +} + +static int cdc_dma_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = cdc_dma_get_port_idx(kcontrol); + + if (ch_num < 0 || ch_num >= CDC_DMA_RX_MAX) { + pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num); + return ch_num; + } + + switch (cdc_dma_rx_cfg[ch_num].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: cdc_dma_rx_format = %d, ucontrol value = %ld\n", + __func__, cdc_dma_rx_cfg[ch_num].bit_format, + ucontrol->value.integer.value[0]); + return 0; +} + +static int cdc_dma_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int rc = 0; + int ch_num = cdc_dma_get_port_idx(kcontrol); + + if (ch_num < 0 || ch_num >= CDC_DMA_RX_MAX) { + pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num); + return ch_num; + } + + switch (ucontrol->value.integer.value[0]) { + case 3: + cdc_dma_rx_cfg[ch_num].bit_format = SNDRV_PCM_FORMAT_S32_LE; + break; + case 2: + cdc_dma_rx_cfg[ch_num].bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + cdc_dma_rx_cfg[ch_num].bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + cdc_dma_rx_cfg[ch_num].bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: cdc_dma_rx_format = %d, ucontrol value = %ld\n", + __func__, cdc_dma_rx_cfg[ch_num].bit_format, + ucontrol->value.integer.value[0]); + + return rc; +} + + +static int cdc_dma_get_sample_rate_val(int sample_rate) +{ + int sample_rate_val = 0; + + switch (sample_rate) { + case SAMPLING_RATE_8KHZ: + sample_rate_val = 0; + break; + case SAMPLING_RATE_11P025KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_16KHZ: + sample_rate_val = 2; + break; + case SAMPLING_RATE_22P05KHZ: + sample_rate_val = 3; + break; + case SAMPLING_RATE_32KHZ: + sample_rate_val = 4; + break; + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 5; + break; + case SAMPLING_RATE_48KHZ: + sample_rate_val = 6; + break; + case SAMPLING_RATE_88P2KHZ: + sample_rate_val = 7; + break; + case SAMPLING_RATE_96KHZ: + sample_rate_val = 8; + break; + case SAMPLING_RATE_176P4KHZ: + sample_rate_val = 9; + break; + case SAMPLING_RATE_192KHZ: + sample_rate_val = 10; + break; + case SAMPLING_RATE_352P8KHZ: + sample_rate_val = 11; + break; + case SAMPLING_RATE_384KHZ: + sample_rate_val = 12; + break; + default: + sample_rate_val = 6; + break; + } + return sample_rate_val; +} + +static int cdc_dma_get_sample_rate(int value) +{ + int sample_rate = 0; + + switch (value) { + case 0: + sample_rate = SAMPLING_RATE_8KHZ; + break; + case 1: + sample_rate = SAMPLING_RATE_11P025KHZ; + break; + case 2: + sample_rate = SAMPLING_RATE_16KHZ; + break; + case 3: + sample_rate = SAMPLING_RATE_22P05KHZ; + break; + case 4: + sample_rate = SAMPLING_RATE_32KHZ; + break; + case 5: + sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 6: + sample_rate = SAMPLING_RATE_48KHZ; + break; + case 7: + sample_rate = SAMPLING_RATE_88P2KHZ; + break; + case 8: + sample_rate = SAMPLING_RATE_96KHZ; + break; + case 9: + sample_rate = SAMPLING_RATE_176P4KHZ; + break; + case 10: + sample_rate = SAMPLING_RATE_192KHZ; + break; + case 11: + sample_rate = SAMPLING_RATE_352P8KHZ; + break; + case 12: + sample_rate = SAMPLING_RATE_384KHZ; + break; + default: + sample_rate = SAMPLING_RATE_48KHZ; + break; + } + return sample_rate; +} + +static int cdc_dma_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = cdc_dma_get_port_idx(kcontrol); + + if (ch_num < 0 || ch_num >= CDC_DMA_RX_MAX) { + pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num); + return ch_num; + } + + ucontrol->value.enumerated.item[0] = + cdc_dma_get_sample_rate_val(cdc_dma_rx_cfg[ch_num].sample_rate); + + pr_debug("%s: cdc_dma_rx_sample_rate = %d\n", __func__, + cdc_dma_rx_cfg[ch_num].sample_rate); + return 0; +} + +static int cdc_dma_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = cdc_dma_get_port_idx(kcontrol); + + if (ch_num < 0 || ch_num >= CDC_DMA_RX_MAX) { + pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num); + return ch_num; + } + + cdc_dma_rx_cfg[ch_num].sample_rate = + cdc_dma_get_sample_rate(ucontrol->value.enumerated.item[0]); + + + pr_debug("%s: control value = %d, cdc_dma_rx_sample_rate = %d\n", + __func__, ucontrol->value.enumerated.item[0], + cdc_dma_rx_cfg[ch_num].sample_rate); + return 0; +} + +static int cdc_dma_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = cdc_dma_get_port_idx(kcontrol); + + if (ch_num < 0) { + pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num); + return ch_num; + } + + pr_debug("%s: cdc_dma_tx_ch = %d\n", __func__, + cdc_dma_tx_cfg[ch_num].channels); + ucontrol->value.integer.value[0] = cdc_dma_tx_cfg[ch_num].channels - 1; + return 0; +} + +static int cdc_dma_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = cdc_dma_get_port_idx(kcontrol); + + if (ch_num < 0) { + pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num); + return ch_num; + } + + cdc_dma_tx_cfg[ch_num].channels = ucontrol->value.integer.value[0] + 1; + + pr_debug("%s: cdc_dma_tx_ch = %d\n", __func__, + cdc_dma_tx_cfg[ch_num].channels); + return 1; +} + +static int cdc_dma_tx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate_val; + int ch_num = cdc_dma_get_port_idx(kcontrol); + + if (ch_num < 0) { + pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num); + return ch_num; + } + + switch (cdc_dma_tx_cfg[ch_num].sample_rate) { + case SAMPLING_RATE_384KHZ: + sample_rate_val = 12; + break; + case SAMPLING_RATE_352P8KHZ: + sample_rate_val = 11; + break; + case SAMPLING_RATE_192KHZ: + sample_rate_val = 10; + break; + case SAMPLING_RATE_176P4KHZ: + sample_rate_val = 9; + break; + case SAMPLING_RATE_96KHZ: + sample_rate_val = 8; + break; + case SAMPLING_RATE_88P2KHZ: + sample_rate_val = 7; + break; + case SAMPLING_RATE_48KHZ: + sample_rate_val = 6; + break; + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 5; + break; + case SAMPLING_RATE_32KHZ: + sample_rate_val = 4; + break; + case SAMPLING_RATE_22P05KHZ: + sample_rate_val = 3; + break; + case SAMPLING_RATE_16KHZ: + sample_rate_val = 2; + break; + case SAMPLING_RATE_11P025KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_8KHZ: + sample_rate_val = 0; + break; + default: + sample_rate_val = 6; + break; + } + + ucontrol->value.integer.value[0] = sample_rate_val; + pr_debug("%s: cdc_dma_tx_sample_rate = %d\n", __func__, + cdc_dma_tx_cfg[ch_num].sample_rate); + return 0; +} + +static int cdc_dma_tx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = cdc_dma_get_port_idx(kcontrol); + + if (ch_num < 0) { + pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num); + return ch_num; + } + + switch (ucontrol->value.integer.value[0]) { + case 12: + cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_384KHZ; + break; + case 11: + cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_352P8KHZ; + break; + case 10: + cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_192KHZ; + break; + case 9: + cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_176P4KHZ; + break; + case 8: + cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_96KHZ; + break; + case 7: + cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_88P2KHZ; + break; + case 6: + cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_48KHZ; + break; + case 5: + cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 4: + cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_32KHZ; + break; + case 3: + cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_22P05KHZ; + break; + case 2: + cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_16KHZ; + break; + case 1: + cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_11P025KHZ; + break; + case 0: + cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_8KHZ; + break; + default: + cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_48KHZ; + break; + } + + pr_debug("%s: control value = %ld, cdc_dma_tx_sample_rate = %d\n", + __func__, ucontrol->value.integer.value[0], + cdc_dma_tx_cfg[ch_num].sample_rate); + return 0; +} + +static int cdc_dma_tx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = cdc_dma_get_port_idx(kcontrol); + + if (ch_num < 0) { + pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num); + return ch_num; + } + + switch (cdc_dma_tx_cfg[ch_num].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: cdc_dma_tx_format = %d, ucontrol value = %ld\n", + __func__, cdc_dma_tx_cfg[ch_num].bit_format, + ucontrol->value.integer.value[0]); + return 0; +} + +static int cdc_dma_tx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int rc = 0; + int ch_num = cdc_dma_get_port_idx(kcontrol); + + if (ch_num < 0) { + pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num); + return ch_num; + } + + switch (ucontrol->value.integer.value[0]) { + case 3: + cdc_dma_tx_cfg[ch_num].bit_format = SNDRV_PCM_FORMAT_S32_LE; + break; + case 2: + cdc_dma_tx_cfg[ch_num].bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + cdc_dma_tx_cfg[ch_num].bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + cdc_dma_tx_cfg[ch_num].bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: cdc_dma_tx_format = %d, ucontrol value = %ld\n", + __func__, cdc_dma_tx_cfg[ch_num].bit_format, + ucontrol->value.integer.value[0]); + + return rc; +} + +static int msm_cdc_dma_get_idx_from_beid(int32_t be_id) +{ + int idx = 0; + + switch (be_id) { + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_0: + idx = RX_CDC_DMA_RX_0; + break; + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_1: + idx = RX_CDC_DMA_RX_1; + break; + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_2: + idx = RX_CDC_DMA_RX_2; + break; + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_3: + idx = RX_CDC_DMA_RX_3; + break; + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_5: + idx = RX_CDC_DMA_RX_5; + break; + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_6: + idx = RX_CDC_DMA_RX_6; + break; + case MSM_BACKEND_DAI_TX_CDC_DMA_TX_0: + idx = TX_CDC_DMA_TX_0; + break; + case MSM_BACKEND_DAI_TX_CDC_DMA_TX_3: + idx = TX_CDC_DMA_TX_3; + break; + case MSM_BACKEND_DAI_TX_CDC_DMA_TX_4: + idx = TX_CDC_DMA_TX_4; + break; + case MSM_BACKEND_DAI_VA_CDC_DMA_TX_0: + idx = VA_CDC_DMA_TX_0; + break; + case MSM_BACKEND_DAI_VA_CDC_DMA_TX_1: + idx = VA_CDC_DMA_TX_1; + break; + case MSM_BACKEND_DAI_VA_CDC_DMA_TX_2: + idx = VA_CDC_DMA_TX_2; + break; + default: + idx = RX_CDC_DMA_RX_0; + break; + } + + return idx; +} + +static int msm_bt_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + /* + * Slimbus_7_Rx/Tx sample rate values should always be in sync (same) + * when used for BT_SCO use case. Return either Rx or Tx sample rate + * value. + */ + switch (slim_rx_cfg[SLIM_RX_7].sample_rate) { + case SAMPLING_RATE_96KHZ: + ucontrol->value.integer.value[0] = 5; + break; + case SAMPLING_RATE_88P2KHZ: + ucontrol->value.integer.value[0] = 4; + break; + case SAMPLING_RATE_48KHZ: + ucontrol->value.integer.value[0] = 3; + break; + case SAMPLING_RATE_44P1KHZ: + ucontrol->value.integer.value[0] = 2; + break; + case SAMPLING_RATE_16KHZ: + ucontrol->value.integer.value[0] = 1; + break; + case SAMPLING_RATE_8KHZ: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: sample rate = %d\n", __func__, + slim_rx_cfg[SLIM_RX_7].sample_rate); + + return 0; +} + +static int msm_bt_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 1: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_16KHZ; + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_16KHZ; + break; + case 2: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_44P1KHZ; + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 3: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_48KHZ; + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_48KHZ; + break; + case 4: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_88P2KHZ; + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_88P2KHZ; + break; + case 5: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_96KHZ; + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_96KHZ; + break; + case 0: + default: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_8KHZ; + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_8KHZ; + break; + } + pr_debug("%s: sample rates: slim7_rx = %d, slim7_tx = %d, value = %d\n", + __func__, + slim_rx_cfg[SLIM_RX_7].sample_rate, + slim_tx_cfg[SLIM_TX_7].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_bt_sample_rate_rx_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (slim_rx_cfg[SLIM_RX_7].sample_rate) { + case SAMPLING_RATE_96KHZ: + ucontrol->value.integer.value[0] = 5; + break; + case SAMPLING_RATE_88P2KHZ: + ucontrol->value.integer.value[0] = 4; + break; + case SAMPLING_RATE_48KHZ: + ucontrol->value.integer.value[0] = 3; + break; + case SAMPLING_RATE_44P1KHZ: + ucontrol->value.integer.value[0] = 2; + break; + case SAMPLING_RATE_16KHZ: + ucontrol->value.integer.value[0] = 1; + break; + case SAMPLING_RATE_8KHZ: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: sample rate rx = %d\n", __func__, + slim_rx_cfg[SLIM_RX_7].sample_rate); + + return 0; +} + +static int msm_bt_sample_rate_rx_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 1: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_16KHZ; + break; + case 2: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 3: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_48KHZ; + break; + case 4: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_88P2KHZ; + break; + case 5: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_96KHZ; + break; + case 0: + default: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_8KHZ; + break; + } + pr_debug("%s: sample rate: slim7_rx = %d, value = %d\n", + __func__, + slim_rx_cfg[SLIM_RX_7].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_bt_sample_rate_tx_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (slim_tx_cfg[SLIM_TX_7].sample_rate) { + case SAMPLING_RATE_96KHZ: + ucontrol->value.integer.value[0] = 5; + break; + case SAMPLING_RATE_88P2KHZ: + ucontrol->value.integer.value[0] = 4; + break; + case SAMPLING_RATE_48KHZ: + ucontrol->value.integer.value[0] = 3; + break; + case SAMPLING_RATE_44P1KHZ: + ucontrol->value.integer.value[0] = 2; + break; + case SAMPLING_RATE_16KHZ: + ucontrol->value.integer.value[0] = 1; + break; + case SAMPLING_RATE_8KHZ: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: sample rate tx = %d\n", __func__, + slim_tx_cfg[SLIM_TX_7].sample_rate); + + return 0; +} + +static int msm_bt_sample_rate_tx_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 1: + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_16KHZ; + break; + case 2: + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 3: + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_48KHZ; + break; + case 4: + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_88P2KHZ; + break; + case 5: + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_96KHZ; + break; + case 0: + default: + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_8KHZ; + break; + } + pr_debug("%s: sample rate: slim7_tx = %d, value = %d\n", + __func__, + slim_tx_cfg[SLIM_TX_7].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static const struct snd_kcontrol_new msm_int_wcd937x_snd_controls[] = { + SOC_ENUM_EXT("RX_CDC_DMA_RX_0 Format", rx_cdc_dma_rx_0_format, + cdc_dma_rx_format_get, cdc_dma_rx_format_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_1 Format", rx_cdc_dma_rx_1_format, + cdc_dma_rx_format_get, cdc_dma_rx_format_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_2 Format", rx_cdc_dma_rx_2_format, + cdc_dma_rx_format_get, cdc_dma_rx_format_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_3 Format", rx_cdc_dma_rx_3_format, + cdc_dma_rx_format_get, cdc_dma_rx_format_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_5 Format", rx_cdc_dma_rx_5_format, + cdc_dma_rx_format_get, cdc_dma_rx_format_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_0 SampleRate", + rx_cdc_dma_rx_0_sample_rate, + cdc_dma_rx_sample_rate_get, + cdc_dma_rx_sample_rate_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_1 SampleRate", + rx_cdc_dma_rx_1_sample_rate, + cdc_dma_rx_sample_rate_get, + cdc_dma_rx_sample_rate_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_2 SampleRate", + rx_cdc_dma_rx_2_sample_rate, + cdc_dma_rx_sample_rate_get, + cdc_dma_rx_sample_rate_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_3 SampleRate", + rx_cdc_dma_rx_3_sample_rate, + cdc_dma_rx_sample_rate_get, + cdc_dma_rx_sample_rate_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_5 SampleRate", + rx_cdc_dma_rx_5_sample_rate, + cdc_dma_rx_sample_rate_get, + cdc_dma_rx_sample_rate_put), +}; + +static const struct snd_kcontrol_new msm_int_snd_controls[] = { + SOC_ENUM_EXT("RX_CDC_DMA_RX_0 Channels", rx_cdc_dma_rx_0_chs, + cdc_dma_rx_ch_get, cdc_dma_rx_ch_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_1 Channels", rx_cdc_dma_rx_1_chs, + cdc_dma_rx_ch_get, cdc_dma_rx_ch_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_2 Channels", rx_cdc_dma_rx_2_chs, + cdc_dma_rx_ch_get, cdc_dma_rx_ch_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_3 Channels", rx_cdc_dma_rx_3_chs, + cdc_dma_rx_ch_get, cdc_dma_rx_ch_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_5 Channels", rx_cdc_dma_rx_5_chs, + cdc_dma_rx_ch_get, cdc_dma_rx_ch_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_6 Channels", rx_cdc_dma_rx_6_chs, + cdc_dma_rx_ch_get, cdc_dma_rx_ch_put), + SOC_ENUM_EXT("TX_CDC_DMA_TX_0 Channels", tx_cdc_dma_tx_0_chs, + cdc_dma_tx_ch_get, cdc_dma_tx_ch_put), + SOC_ENUM_EXT("TX_CDC_DMA_TX_3 Channels", tx_cdc_dma_tx_3_chs, + cdc_dma_tx_ch_get, cdc_dma_tx_ch_put), + SOC_ENUM_EXT("TX_CDC_DMA_TX_4 Channels", tx_cdc_dma_tx_4_chs, + cdc_dma_tx_ch_get, cdc_dma_tx_ch_put), + SOC_ENUM_EXT("VA_CDC_DMA_TX_0 Channels", va_cdc_dma_tx_0_chs, + cdc_dma_tx_ch_get, cdc_dma_tx_ch_put), + SOC_ENUM_EXT("VA_CDC_DMA_TX_1 Channels", va_cdc_dma_tx_1_chs, + cdc_dma_tx_ch_get, cdc_dma_tx_ch_put), + SOC_ENUM_EXT("VA_CDC_DMA_TX_2 Channels", va_cdc_dma_tx_2_chs, + cdc_dma_tx_ch_get, cdc_dma_tx_ch_put), + SOC_ENUM_EXT("TX_CDC_DMA_TX_0 Format", tx_cdc_dma_tx_0_format, + cdc_dma_tx_format_get, cdc_dma_tx_format_put), + SOC_ENUM_EXT("TX_CDC_DMA_TX_3 Format", tx_cdc_dma_tx_3_format, + cdc_dma_tx_format_get, cdc_dma_tx_format_put), + SOC_ENUM_EXT("TX_CDC_DMA_TX_4 Format", tx_cdc_dma_tx_4_format, + cdc_dma_tx_format_get, cdc_dma_tx_format_put), + SOC_ENUM_EXT("VA_CDC_DMA_TX_0 Format", va_cdc_dma_tx_0_format, + cdc_dma_tx_format_get, cdc_dma_tx_format_put), + SOC_ENUM_EXT("VA_CDC_DMA_TX_1 Format", va_cdc_dma_tx_1_format, + cdc_dma_tx_format_get, cdc_dma_tx_format_put), + SOC_ENUM_EXT("VA_CDC_DMA_TX_2 Format", va_cdc_dma_tx_2_format, + cdc_dma_tx_format_get, cdc_dma_tx_format_put), + SOC_ENUM_EXT("TX_CDC_DMA_TX_0 SampleRate", + tx_cdc_dma_tx_0_sample_rate, + cdc_dma_tx_sample_rate_get, + cdc_dma_tx_sample_rate_put), + SOC_ENUM_EXT("TX_CDC_DMA_TX_3 SampleRate", + tx_cdc_dma_tx_3_sample_rate, + cdc_dma_tx_sample_rate_get, + cdc_dma_tx_sample_rate_put), + SOC_ENUM_EXT("TX_CDC_DMA_TX_4 SampleRate", + tx_cdc_dma_tx_4_sample_rate, + cdc_dma_tx_sample_rate_get, + cdc_dma_tx_sample_rate_put), + SOC_ENUM_EXT("VA_CDC_DMA_TX_0 SampleRate", + va_cdc_dma_tx_0_sample_rate, + cdc_dma_tx_sample_rate_get, + cdc_dma_tx_sample_rate_put), + SOC_ENUM_EXT("VA_CDC_DMA_TX_1 SampleRate", + va_cdc_dma_tx_1_sample_rate, + cdc_dma_tx_sample_rate_get, + cdc_dma_tx_sample_rate_put), + SOC_ENUM_EXT("VA_CDC_DMA_TX_2 SampleRate", + va_cdc_dma_tx_2_sample_rate, + cdc_dma_tx_sample_rate_get, + cdc_dma_tx_sample_rate_put), +}; + +static const struct snd_kcontrol_new msm_int_wcd9380_snd_controls[] = { + SOC_ENUM_EXT("RX_CDC_DMA_RX_0 Format", rx_cdc80_dma_rx_0_format, + cdc_dma_rx_format_get, cdc_dma_rx_format_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_1 Format", rx_cdc80_dma_rx_1_format, + cdc_dma_rx_format_get, cdc_dma_rx_format_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_2 Format", rx_cdc80_dma_rx_2_format, + cdc_dma_rx_format_get, cdc_dma_rx_format_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_3 Format", rx_cdc80_dma_rx_3_format, + cdc_dma_rx_format_get, cdc_dma_rx_format_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_5 Format", rx_cdc80_dma_rx_5_format, + cdc_dma_rx_format_get, cdc_dma_rx_format_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_6 Format", rx_cdc80_dma_rx_6_format, + cdc_dma_rx_format_get, cdc_dma_rx_format_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_0 SampleRate", + rx_cdc80_dma_rx_0_sample_rate, + cdc_dma_rx_sample_rate_get, + cdc_dma_rx_sample_rate_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_1 SampleRate", + rx_cdc80_dma_rx_1_sample_rate, + cdc_dma_rx_sample_rate_get, + cdc_dma_rx_sample_rate_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_2 SampleRate", + rx_cdc80_dma_rx_2_sample_rate, + cdc_dma_rx_sample_rate_get, + cdc_dma_rx_sample_rate_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_3 SampleRate", + rx_cdc80_dma_rx_3_sample_rate, + cdc_dma_rx_sample_rate_get, + cdc_dma_rx_sample_rate_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_5 SampleRate", + rx_cdc80_dma_rx_5_sample_rate, + cdc_dma_rx_sample_rate_get, + cdc_dma_rx_sample_rate_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_6 SampleRate", + rx_cdc80_dma_rx_6_sample_rate, + cdc_dma_rx_sample_rate_get, + cdc_dma_rx_sample_rate_put), +}; + +static const struct snd_kcontrol_new msm_int_wcd9385_snd_controls[] = { + SOC_ENUM_EXT("RX_CDC_DMA_RX_0 Format", rx_cdc85_dma_rx_0_format, + cdc_dma_rx_format_get, cdc_dma_rx_format_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_1 Format", rx_cdc85_dma_rx_1_format, + cdc_dma_rx_format_get, cdc_dma_rx_format_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_2 Format", rx_cdc85_dma_rx_2_format, + cdc_dma_rx_format_get, cdc_dma_rx_format_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_3 Format", rx_cdc85_dma_rx_3_format, + cdc_dma_rx_format_get, cdc_dma_rx_format_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_5 Format", rx_cdc85_dma_rx_5_format, + cdc_dma_rx_format_get, cdc_dma_rx_format_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_6 Format", rx_cdc85_dma_rx_6_format, + cdc_dma_rx_format_get, cdc_dma_rx_format_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_0 SampleRate", + rx_cdc85_dma_rx_0_sample_rate, + cdc_dma_rx_sample_rate_get, + cdc_dma_rx_sample_rate_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_1 SampleRate", + rx_cdc85_dma_rx_1_sample_rate, + cdc_dma_rx_sample_rate_get, + cdc_dma_rx_sample_rate_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_2 SampleRate", + rx_cdc85_dma_rx_2_sample_rate, + cdc_dma_rx_sample_rate_get, + cdc_dma_rx_sample_rate_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_3 SampleRate", + rx_cdc85_dma_rx_3_sample_rate, + cdc_dma_rx_sample_rate_get, + cdc_dma_rx_sample_rate_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_5 SampleRate", + rx_cdc85_dma_rx_5_sample_rate, + cdc_dma_rx_sample_rate_get, + cdc_dma_rx_sample_rate_put), + SOC_ENUM_EXT("RX_CDC_DMA_RX_6 SampleRate", + rx_cdc85_dma_rx_6_sample_rate, + cdc_dma_rx_sample_rate_get, + cdc_dma_rx_sample_rate_put), +}; + +static const struct snd_kcontrol_new msm_common_snd_controls[] = { + SOC_ENUM_EXT("USB_AUDIO_RX SampleRate", usb_rx_sample_rate, + usb_audio_rx_sample_rate_get, + usb_audio_rx_sample_rate_put), + SOC_ENUM_EXT("USB_AUDIO_TX SampleRate", usb_tx_sample_rate, + usb_audio_tx_sample_rate_get, + usb_audio_tx_sample_rate_put), + SOC_ENUM_EXT("PRI_TDM_RX_0 SampleRate", tdm_rx_sample_rate, + tdm_rx_sample_rate_get, + tdm_rx_sample_rate_put), + SOC_ENUM_EXT("SEC_TDM_RX_0 SampleRate", tdm_rx_sample_rate, + tdm_rx_sample_rate_get, + tdm_rx_sample_rate_put), + SOC_ENUM_EXT("TERT_TDM_RX_0 SampleRate", tdm_rx_sample_rate, + tdm_rx_sample_rate_get, + tdm_rx_sample_rate_put), + SOC_ENUM_EXT("QUAT_TDM_RX_0 SampleRate", tdm_rx_sample_rate, + tdm_rx_sample_rate_get, + tdm_rx_sample_rate_put), + SOC_ENUM_EXT("PRI_TDM_TX_0 SampleRate", tdm_tx_sample_rate, + tdm_tx_sample_rate_get, + tdm_tx_sample_rate_put), + SOC_ENUM_EXT("SEC_TDM_TX_0 SampleRate", tdm_tx_sample_rate, + tdm_tx_sample_rate_get, + tdm_tx_sample_rate_put), + SOC_ENUM_EXT("TERT_TDM_TX_0 SampleRate", tdm_tx_sample_rate, + tdm_tx_sample_rate_get, + tdm_tx_sample_rate_put), + SOC_ENUM_EXT("QUAT_TDM_TX_0 SampleRate", tdm_tx_sample_rate, + tdm_tx_sample_rate_get, + tdm_tx_sample_rate_put), + SOC_ENUM_EXT("PRIM_AUX_PCM_RX SampleRate", prim_aux_pcm_rx_sample_rate, + aux_pcm_rx_sample_rate_get, + aux_pcm_rx_sample_rate_put), + SOC_ENUM_EXT("SEC_AUX_PCM_RX SampleRate", sec_aux_pcm_rx_sample_rate, + aux_pcm_rx_sample_rate_get, + aux_pcm_rx_sample_rate_put), + SOC_ENUM_EXT("TERT_AUX_PCM_RX SampleRate", tert_aux_pcm_rx_sample_rate, + aux_pcm_rx_sample_rate_get, + aux_pcm_rx_sample_rate_put), + SOC_ENUM_EXT("QUAT_AUX_PCM_RX SampleRate", quat_aux_pcm_rx_sample_rate, + aux_pcm_rx_sample_rate_get, + aux_pcm_rx_sample_rate_put), + SOC_ENUM_EXT("PRIM_AUX_PCM_TX SampleRate", prim_aux_pcm_tx_sample_rate, + aux_pcm_tx_sample_rate_get, + aux_pcm_tx_sample_rate_put), + SOC_ENUM_EXT("SEC_AUX_PCM_TX SampleRate", sec_aux_pcm_tx_sample_rate, + aux_pcm_tx_sample_rate_get, + aux_pcm_tx_sample_rate_put), + SOC_ENUM_EXT("TERT_AUX_PCM_TX SampleRate", tert_aux_pcm_tx_sample_rate, + aux_pcm_tx_sample_rate_get, + aux_pcm_tx_sample_rate_put), + SOC_ENUM_EXT("QUAT_AUX_PCM_TX SampleRate", quat_aux_pcm_tx_sample_rate, + aux_pcm_tx_sample_rate_get, + aux_pcm_tx_sample_rate_put), + SOC_ENUM_EXT("PRIM_MI2S_RX SampleRate", prim_mi2s_rx_sample_rate, + mi2s_rx_sample_rate_get, + mi2s_rx_sample_rate_put), + SOC_ENUM_EXT("SEC_MI2S_RX SampleRate", sec_mi2s_rx_sample_rate, + mi2s_rx_sample_rate_get, + mi2s_rx_sample_rate_put), + SOC_ENUM_EXT("TERT_MI2S_RX SampleRate", tert_mi2s_rx_sample_rate, + mi2s_rx_sample_rate_get, + mi2s_rx_sample_rate_put), + SOC_ENUM_EXT("QUAT_MI2S_RX SampleRate", quat_mi2s_rx_sample_rate, + mi2s_rx_sample_rate_get, + mi2s_rx_sample_rate_put), + SOC_ENUM_EXT("PRIM_MI2S_TX SampleRate", prim_mi2s_tx_sample_rate, + mi2s_tx_sample_rate_get, + mi2s_tx_sample_rate_put), + SOC_ENUM_EXT("SEC_MI2S_TX SampleRate", sec_mi2s_tx_sample_rate, + mi2s_tx_sample_rate_get, + mi2s_tx_sample_rate_put), + SOC_ENUM_EXT("TERT_MI2S_TX SampleRate", tert_mi2s_tx_sample_rate, + mi2s_tx_sample_rate_get, + mi2s_tx_sample_rate_put), + SOC_ENUM_EXT("QUAT_MI2S_TX SampleRate", quat_mi2s_tx_sample_rate, + mi2s_tx_sample_rate_get, + mi2s_tx_sample_rate_put), + SOC_ENUM_EXT("USB_AUDIO_RX Format", usb_rx_format, + usb_audio_rx_format_get, usb_audio_rx_format_put), + SOC_ENUM_EXT("USB_AUDIO_TX Format", usb_tx_format, + usb_audio_tx_format_get, usb_audio_tx_format_put), + SOC_ENUM_EXT("PRI_TDM_RX_0 Format", tdm_rx_format, + tdm_rx_format_get, + tdm_rx_format_put), + SOC_ENUM_EXT("SEC_TDM_RX_0 Format", tdm_rx_format, + tdm_rx_format_get, + tdm_rx_format_put), + SOC_ENUM_EXT("TERT_TDM_RX_0 Format", tdm_rx_format, + tdm_rx_format_get, + tdm_rx_format_put), + SOC_ENUM_EXT("QUAT_TDM_RX_0 Format", tdm_rx_format, + tdm_rx_format_get, + tdm_rx_format_put), + SOC_ENUM_EXT("PRI_TDM_TX_0 Format", tdm_tx_format, + tdm_tx_format_get, + tdm_tx_format_put), + SOC_ENUM_EXT("SEC_TDM_TX_0 Format", tdm_tx_format, + tdm_tx_format_get, + tdm_tx_format_put), + SOC_ENUM_EXT("TERT_TDM_TX_0 Format", tdm_tx_format, + tdm_tx_format_get, + tdm_tx_format_put), + SOC_ENUM_EXT("QUAT_TDM_TX_0 Format", tdm_tx_format, + tdm_tx_format_get, + tdm_tx_format_put), + SOC_ENUM_EXT("PRIM_AUX_PCM_RX Format", aux_pcm_rx_format, + msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put), + SOC_ENUM_EXT("SEC_AUX_PCM_RX Format", aux_pcm_rx_format, + msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put), + SOC_ENUM_EXT("TERT_AUX_PCM_RX Format", aux_pcm_rx_format, + msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put), + SOC_ENUM_EXT("QUAT_AUX_PCM_RX Format", aux_pcm_rx_format, + msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put), + SOC_ENUM_EXT("PRIM_AUX_PCM_TX Format", aux_pcm_tx_format, + msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put), + SOC_ENUM_EXT("SEC_AUX_PCM_TX Format", aux_pcm_tx_format, + msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put), + SOC_ENUM_EXT("TERT_AUX_PCM_TX Format", aux_pcm_tx_format, + msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put), + SOC_ENUM_EXT("QUAT_AUX_PCM_TX Format", aux_pcm_tx_format, + msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put), + SOC_ENUM_EXT("PRIM_MI2S_RX Format", mi2s_rx_format, + msm_mi2s_rx_format_get, msm_mi2s_rx_format_put), + SOC_ENUM_EXT("SEC_MI2S_RX Format", mi2s_rx_format, + msm_mi2s_rx_format_get, msm_mi2s_rx_format_put), + SOC_ENUM_EXT("TERT_MI2S_RX Format", mi2s_rx_format, + msm_mi2s_rx_format_get, msm_mi2s_rx_format_put), + SOC_ENUM_EXT("QUAT_MI2S_RX Format", mi2s_rx_format, + msm_mi2s_rx_format_get, msm_mi2s_rx_format_put), + SOC_ENUM_EXT("PRIM_MI2S_TX Format", mi2s_tx_format, + msm_mi2s_tx_format_get, msm_mi2s_tx_format_put), + SOC_ENUM_EXT("SEC_MI2S_TX Format", mi2s_tx_format, + msm_mi2s_tx_format_get, msm_mi2s_tx_format_put), + SOC_ENUM_EXT("TERT_MI2S_TX Format", mi2s_tx_format, + msm_mi2s_tx_format_get, msm_mi2s_tx_format_put), + SOC_ENUM_EXT("QUAT_MI2S_TX Format", mi2s_tx_format, + msm_mi2s_tx_format_get, msm_mi2s_tx_format_put), + SOC_ENUM_EXT("USB_AUDIO_RX Channels", usb_rx_chs, + usb_audio_rx_ch_get, usb_audio_rx_ch_put), + SOC_ENUM_EXT("USB_AUDIO_TX Channels", usb_tx_chs, + usb_audio_tx_ch_get, usb_audio_tx_ch_put), + SOC_ENUM_EXT("PROXY_RX Channels", proxy_rx_chs, + proxy_rx_ch_get, proxy_rx_ch_put), + SOC_ENUM_EXT("PRI_TDM_RX_0 Channels", tdm_rx_chs, + tdm_rx_ch_get, + tdm_rx_ch_put), + SOC_ENUM_EXT("SEC_TDM_RX_0 Channels", tdm_rx_chs, + tdm_rx_ch_get, + tdm_rx_ch_put), + SOC_ENUM_EXT("TERT_TDM_RX_0 Channels", tdm_rx_chs, + tdm_rx_ch_get, + tdm_rx_ch_put), + SOC_ENUM_EXT("QUAT_TDM_RX_0 Channels", tdm_rx_chs, + tdm_rx_ch_get, + tdm_rx_ch_put), + SOC_ENUM_EXT("PRI_TDM_TX_0 Channels", tdm_tx_chs, + tdm_tx_ch_get, + tdm_tx_ch_put), + SOC_ENUM_EXT("SEC_TDM_TX_0 Channels", tdm_tx_chs, + tdm_tx_ch_get, + tdm_tx_ch_put), + SOC_ENUM_EXT("TERT_TDM_TX_0 Channels", tdm_tx_chs, + tdm_tx_ch_get, + tdm_tx_ch_put), + SOC_ENUM_EXT("QUAT_TDM_TX_0 Channels", tdm_tx_chs, + tdm_tx_ch_get, + tdm_tx_ch_put), + SOC_ENUM_EXT("PRIM_MI2S_RX Channels", prim_mi2s_rx_chs, + msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put), + SOC_ENUM_EXT("SEC_MI2S_RX Channels", sec_mi2s_rx_chs, + msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put), + SOC_ENUM_EXT("TERT_MI2S_RX Channels", tert_mi2s_rx_chs, + msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put), + SOC_ENUM_EXT("QUAT_MI2S_RX Channels", quat_mi2s_rx_chs, + msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put), + SOC_ENUM_EXT("PRIM_MI2S_TX Channels", prim_mi2s_tx_chs, + msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put), + SOC_ENUM_EXT("SEC_MI2S_TX Channels", sec_mi2s_tx_chs, + msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put), + SOC_ENUM_EXT("TERT_MI2S_TX Channels", tert_mi2s_tx_chs, + msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put), + SOC_ENUM_EXT("QUAT_MI2S_TX Channels", quat_mi2s_tx_chs, + msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put), + SOC_ENUM_EXT("BT SampleRate", bt_sample_rate, + msm_bt_sample_rate_get, + msm_bt_sample_rate_put), + SOC_ENUM_EXT("BT SampleRate RX", bt_sample_rate_rx, + msm_bt_sample_rate_rx_get, + msm_bt_sample_rate_rx_put), + SOC_ENUM_EXT("BT SampleRate TX", bt_sample_rate_tx, + msm_bt_sample_rate_tx_get, + msm_bt_sample_rate_tx_put), + SOC_ENUM_EXT("AFE_LOOPBACK_TX Channels", afe_loopback_tx_chs, + afe_loopback_tx_ch_get, afe_loopback_tx_ch_put), + SOC_ENUM_EXT("VI_FEED_TX Channels", vi_feed_tx_chs, + msm_vi_feed_tx_ch_get, msm_vi_feed_tx_ch_put), + SOC_SINGLE_MULTI_EXT("TDM Slot Map", SND_SOC_NOPM, 0, 255, 0, + TDM_MAX_SLOTS + MAX_PATH, NULL, tdm_slot_map_put), +}; + +static const struct snd_kcontrol_new msm_snd_controls[] = { + SOC_ENUM_EXT("PRIM_AUX_PCM_RX Format", aux_pcm_rx_format, + msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put), + SOC_ENUM_EXT("PRIM_AUX_PCM_TX Format", aux_pcm_tx_format, + msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put), + SOC_ENUM_EXT("PRIM_AUX_PCM_RX SampleRate", prim_aux_pcm_rx_sample_rate, + aux_pcm_rx_sample_rate_get, + aux_pcm_rx_sample_rate_put), + SOC_ENUM_EXT("PRIM_AUX_PCM_TX SampleRate", prim_aux_pcm_tx_sample_rate, + aux_pcm_tx_sample_rate_get, + aux_pcm_tx_sample_rate_put), +}; + +static int holi_send_island_va_config(int32_t be_id) +{ + int rc = 0; + int port_id = 0xFFFF; + + port_id = msm_get_port_id(be_id); + if (port_id < 0) { + pr_err("%s: Invalid island interface, be_id: %d\n", + __func__, be_id); + rc = -EINVAL; + } else { + /* + * send island mode config + * This should be the first configuration + */ + rc = afe_send_port_island_mode(port_id); + if (rc) + pr_err("%s: afe send island mode failed %d\n", + __func__, rc); + } + + return rc; +} + +static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_dai_link *dai_link = rtd->dai_link; + 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); + int idx = 0, rc = 0; + + pr_debug("%s: dai_id= %d, format = %d, rate = %d\n", + __func__, dai_link->id, params_format(params), + params_rate(params)); + + switch (dai_link->id) { + case MSM_BACKEND_DAI_USB_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + usb_rx_cfg.bit_format); + rate->min = rate->max = usb_rx_cfg.sample_rate; + channels->min = channels->max = usb_rx_cfg.channels; + break; + + case MSM_BACKEND_DAI_USB_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + usb_tx_cfg.bit_format); + rate->min = rate->max = usb_tx_cfg.sample_rate; + channels->min = channels->max = usb_tx_cfg.channels; + break; + + case MSM_BACKEND_DAI_AFE_PCM_RX: + channels->min = channels->max = proxy_rx_cfg.channels; + rate->min = rate->max = SAMPLING_RATE_48KHZ; + break; + + case MSM_BACKEND_DAI_PRI_TDM_RX_0: + channels->min = channels->max = + tdm_rx_cfg[TDM_PRI][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_rx_cfg[TDM_PRI][TDM_0].bit_format); + rate->min = rate->max = tdm_rx_cfg[TDM_PRI][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_PRI_TDM_TX_0: + channels->min = channels->max = + tdm_tx_cfg[TDM_PRI][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_tx_cfg[TDM_PRI][TDM_0].bit_format); + rate->min = rate->max = tdm_tx_cfg[TDM_PRI][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_SEC_TDM_RX_0: + channels->min = channels->max = + tdm_rx_cfg[TDM_SEC][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_rx_cfg[TDM_SEC][TDM_0].bit_format); + rate->min = rate->max = tdm_rx_cfg[TDM_SEC][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_SEC_TDM_TX_0: + channels->min = channels->max = + tdm_tx_cfg[TDM_SEC][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_tx_cfg[TDM_SEC][TDM_0].bit_format); + rate->min = rate->max = tdm_tx_cfg[TDM_SEC][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_TERT_TDM_RX_0: + channels->min = channels->max = + tdm_rx_cfg[TDM_TERT][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_rx_cfg[TDM_TERT][TDM_0].bit_format); + rate->min = rate->max = tdm_rx_cfg[TDM_TERT][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_TERT_TDM_TX_0: + channels->min = channels->max = + tdm_tx_cfg[TDM_TERT][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_tx_cfg[TDM_TERT][TDM_0].bit_format); + rate->min = rate->max = tdm_tx_cfg[TDM_TERT][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_QUAT_TDM_RX_0: + channels->min = channels->max = + tdm_rx_cfg[TDM_QUAT][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_rx_cfg[TDM_QUAT][TDM_0].bit_format); + rate->min = rate->max = tdm_rx_cfg[TDM_QUAT][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_QUAT_TDM_TX_0: + channels->min = channels->max = + tdm_tx_cfg[TDM_QUAT][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_tx_cfg[TDM_QUAT][TDM_0].bit_format); + rate->min = rate->max = tdm_tx_cfg[TDM_QUAT][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_AUXPCM_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + aux_pcm_rx_cfg[PRIM_AUX_PCM].bit_format); + rate->min = rate->max = + aux_pcm_rx_cfg[PRIM_AUX_PCM].sample_rate; + channels->min = channels->max = + aux_pcm_rx_cfg[PRIM_AUX_PCM].channels; + break; + + case MSM_BACKEND_DAI_AUXPCM_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + aux_pcm_tx_cfg[PRIM_AUX_PCM].bit_format); + rate->min = rate->max = + aux_pcm_tx_cfg[PRIM_AUX_PCM].sample_rate; + channels->min = channels->max = + aux_pcm_tx_cfg[PRIM_AUX_PCM].channels; + break; + + case MSM_BACKEND_DAI_SEC_AUXPCM_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + aux_pcm_rx_cfg[SEC_AUX_PCM].bit_format); + rate->min = rate->max = + aux_pcm_rx_cfg[SEC_AUX_PCM].sample_rate; + channels->min = channels->max = + aux_pcm_rx_cfg[SEC_AUX_PCM].channels; + break; + + case MSM_BACKEND_DAI_SEC_AUXPCM_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + aux_pcm_tx_cfg[SEC_AUX_PCM].bit_format); + rate->min = rate->max = + aux_pcm_tx_cfg[SEC_AUX_PCM].sample_rate; + channels->min = channels->max = + aux_pcm_tx_cfg[SEC_AUX_PCM].channels; + break; + + case MSM_BACKEND_DAI_TERT_AUXPCM_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + aux_pcm_rx_cfg[TERT_AUX_PCM].bit_format); + rate->min = rate->max = + aux_pcm_rx_cfg[TERT_AUX_PCM].sample_rate; + channels->min = channels->max = + aux_pcm_rx_cfg[TERT_AUX_PCM].channels; + break; + + case MSM_BACKEND_DAI_TERT_AUXPCM_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + aux_pcm_tx_cfg[TERT_AUX_PCM].bit_format); + rate->min = rate->max = + aux_pcm_tx_cfg[TERT_AUX_PCM].sample_rate; + channels->min = channels->max = + aux_pcm_tx_cfg[TERT_AUX_PCM].channels; + break; + + case MSM_BACKEND_DAI_QUAT_AUXPCM_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + aux_pcm_rx_cfg[QUAT_AUX_PCM].bit_format); + rate->min = rate->max = + aux_pcm_rx_cfg[QUAT_AUX_PCM].sample_rate; + channels->min = channels->max = + aux_pcm_rx_cfg[QUAT_AUX_PCM].channels; + break; + + case MSM_BACKEND_DAI_QUAT_AUXPCM_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + aux_pcm_tx_cfg[QUAT_AUX_PCM].bit_format); + rate->min = rate->max = + aux_pcm_tx_cfg[QUAT_AUX_PCM].sample_rate; + channels->min = channels->max = + aux_pcm_tx_cfg[QUAT_AUX_PCM].channels; + break; + + case MSM_BACKEND_DAI_PRI_MI2S_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_rx_cfg[PRIM_MI2S].bit_format); + rate->min = rate->max = mi2s_rx_cfg[PRIM_MI2S].sample_rate; + channels->min = channels->max = + mi2s_rx_cfg[PRIM_MI2S].channels; + break; + + case MSM_BACKEND_DAI_PRI_MI2S_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_tx_cfg[PRIM_MI2S].bit_format); + rate->min = rate->max = mi2s_tx_cfg[PRIM_MI2S].sample_rate; + channels->min = channels->max = + mi2s_tx_cfg[PRIM_MI2S].channels; + break; + + case MSM_BACKEND_DAI_SECONDARY_MI2S_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_rx_cfg[SEC_MI2S].bit_format); + rate->min = rate->max = mi2s_rx_cfg[SEC_MI2S].sample_rate; + channels->min = channels->max = + mi2s_rx_cfg[SEC_MI2S].channels; + break; + + case MSM_BACKEND_DAI_SECONDARY_MI2S_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_tx_cfg[SEC_MI2S].bit_format); + rate->min = rate->max = mi2s_tx_cfg[SEC_MI2S].sample_rate; + channels->min = channels->max = + mi2s_tx_cfg[SEC_MI2S].channels; + break; + + case MSM_BACKEND_DAI_TERTIARY_MI2S_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_rx_cfg[TERT_MI2S].bit_format); + rate->min = rate->max = mi2s_rx_cfg[TERT_MI2S].sample_rate; + channels->min = channels->max = + mi2s_rx_cfg[TERT_MI2S].channels; + break; + + case MSM_BACKEND_DAI_TERTIARY_MI2S_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_tx_cfg[TERT_MI2S].bit_format); + rate->min = rate->max = mi2s_tx_cfg[TERT_MI2S].sample_rate; + channels->min = channels->max = + mi2s_tx_cfg[TERT_MI2S].channels; + break; + + case MSM_BACKEND_DAI_QUATERNARY_MI2S_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_rx_cfg[QUAT_MI2S].bit_format); + rate->min = rate->max = mi2s_rx_cfg[QUAT_MI2S].sample_rate; + channels->min = channels->max = + mi2s_rx_cfg[QUAT_MI2S].channels; + break; + + case MSM_BACKEND_DAI_QUATERNARY_MI2S_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_tx_cfg[QUAT_MI2S].bit_format); + rate->min = rate->max = mi2s_tx_cfg[QUAT_MI2S].sample_rate; + channels->min = channels->max = + mi2s_tx_cfg[QUAT_MI2S].channels; + break; + + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_0: + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_1: + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_2: + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_3: + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_6: + idx = msm_cdc_dma_get_idx_from_beid(dai_link->id); + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + cdc_dma_rx_cfg[idx].bit_format); + rate->min = rate->max = cdc_dma_rx_cfg[idx].sample_rate; + channels->min = channels->max = cdc_dma_rx_cfg[idx].channels; + break; + + case MSM_BACKEND_DAI_TX_CDC_DMA_TX_0: + case MSM_BACKEND_DAI_TX_CDC_DMA_TX_3: + case MSM_BACKEND_DAI_TX_CDC_DMA_TX_4: + case MSM_BACKEND_DAI_VA_CDC_DMA_TX_0: + case MSM_BACKEND_DAI_VA_CDC_DMA_TX_1: + case MSM_BACKEND_DAI_VA_CDC_DMA_TX_2: + idx = msm_cdc_dma_get_idx_from_beid(dai_link->id); + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + cdc_dma_tx_cfg[idx].bit_format); + rate->min = rate->max = cdc_dma_tx_cfg[idx].sample_rate; + channels->min = channels->max = cdc_dma_tx_cfg[idx].channels; + break; + + case MSM_BACKEND_DAI_SLIMBUS_7_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim_rx_cfg[SLIM_RX_7].bit_format); + rate->min = rate->max = slim_rx_cfg[SLIM_RX_7].sample_rate; + channels->min = channels->max = + slim_rx_cfg[SLIM_RX_7].channels; + break; + + case MSM_BACKEND_DAI_SLIMBUS_7_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim_tx_cfg[SLIM_TX_7].bit_format); + rate->min = rate->max = slim_tx_cfg[SLIM_TX_7].sample_rate; + channels->min = channels->max = + slim_tx_cfg[SLIM_TX_7].channels; + break; + + case MSM_BACKEND_DAI_SLIMBUS_8_TX: + rate->min = rate->max = slim_tx_cfg[SLIM_TX_8].sample_rate; + channels->min = channels->max = + slim_tx_cfg[SLIM_TX_8].channels; + break; + + case MSM_BACKEND_DAI_AFE_LOOPBACK_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + afe_loopback_tx_cfg[idx].bit_format); + rate->min = rate->max = afe_loopback_tx_cfg[idx].sample_rate; + channels->min = channels->max = + afe_loopback_tx_cfg[idx].channels; + break; + + default: + rate->min = rate->max = SAMPLING_RATE_48KHZ; + break; + } + + return rc; +} + +static bool msm_usbc_swap_gnd_mic(struct snd_soc_component *component, + bool active) +{ + struct snd_soc_card *card = component->card; + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + + if (!pdata->fsa_handle) + return false; + + return fsa4480_switch_event(pdata->fsa_handle, FSA_MIC_GND_SWAP); +} + +static bool msm_swap_gnd_mic(struct snd_soc_component *component, bool active) +{ + int value = 0; + bool ret = false; + struct snd_soc_card *card; + struct msm_asoc_mach_data *pdata; + + if (!component) { + pr_err("%s component is NULL\n", __func__); + return false; + } + card = component->card; + pdata = snd_soc_card_get_drvdata(card); + + if (!pdata) + return false; + + if (wcd_mbhc_cfg.enable_usbc_analog) + return msm_usbc_swap_gnd_mic(component, active); + + /* if usbc is not defined, swap using us_euro_gpio_p */ + if (pdata->us_euro_gpio_p) { + value = msm_cdc_pinctrl_get_state( + pdata->us_euro_gpio_p); + if (value) + msm_cdc_pinctrl_select_sleep_state( + pdata->us_euro_gpio_p); + else + msm_cdc_pinctrl_select_active_state( + pdata->us_euro_gpio_p); + dev_dbg(component->dev, "%s: swap select switch %d to %d\n", + __func__, value, !value); + ret = true; + } + + return ret; +} + +static int holi_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 slot_width = TDM_SLOT_WIDTH_BITS; + int channels, slots = TDM_MAX_SLOTS; + unsigned int slot_mask, rate, clk_freq; + unsigned int *slot_offset; + struct tdm_dev_config *config; + unsigned int path_dir = 0, interface = 0, channel_interface = 0; + + pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id); + + if (cpu_dai->id < AFE_PORT_ID_TDM_PORT_RANGE_START) { + pr_err("%s: dai id 0x%x not supported\n", + __func__, cpu_dai->id); + return -EINVAL; + } + + /* RX or TX */ + path_dir = cpu_dai->id % MAX_PATH; + + /* PRI, SEC, TERT, QUAT ... */ + interface = (cpu_dai->id - AFE_PORT_ID_TDM_PORT_RANGE_START) + / (MAX_PATH * TDM_PORT_MAX); + + /* 0, 1, 2, .. 7 */ + channel_interface = + ((cpu_dai->id - AFE_PORT_ID_TDM_PORT_RANGE_START) / MAX_PATH) + % TDM_PORT_MAX; + + pr_debug("%s: path dir: %u, interface %u, channel interface %u\n", + __func__, path_dir, interface, channel_interface); + + config = ((struct tdm_dev_config *) tdm_cfg[interface]) + + (path_dir * TDM_PORT_MAX) + channel_interface; + slot_offset = config->tdm_slot_offset; + + if (path_dir) + channels = tdm_tx_cfg[interface][channel_interface].channels; + else + channels = tdm_rx_cfg[interface][channel_interface].channels; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /*2 slot config - bits 0 and 1 set for the first two slots */ + slot_mask = 0x0000FFFF >> (16 - slots); + + pr_debug("%s: tdm rx slot_width %d slots %d slot_mask %x\n", + __func__, slot_width, slots, slot_mask); + + 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 rx slot, err:%d\n", + __func__, ret); + goto end; + } + + pr_debug("%s: tdm rx channels: %d\n", __func__, channels); + + ret = snd_soc_dai_set_channel_map(cpu_dai, + 0, NULL, channels, slot_offset); + if (ret < 0) { + pr_err("%s: failed to set tdm rx channel map, err:%d\n", + __func__, ret); + goto end; + } + } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + /*2 slot config - bits 0 and 1 set for the first two slots */ + slot_mask = 0x0000FFFF >> (16 - slots); + + pr_debug("%s: tdm tx slot_width %d slots %d slot_mask %x\n", + __func__, slot_width, slots, slot_mask); + + 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 tx slot, err:%d\n", + __func__, ret); + goto end; + } + + pr_debug("%s: tdm tx channels: %d\n", __func__, channels); + + ret = snd_soc_dai_set_channel_map(cpu_dai, + channels, slot_offset, 0, NULL); + if (ret < 0) { + pr_err("%s: failed to set tdm tx channel map, err:%d\n", + __func__, ret); + goto end; + } + } else { + ret = -EINVAL; + pr_err("%s: invalid use case, err:%d\n", + __func__, ret); + goto end; + } + + rate = params_rate(params); + clk_freq = rate * slot_width * slots; + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, clk_freq, SND_SOC_CLOCK_OUT); + if (ret < 0) + pr_err("%s: failed to set tdm clk, err:%d\n", + __func__, ret); + +end: + return ret; +} + +static int msm_get_tdm_mode(u32 port_id) +{ + int tdm_mode; + + switch (port_id) { + case AFE_PORT_ID_PRIMARY_TDM_RX: + case AFE_PORT_ID_PRIMARY_TDM_TX: + tdm_mode = TDM_PRI; + break; + case AFE_PORT_ID_SECONDARY_TDM_RX: + case AFE_PORT_ID_SECONDARY_TDM_TX: + tdm_mode = TDM_SEC; + break; + case AFE_PORT_ID_TERTIARY_TDM_RX: + case AFE_PORT_ID_TERTIARY_TDM_TX: + tdm_mode = TDM_TERT; + break; + case AFE_PORT_ID_QUATERNARY_TDM_RX: + case AFE_PORT_ID_QUATERNARY_TDM_TX: + tdm_mode = TDM_QUAT; + break; + default: + pr_err("%s: Invalid port id: %d\n", __func__, port_id); + tdm_mode = -EINVAL; + } + return tdm_mode; +} + +static int holi_tdm_snd_startup(struct snd_pcm_substream *substream) +{ + int ret = 0; + 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 msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + int tdm_mode = msm_get_tdm_mode(cpu_dai->id); + + if (tdm_mode >= TDM_INTERFACE_MAX || tdm_mode < 0) { + ret = -EINVAL; + pr_err("%s: Invalid TDM interface %d\n", + __func__, ret); + return ret; + } + + if (pdata->mi2s_gpio_p[tdm_mode]) { + if (atomic_read(&(pdata->mi2s_gpio_ref_count[tdm_mode])) + == 0) { + ret = msm_cdc_pinctrl_select_active_state( + pdata->mi2s_gpio_p[tdm_mode]); + if (ret) { + pr_err("%s: TDM GPIO pinctrl set active failed with %d\n", + __func__, ret); + goto done; + } + } + atomic_inc(&(pdata->mi2s_gpio_ref_count[tdm_mode])); + } + +done: + return ret; +} + +static void holi_tdm_snd_shutdown(struct snd_pcm_substream *substream) +{ + int ret = 0; + 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 msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + int tdm_mode = msm_get_tdm_mode(cpu_dai->id); + + if (tdm_mode >= TDM_INTERFACE_MAX || tdm_mode < 0) { + ret = -EINVAL; + pr_err("%s: Invalid TDM interface %d\n", + __func__, ret); + return; + } + + if (pdata->mi2s_gpio_p[tdm_mode]) { + atomic_dec(&(pdata->mi2s_gpio_ref_count[tdm_mode])); + if (atomic_read(&(pdata->mi2s_gpio_ref_count[tdm_mode])) + == 0) { + ret = msm_cdc_pinctrl_select_sleep_state( + pdata->mi2s_gpio_p[tdm_mode]); + if (ret) + pr_err("%s: TDM GPIO pinctrl set sleep failed with %d\n", + __func__, ret); + } + } +} + +static int holi_aux_snd_startup(struct snd_pcm_substream *substream) +{ + int ret = 0; + 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 msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + u32 aux_mode = cpu_dai->id - 1; + + if (aux_mode >= AUX_PCM_MAX) { + ret = -EINVAL; + pr_err("%s: Invalid AUX interface %d\n", + __func__, ret); + return ret; + } + + if (pdata->mi2s_gpio_p[aux_mode]) { + if (atomic_read(&(pdata->mi2s_gpio_ref_count[aux_mode])) + == 0) { + ret = msm_cdc_pinctrl_select_active_state( + pdata->mi2s_gpio_p[aux_mode]); + if (ret) { + pr_err("%s: AUX GPIO pinctrl set active failed with %d\n", + __func__, ret); + goto done; + } + } + atomic_inc(&(pdata->mi2s_gpio_ref_count[aux_mode])); + } + +done: + return ret; +} + +static void holi_aux_snd_shutdown(struct snd_pcm_substream *substream) +{ + int ret = 0; + 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 msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + u32 aux_mode = cpu_dai->id - 1; + + if (aux_mode >= AUX_PCM_MAX) { + pr_err("%s: Invalid AUX interface %d\n", + __func__, ret); + return; + } + + if (pdata->mi2s_gpio_p[aux_mode]) { + atomic_dec(&(pdata->mi2s_gpio_ref_count[aux_mode])); + if (atomic_read(&(pdata->mi2s_gpio_ref_count[aux_mode])) + == 0) { + ret = msm_cdc_pinctrl_select_sleep_state( + pdata->mi2s_gpio_p[aux_mode]); + if (ret) + pr_err("%s: AUX GPIO pinctrl set sleep failed with %d\n", + __func__, ret); + } + } +} + +static int msm_snd_cdc_dma_startup(struct snd_pcm_substream *substream) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai_link *dai_link = rtd->dai_link; + + switch (dai_link->id) { + case MSM_BACKEND_DAI_VA_CDC_DMA_TX_0: + case MSM_BACKEND_DAI_VA_CDC_DMA_TX_1: + case MSM_BACKEND_DAI_VA_CDC_DMA_TX_2: + ret = holi_send_island_va_config(dai_link->id); + if (ret) + pr_err("%s: send island va cfg failed, err: %d\n", + __func__, ret); + break; + } + + return ret; +} + +static int msm_snd_cdc_dma_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_cdc_dma, tx_ch_cdc_dma; + u32 rx_ch_cnt = 0, tx_ch_cnt = 0; + u32 user_set_tx_ch = 0; + u32 user_set_rx_ch = 0; + u32 ch_id; + + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, &tx_ch_cdc_dma, &rx_ch_cnt, + &rx_ch_cdc_dma); + if (ret < 0) { + pr_err("%s: failed to get codec chan map, err:%d\n", + __func__, ret); + goto err; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + switch (dai_link->id) { + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_0: + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_1: + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_2: + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_3: + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_4: + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_5: + case MSM_BACKEND_DAI_RX_CDC_DMA_RX_6: + { + ch_id = msm_cdc_dma_get_idx_from_beid(dai_link->id); + pr_debug("%s: id %d rx_ch=%d\n", __func__, + ch_id, cdc_dma_rx_cfg[ch_id].channels); + user_set_rx_ch = cdc_dma_rx_cfg[ch_id].channels; + ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0, + user_set_rx_ch, &rx_ch_cdc_dma); + if (ret < 0) { + pr_err("%s: failed to set cpu chan map, err:%d\n", + __func__, ret); + goto err; + } + + } + break; + } + } else { + switch (dai_link->id) { + case MSM_BACKEND_DAI_TX_CDC_DMA_TX_0: + case MSM_BACKEND_DAI_TX_CDC_DMA_TX_3: + case MSM_BACKEND_DAI_TX_CDC_DMA_TX_4: + case MSM_BACKEND_DAI_VA_CDC_DMA_TX_0: + case MSM_BACKEND_DAI_VA_CDC_DMA_TX_1: + case MSM_BACKEND_DAI_VA_CDC_DMA_TX_2: + { + ch_id = msm_cdc_dma_get_idx_from_beid(dai_link->id); + pr_debug("%s: id %d tx_ch=%d\n", __func__, + ch_id, cdc_dma_tx_cfg[ch_id].channels); + user_set_tx_ch = cdc_dma_tx_cfg[ch_id].channels; + } + break; + } + + ret = snd_soc_dai_set_channel_map(cpu_dai, user_set_tx_ch, + &tx_ch_cdc_dma, 0, 0); + if (ret < 0) { + pr_err("%s: failed to set cpu chan map, err:%d\n", + __func__, ret); + goto err; + } + } + +err: + return ret; +} + +static int msm_fe_qos_prepare(struct snd_pcm_substream *substream) +{ + (void)substream; + + qos_client_active_cnt++; + if (qos_client_active_cnt == 1) + msm_audio_update_qos_request(MSM_LL_QOS_VALUE); + + return 0; +} + +static void msm_fe_qos_shutdown(struct snd_pcm_substream *substream) +{ + (void)substream; + + if (qos_client_active_cnt > 0) + qos_client_active_cnt--; + if (qos_client_active_cnt == 0) + msm_audio_update_qos_request(PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE); +} + +void mi2s_disable_audio_vote(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int index = cpu_dai->id; + struct snd_soc_card *card = rtd->card; + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + int sample_rate = 0; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + sample_rate = mi2s_rx_cfg[index].sample_rate; + } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + sample_rate = mi2s_tx_cfg[index].sample_rate; + } else { + pr_err("%s: invalid stream %d\n", __func__, substream->stream); + return; + } + + if (IS_MSM_INTERFACE_MI2S(index) && IS_FRACTIONAL(sample_rate)) { + if (pdata->lpass_audio_hw_vote != NULL) { + if (--pdata->core_audio_vote_count == 0) { + clk_disable_unprepare( + pdata->lpass_audio_hw_vote); + } else if (pdata->core_audio_vote_count < 0) { + pr_err("%s: audio vote mismatch\n", __func__); + pdata->core_audio_vote_count = 0; + } + } else { + pr_err("%s: Invalid lpass audio hw node\n", __func__); + } + } +} + +static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int index = cpu_dai->id; + unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS; + struct snd_soc_card *card = rtd->card; + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + int sample_rate = 0; + + dev_dbg(rtd->card->dev, + "%s: substream = %s stream = %d, dai name %s, dai ID %d\n", + __func__, substream->name, substream->stream, + cpu_dai->name, cpu_dai->id); + + if (index < PRIM_MI2S || index >= MI2S_MAX) { + ret = -EINVAL; + dev_err(rtd->card->dev, + "%s: CPU DAI id (%d) out of range\n", + __func__, cpu_dai->id); + goto err; + } + /* + * Mutex protection in case the same MI2S + * interface using for both TX and RX so + * that the same clock won't be enable twice. + */ + mutex_lock(&mi2s_intf_conf[index].lock); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + sample_rate = mi2s_rx_cfg[index].sample_rate; + } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + sample_rate = mi2s_tx_cfg[index].sample_rate; + } else { + pr_err("%s: invalid stream %d\n", __func__, substream->stream); + ret = -EINVAL; + goto vote_err; + } + + if (IS_MSM_INTERFACE_MI2S(index) && IS_FRACTIONAL(sample_rate)) { + if (pdata->lpass_audio_hw_vote == NULL) { + dev_err(rtd->card->dev, "%s: Invalid lpass audio hw node\n", + __func__); + ret = -EINVAL; + goto vote_err; + } + if (pdata->core_audio_vote_count == 0) { + ret = clk_prepare_enable(pdata->lpass_audio_hw_vote); + if (ret < 0) { + dev_err(rtd->card->dev, "%s: audio vote error\n", + __func__); + goto vote_err; + } + } + pdata->core_audio_vote_count++; + } + + if (++mi2s_intf_conf[index].ref_cnt == 1) { + /* Check if msm needs to provide the clock to the interface */ + if (!mi2s_intf_conf[index].msm_is_mi2s_master) { + mi2s_clk[index].clk_id = mi2s_ebit_clk[index]; + fmt = SND_SOC_DAIFMT_CBM_CFM; + } + ret = msm_mi2s_set_sclk(substream, true); + if (ret < 0) { + dev_err(rtd->card->dev, + "%s: afe lpass clock failed to enable MI2S clock, err:%d\n", + __func__, ret); + goto clean_up; + } + + ret = snd_soc_dai_set_fmt(cpu_dai, fmt); + if (ret < 0) { + pr_err("%s: set fmt cpu dai failed for MI2S (%d), err:%d\n", + __func__, index, ret); + goto clk_off; + } + if (pdata->mi2s_gpio_p[index]) { + if (atomic_read(&(pdata->mi2s_gpio_ref_count[index])) + == 0) { + ret = msm_cdc_pinctrl_select_active_state( + pdata->mi2s_gpio_p[index]); + if (ret) { + pr_err("%s: MI2S GPIO pinctrl set active failed with %d\n", + __func__, ret); + goto clk_off; + } + } + atomic_inc(&(pdata->mi2s_gpio_ref_count[index])); + } + } +clk_off: + if (ret < 0) + msm_mi2s_set_sclk(substream, false); +clean_up: + if (ret < 0) { + mi2s_intf_conf[index].ref_cnt--; + mi2s_disable_audio_vote(substream); + } +vote_err: + mutex_unlock(&mi2s_intf_conf[index].lock); +err: + return ret; +} + +static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int index = rtd->cpu_dai->id; + 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 (index < PRIM_MI2S || index >= MI2S_MAX) { + pr_err("%s:invalid MI2S DAI(%d)\n", __func__, index); + return; + } + + mutex_lock(&mi2s_intf_conf[index].lock); + if (--mi2s_intf_conf[index].ref_cnt == 0) { + if (pdata->mi2s_gpio_p[index]) { + atomic_dec(&(pdata->mi2s_gpio_ref_count[index])); + if (atomic_read(&(pdata->mi2s_gpio_ref_count[index])) + == 0) { + ret = msm_cdc_pinctrl_select_sleep_state( + pdata->mi2s_gpio_p[index]); + if (ret) + pr_err("%s: MI2S GPIO pinctrl set sleep failed with %d\n", + __func__, ret); + } + } + + ret = msm_mi2s_set_sclk(substream, false); + if (ret < 0) + pr_err("%s:clock disable failed for MI2S (%d); ret=%d\n", + __func__, index, ret); + } + mi2s_disable_audio_vote(substream); + mutex_unlock(&mi2s_intf_conf[index].lock); +} + +static int msm_wcn_hw_params_lito(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; + u32 rx_ch[WCN_CDC_SLIM_RX_CH_MAX], tx_ch[WCN_CDC_SLIM_TX_CH_MAX_LITO]; + u32 rx_ch_cnt = 0, tx_ch_cnt = 0; + int ret = 0; + + dev_dbg(rtd->dev, "%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, &rx_ch_cnt, rx_ch); + if (ret) { + dev_err(rtd->dev, + "%s: failed to get BTFM codec chan map\n, err:%d\n", + __func__, ret); + goto err; + } + + dev_dbg(rtd->dev, "%s: tx_ch_cnt(%d) BE id %d\n", + __func__, tx_ch_cnt, dai_link->id); + + ret = snd_soc_dai_set_channel_map(cpu_dai, + tx_ch_cnt, tx_ch, rx_ch_cnt, rx_ch); + if (ret) + dev_err(rtd->dev, "%s: failed to set cpu chan map, err:%d\n", + __func__, ret); + +err: + return ret; +} + +static struct snd_soc_ops holi_aux_be_ops = { + .startup = holi_aux_snd_startup, + .shutdown = holi_aux_snd_shutdown +}; + +static struct snd_soc_ops holi_tdm_be_ops = { + .hw_params = holi_tdm_snd_hw_params, + .startup = holi_tdm_snd_startup, + .shutdown = holi_tdm_snd_shutdown +}; + +static struct snd_soc_ops msm_mi2s_be_ops = { + .startup = msm_mi2s_snd_startup, + .shutdown = msm_mi2s_snd_shutdown, +}; + +static struct snd_soc_ops msm_fe_qos_ops = { + .prepare = msm_fe_qos_prepare, + .shutdown = msm_fe_qos_shutdown, +}; + +static struct snd_soc_ops msm_cdc_dma_be_ops = { + .startup = msm_snd_cdc_dma_startup, + .hw_params = msm_snd_cdc_dma_hw_params, +}; + +static struct snd_soc_ops msm_wcn_ops_lito = { + .hw_params = msm_wcn_hw_params_lito, +}; + +static int msm_dmic_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct msm_asoc_mach_data *pdata = NULL; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + int ret = 0; + u32 dmic_idx; + int *dmic_gpio_cnt; + struct device_node *dmic_gpio; + char *wname; + + wname = strpbrk(w->name, "012345"); + if (!wname) { + dev_err(component->dev, "%s: widget not found\n", __func__); + return -EINVAL; + } + + ret = kstrtouint(wname, 10, &dmic_idx); + if (ret < 0) { + dev_err(component->dev, "%s: Invalid DMIC line on the codec\n", + __func__); + return -EINVAL; + } + + pdata = snd_soc_card_get_drvdata(component->card); + + switch (dmic_idx) { + case 0: + case 1: + dmic_gpio_cnt = &dmic_0_1_gpio_cnt; + dmic_gpio = pdata->dmic01_gpio_p; + break; + case 2: + case 3: + dmic_gpio_cnt = &dmic_2_3_gpio_cnt; + dmic_gpio = pdata->dmic23_gpio_p; + break; + case 4: + case 5: + dmic_gpio_cnt = &dmic_4_5_gpio_cnt; + dmic_gpio = pdata->dmic45_gpio_p; + break; + default: + dev_err(component->dev, "%s: Invalid DMIC Selection\n", + __func__); + return -EINVAL; + } + + dev_dbg(component->dev, "%s: event %d DMIC%d dmic_gpio_cnt %d\n", + __func__, event, dmic_idx, *dmic_gpio_cnt); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + (*dmic_gpio_cnt)++; + if (*dmic_gpio_cnt == 1) { + ret = msm_cdc_pinctrl_select_active_state( + dmic_gpio); + if (ret < 0) { + pr_err("%s: gpio set cannot be activated %sd", + __func__, "dmic_gpio"); + return ret; + } + } + + break; + case SND_SOC_DAPM_POST_PMD: + (*dmic_gpio_cnt)--; + if (*dmic_gpio_cnt == 0) { + ret = msm_cdc_pinctrl_select_sleep_state( + dmic_gpio); + if (ret < 0) { + pr_err("%s: gpio set cannot be de-activated %sd", + __func__, "dmic_gpio"); + return ret; + } + } + break; + default: + pr_err("%s: invalid DAPM event %d\n", __func__, event); + return -EINVAL; + } + return 0; +} + +static const struct snd_soc_dapm_widget msm_int_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Analog Mic1", NULL), + SND_SOC_DAPM_MIC("Analog Mic2", NULL), + SND_SOC_DAPM_MIC("Analog Mic3", NULL), + SND_SOC_DAPM_MIC("Analog Mic4", NULL), + SND_SOC_DAPM_MIC("Analog Mic5", NULL), + SND_SOC_DAPM_MIC("Digital Mic0", msm_dmic_event), + SND_SOC_DAPM_MIC("Digital Mic1", msm_dmic_event), + SND_SOC_DAPM_MIC("Digital Mic2", msm_dmic_event), + SND_SOC_DAPM_MIC("Digital Mic3", msm_dmic_event), + SND_SOC_DAPM_MIC("Digital Mic4", msm_dmic_event), + SND_SOC_DAPM_MIC("Digital Mic5", msm_dmic_event), + SND_SOC_DAPM_MIC("Digital Mic6", NULL), + SND_SOC_DAPM_MIC("Digital Mic7", NULL), +}; + +static int msm_wcn_init_lito(struct snd_soc_pcm_runtime *rtd) +{ + unsigned int rx_ch[WCN_CDC_SLIM_RX_CH_MAX] = {157, 158}; + unsigned int tx_ch[WCN_CDC_SLIM_TX_CH_MAX_LITO] = {159, 160, 161}; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + return snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), + tx_ch, ARRAY_SIZE(rx_ch), rx_ch); +} + +static struct snd_info_entry *msm_snd_info_create_subdir(struct module *mod, + const char *name, + struct snd_info_entry *parent) +{ + struct snd_info_entry *entry; + + entry = snd_info_create_module_entry(mod, name, parent); + if (!entry) + return NULL; + entry->mode = S_IFDIR | 0555; + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + return NULL; + } + return entry; +} + +static void *def_wcd_mbhc_cal(void) +{ + void *wcd_mbhc_cal; + struct wcd_mbhc_btn_detect_cfg *btn_cfg; + u16 *btn_high; + + wcd_mbhc_cal = kzalloc(WCD_MBHC_CAL_SIZE(WCD_MBHC_DEF_BUTTONS, + WCD9XXX_MBHC_DEF_RLOADS), GFP_KERNEL); + if (!wcd_mbhc_cal) + return NULL; + + WCD_MBHC_CAL_PLUG_TYPE_PTR(wcd_mbhc_cal)->v_hs_max = WCD_MBHC_HS_V_MAX; + WCD_MBHC_CAL_BTN_DET_PTR(wcd_mbhc_cal)->num_btn = WCD_MBHC_DEF_BUTTONS; + btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(wcd_mbhc_cal); + btn_high = ((void *)&btn_cfg->_v_btn_low) + + (sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn); + + btn_high[0] = 75; + btn_high[1] = 150; + btn_high[2] = 237; + btn_high[3] = 500; + btn_high[4] = 500; + btn_high[5] = 500; + btn_high[6] = 500; + btn_high[7] = 500; + + return wcd_mbhc_cal; +} + +/* Digital audio interface glue - connects codec <---> CPU */ +static struct snd_soc_dai_link msm_common_dai_links[] = { + /* FrontEnd DAI Links */ + {/* hw:x,0 */ + .name = MSM_DAILINK_NAME(Media1), + .stream_name = "MultiMedia1", + .dynamic = 1, +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, +#endif /* CONFIG_AUDIO_QGKI */ + .dpcm_playback = 1, + .dpcm_capture = 1, + .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_MULTIMEDIA1, + SND_SOC_DAILINK_REG(multimedia1), + }, + {/* hw:x,1 */ + .name = MSM_DAILINK_NAME(Media2), + .stream_name = "MultiMedia2", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .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, + SND_SOC_DAILINK_REG(multimedia2), + }, + {/* hw:x,2 */ + .name = "VoiceMMode1", + .stream_name = "VoiceMMode1", + .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, + .id = MSM_FRONTEND_DAI_VOICEMMODE1, + SND_SOC_DAILINK_REG(voicemmode1), + }, + {/* hw:x,3 */ + .name = "MSM VoIP", + .stream_name = "VoIP", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .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_VOIP, + SND_SOC_DAILINK_REG(msmvoip), + }, + {/* hw:x,4 */ + .name = MSM_DAILINK_NAME(ULL), + .stream_name = "MultiMedia3", + .dynamic = 1, +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, +#endif /* CONFIG_AUDIO_QGKI */ + .dpcm_playback = 1, + .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_MULTIMEDIA3, + SND_SOC_DAILINK_REG(multimedia3), + }, + {/* hw:x,5 */ + .name = "MSM AFE-PCM RX", + .stream_name = "AFE-PROXY RX", + .dpcm_playback = 1, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(afepcm_rx), + }, + {/* hw:x,6 */ + .name = "MSM AFE-PCM TX", + .stream_name = "AFE-PROXY TX", + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(afepcm_tx), + }, + {/* hw:x,7 */ + .name = MSM_DAILINK_NAME(Compress1), + .stream_name = "Compress1", + .dynamic = 1, +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + .async_ops = ASYNC_DPCM_SND_SOC_HW_PARAMS, +#endif /* CONFIG_AUDIO_QGKI */ + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA4, + SND_SOC_DAILINK_REG(multimedia4), + }, + /* Hostless PCM purpose */ + {/* hw:x,8 */ + .name = "AUXPCM Hostless", + .stream_name = "AUXPCM 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, + SND_SOC_DAILINK_REG(auxpcm_hostless), + }, + {/* hw:x,9 */ + .name = MSM_DAILINK_NAME(LowLatency), + .stream_name = "MultiMedia5", + .dynamic = 1, +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, +#endif /* CONFIG_AUDIO_QGKI */ + .dpcm_playback = 1, + .dpcm_capture = 1, + .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, + .ops = &msm_fe_qos_ops, + SND_SOC_DAILINK_REG(multimedia5), + }, + {/* hw:x,10 */ + .name = "Listen 1 Audio Service", + .stream_name = "Listen 1 Audio Service", + .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, + .id = MSM_FRONTEND_DAI_LSM1, + SND_SOC_DAILINK_REG(listen1), + }, + /* Multiple Tunnel instances */ + {/* hw:x,11 */ + .name = MSM_DAILINK_NAME(Compress2), + .stream_name = "Compress2", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA7, + SND_SOC_DAILINK_REG(multimedia7), + }, + {/* hw:x,12 */ + .name = MSM_DAILINK_NAME(MultiMedia10), + .stream_name = "MultiMedia10", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA10, + SND_SOC_DAILINK_REG(multimedia10), + }, + {/* hw:x,13 */ + .name = MSM_DAILINK_NAME(ULL_NOIRQ), + .stream_name = "MM_NOIRQ", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA8, + .ops = &msm_fe_qos_ops, + SND_SOC_DAILINK_REG(multimedia8), + }, + /* HDMI Hostless */ + {/* hw:x,14 */ + .name = "HDMI_RX_HOSTLESS", + .stream_name = "HDMI_RX_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, + SND_SOC_DAILINK_REG(hdmi_rx_hostless), + }, + {/* hw:x,15 */ + .name = "VoiceMMode2", + .stream_name = "VoiceMMode2", + .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, + .id = MSM_FRONTEND_DAI_VOICEMMODE2, + SND_SOC_DAILINK_REG(voicemmode2), + }, + /* LSM FE */ + {/* hw:x,16 */ + .name = "Listen 2 Audio Service", + .stream_name = "Listen 2 Audio Service", + .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, + .id = MSM_FRONTEND_DAI_LSM2, + SND_SOC_DAILINK_REG(listen2), + }, + {/* hw:x,17 */ + .name = "Listen 3 Audio Service", + .stream_name = "Listen 3 Audio Service", + .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, + .id = MSM_FRONTEND_DAI_LSM3, + SND_SOC_DAILINK_REG(listen3), + }, + {/* hw:x,18 */ + .name = "Listen 4 Audio Service", + .stream_name = "Listen 4 Audio Service", + .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, + .id = MSM_FRONTEND_DAI_LSM4, + SND_SOC_DAILINK_REG(listen4), + }, + {/* hw:x,19 */ + .name = "Listen 5 Audio Service", + .stream_name = "Listen 5 Audio Service", + .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, + .id = MSM_FRONTEND_DAI_LSM5, + SND_SOC_DAILINK_REG(listen5), + }, + {/* hw:x,20 */ + .name = "Listen 6 Audio Service", + .stream_name = "Listen 6 Audio Service", + .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, + .id = MSM_FRONTEND_DAI_LSM6, + SND_SOC_DAILINK_REG(listen6), + }, + {/* hw:x,21 */ + .name = "Listen 7 Audio Service", + .stream_name = "Listen 7 Audio Service", + .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, + .id = MSM_FRONTEND_DAI_LSM7, + SND_SOC_DAILINK_REG(listen7), + }, + {/* hw:x,22 */ + .name = "Listen 8 Audio Service", + .stream_name = "Listen 8 Audio Service", + .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, + .id = MSM_FRONTEND_DAI_LSM8, + SND_SOC_DAILINK_REG(listen8), + }, + {/* hw:x,23 */ + .name = MSM_DAILINK_NAME(Media9), + .stream_name = "MultiMedia9", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .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_MULTIMEDIA9, + SND_SOC_DAILINK_REG(multimedia9), + }, + {/* hw:x,24 */ + .name = MSM_DAILINK_NAME(Compress4), + .stream_name = "Compress4", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA11, + SND_SOC_DAILINK_REG(multimedia11), + }, + {/* hw:x,25 */ + .name = MSM_DAILINK_NAME(Compress5), + .stream_name = "Compress5", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA12, + SND_SOC_DAILINK_REG(multimedia12), + }, + {/* hw:x,26 */ + .name = MSM_DAILINK_NAME(Compress6), + .stream_name = "Compress6", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA13, + SND_SOC_DAILINK_REG(multimedia13), + }, + {/* hw:x,27 */ + .name = MSM_DAILINK_NAME(Compress7), + .stream_name = "Compress7", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA14, + SND_SOC_DAILINK_REG(multimedia14), + }, + {/* hw:x,28 */ + .name = MSM_DAILINK_NAME(Compress8), + .stream_name = "Compress8", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA15, + SND_SOC_DAILINK_REG(multimedia15), + }, + {/* hw:x,29 */ + .name = MSM_DAILINK_NAME(ULL_NOIRQ_2), + .stream_name = "MM_NOIRQ_2", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA16, + .ops = &msm_fe_qos_ops, + SND_SOC_DAILINK_REG(multimedia16), + }, + {/* hw:x,30 */ + .name = "CDC_DMA Hostless", + .stream_name = "CDC_DMA 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 dailink has playback support */ + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(cdcdma_hostless), + }, + {/* hw:x,31 */ + .name = "TX3_CDC_DMA Hostless", + .stream_name = "TX3_CDC_DMA 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, + SND_SOC_DAILINK_REG(tx3_cdcdma_hostless), + }, + {/* hw:x,32 */ + .name = "Tertiary MI2S TX_Hostless", + .stream_name = "Tertiary MI2S_TX Hostless Capture", + .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, + SND_SOC_DAILINK_REG(tert_mi2s_tx_hostless), + }, +}; + +static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = { + {/* hw:x,33 */ + .name = MSM_DAILINK_NAME(ASM Loopback), + .stream_name = "MultiMedia6", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA6, + SND_SOC_DAILINK_REG(multimedia6), + }, + {/* hw:x,34 */ + .name = "USB Audio Hostless", + .stream_name = "USB Audio 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, + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(usbaudio_hostless), + }, + {/* hw:x,35 */ + .name = "SLIMBUS_7 Hostless", + .stream_name = "SLIMBUS_7 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, + SND_SOC_DAILINK_REG(slimbus7_hostless), + }, + {/* hw:x,36 */ + .name = "Compress Capture", + .stream_name = "Compress9", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA17, + SND_SOC_DAILINK_REG(multimedia17), + }, + {/* hw:x,37 */ + .name = "SLIMBUS_8 Hostless", + .stream_name = "SLIMBUS_8 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, + SND_SOC_DAILINK_REG(slimbus8_hostless), + }, + {/* hw:x,38 */ + .name = LPASS_BE_TX_CDC_DMA_TX_5, + .stream_name = "TX CDC DMA5 Capture", + .id = MSM_BACKEND_DAI_TX_CDC_DMA_TX_5, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ops = &msm_cdc_dma_be_ops, + SND_SOC_DAILINK_REG(tx_cdcdma5_tx), + }, + {/* hw:x,39 */ + .name = MSM_DAILINK_NAME(Media31), + .stream_name = "MultiMedia31", + .dynamic = 1, +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, +#endif /* CONFIG_AUDIO_QGKI */ + .dpcm_playback = 1, + .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_MULTIMEDIA31, + SND_SOC_DAILINK_REG(multimedia31), + }, + {/* hw:x,40 */ + .name = MSM_DAILINK_NAME(Media32), + .stream_name = "MultiMedia32", + .dynamic = 1, +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, +#endif /* CONFIG_AUDIO_QGKI */ + .dpcm_playback = 1, + .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_MULTIMEDIA32, + SND_SOC_DAILINK_REG(multimedia32), + }, + {/* hw:x,41 */ + .name = "MSM AFE-PCM TX1", + .stream_name = "AFE-PROXY TX1", + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(afepcm_tx1), + }, +}; + +static struct snd_soc_dai_link msm_common_be_dai_links[] = { + /* Backend AFE DAI Links */ + { + .name = LPASS_BE_AFE_PCM_RX, + .stream_name = "AFE Playback", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_AFE_PCM_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(afe_pcm_rx), + }, + { + .name = LPASS_BE_AFE_PCM_TX, + .stream_name = "AFE Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_AFE_PCM_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(afe_pcm_tx), + }, + /* Incall Record Uplink BACK END DAI Link */ + { + .name = LPASS_BE_INCALL_RECORD_TX, + .stream_name = "Voice Uplink Capture", + .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, + SND_SOC_DAILINK_REG(incall_record_tx), + }, + /* Incall Record Downlink BACK END DAI Link */ + { + .name = LPASS_BE_INCALL_RECORD_RX, + .stream_name = "Voice Downlink Capture", + .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, + SND_SOC_DAILINK_REG(incall_record_rx), + }, + /* Incall Music BACK END DAI Link */ + { + .name = LPASS_BE_VOICE_PLAYBACK_TX, + .stream_name = "Voice Farend Playback", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(voice_playback_tx), + }, + /* Incall Music 2 BACK END DAI Link */ + { + .name = LPASS_BE_VOICE2_PLAYBACK_TX, + .stream_name = "Voice2 Farend Playback", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(voice2_playback_tx), + }, + /* Proxy Tx BACK END DAI Link */ + { + .name = LPASS_BE_PROXY_TX, + .stream_name = "Proxy Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_PROXY_TX, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(proxy_tx), + }, + /* Proxy Rx BACK END DAI Link */ + { + .name = LPASS_BE_PROXY_RX, + .stream_name = "Proxy Playback", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_PROXY_RX, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(proxy_rx), + }, + { + .name = LPASS_BE_USB_AUDIO_RX, + .stream_name = "USB Audio Playback", +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + .dynamic_be = 1, +#endif /* CONFIG_AUDIO_QGKI */ + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_USB_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(usb_audio_rx), + }, + { + .name = LPASS_BE_USB_AUDIO_TX, + .stream_name = "USB Audio Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_USB_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(usb_audio_tx), + }, + { + .name = LPASS_BE_PRI_TDM_RX_0, + .stream_name = "Primary TDM0 Playback", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_PRI_TDM_RX_0, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &holi_tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(pri_tdm_rx_0), + }, + { + .name = LPASS_BE_PRI_TDM_TX_0, + .stream_name = "Primary TDM0 Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_PRI_TDM_TX_0, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &holi_tdm_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(pri_tdm_tx_0), + }, + { + .name = LPASS_BE_SEC_TDM_RX_0, + .stream_name = "Secondary TDM0 Playback", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SEC_TDM_RX_0, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &holi_tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(sec_tdm_rx_0), + }, + { + .name = LPASS_BE_SEC_TDM_TX_0, + .stream_name = "Secondary TDM0 Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SEC_TDM_TX_0, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &holi_tdm_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(sec_tdm_tx_0), + }, + { + .name = LPASS_BE_TERT_TDM_RX_0, + .stream_name = "Tertiary TDM0 Playback", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_TERT_TDM_RX_0, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &holi_tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(tert_tdm_rx_0), + }, + { + .name = LPASS_BE_TERT_TDM_TX_0, + .stream_name = "Tertiary TDM0 Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_TERT_TDM_TX_0, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &holi_tdm_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(tert_tdm_tx_0), + }, + { + .name = LPASS_BE_QUAT_TDM_RX_0, + .stream_name = "Quaternary TDM0 Playback", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_QUAT_TDM_RX_0, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &holi_tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(quat_tdm_rx_0), + }, + { + .name = LPASS_BE_QUAT_TDM_TX_0, + .stream_name = "Quaternary TDM0 Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_QUAT_TDM_TX_0, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &holi_tdm_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(quat_tdm_tx_0), + }, +}; + +static struct snd_soc_dai_link msm_wcn_btfm_be_dai_links[] = { + { + .name = LPASS_BE_SLIMBUS_7_RX, + .stream_name = "Slimbus7 Playback", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_7_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .init = &msm_wcn_init_lito, + .ops = &msm_wcn_ops_lito, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(slimbus_7_rx), + }, + { + .name = LPASS_BE_SLIMBUS_7_TX, + .stream_name = "Slimbus7 Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_7_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_wcn_ops_lito, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(slimbus_7_tx), + }, + { + .name = LPASS_BE_SLIMBUS_8_TX, + .stream_name = "Slimbus8 Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_8_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_wcn_ops_lito, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(slimbus_8_tx), + }, +}; + +static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = { + { + .name = LPASS_BE_PRI_MI2S_RX, + .stream_name = "Primary MI2S Playback", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_PRI_MI2S_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(pri_mi2s_rx), + }, + { + .name = LPASS_BE_PRI_MI2S_TX, + .stream_name = "Primary MI2S Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_PRI_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(pri_mi2s_tx), + }, + { + .name = LPASS_BE_SEC_MI2S_RX, + .stream_name = "Secondary MI2S Playback", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(sec_mi2s_rx), + }, + { + .name = LPASS_BE_SEC_MI2S_TX, + .stream_name = "Secondary MI2S Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(sec_mi2s_tx), + }, + { + .name = LPASS_BE_TERT_MI2S_RX, + .stream_name = "Tertiary MI2S Playback", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(tert_mi2s_rx), + }, + { + .name = LPASS_BE_TERT_MI2S_TX, + .stream_name = "Tertiary MI2S Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(tert_mi2s_tx), + }, + { + .name = LPASS_BE_QUAT_MI2S_RX, + .stream_name = "Quaternary MI2S Playback", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(quat_mi2s_rx), + }, + { + .name = LPASS_BE_QUAT_MI2S_TX, + .stream_name = "Quaternary MI2S Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(quat_mi2s_tx), + }, +}; + +static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = { + /* Primary AUX PCM Backend DAI Links */ + { + .name = LPASS_BE_AUXPCM_RX, + .stream_name = "AUX PCM Playback", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_AUXPCM_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &holi_aux_be_ops, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(auxpcm_rx), + }, + { + .name = LPASS_BE_AUXPCM_TX, + .stream_name = "AUX PCM Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_AUXPCM_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &holi_aux_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(auxpcm_tx), + }, + /* Secondary AUX PCM Backend DAI Links */ + { + .name = LPASS_BE_SEC_AUXPCM_RX, + .stream_name = "Sec AUX PCM Playback", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SEC_AUXPCM_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &holi_aux_be_ops, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(sec_auxpcm_rx), + }, + { + .name = LPASS_BE_SEC_AUXPCM_TX, + .stream_name = "Sec AUX PCM Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SEC_AUXPCM_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &holi_aux_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(sec_auxpcm_tx), + }, + /* Tertiary AUX PCM Backend DAI Links */ + { + .name = LPASS_BE_TERT_AUXPCM_RX, + .stream_name = "Tert AUX PCM Playback", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_TERT_AUXPCM_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &holi_aux_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(tert_auxpcm_rx), + }, + { + .name = LPASS_BE_TERT_AUXPCM_TX, + .stream_name = "Tert AUX PCM Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_TERT_AUXPCM_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &holi_aux_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(tert_auxpcm_tx), + }, + /* Quaternary AUX PCM Backend DAI Links */ + { + .name = LPASS_BE_QUAT_AUXPCM_RX, + .stream_name = "Quat AUX PCM Playback", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &holi_aux_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(quat_auxpcm_rx), + }, + { + .name = LPASS_BE_QUAT_AUXPCM_TX, + .stream_name = "Quat AUX PCM Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &holi_aux_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(quat_auxpcm_tx), + }, +}; + +static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = { + /* RX CDC DMA Backend DAI Links */ + { + .name = LPASS_BE_RX_CDC_DMA_RX_0, + .stream_name = "RX CDC DMA0 Playback", +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + .dynamic_be = 1, +#endif /* CONFIG_AUDIO_QGKI */ + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_RX_CDC_DMA_RX_0, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + .ops = &msm_cdc_dma_be_ops, + SND_SOC_DAILINK_REG(rx_dma_rx0), + .init = &msm_aux_codec_init, + }, + { + .name = LPASS_BE_RX_CDC_DMA_RX_1, + .stream_name = "RX CDC DMA1 Playback", +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + .dynamic_be = 1, +#endif /* CONFIG_AUDIO_QGKI */ + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_RX_CDC_DMA_RX_1, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + .ops = &msm_cdc_dma_be_ops, + SND_SOC_DAILINK_REG(rx_dma_rx1), + }, + { + .name = LPASS_BE_RX_CDC_DMA_RX_2, + .stream_name = "RX CDC DMA2 Playback", +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + .dynamic_be = 1, +#endif /* CONFIG_AUDIO_QGKI */ + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_RX_CDC_DMA_RX_2, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + .ops = &msm_cdc_dma_be_ops, + SND_SOC_DAILINK_REG(rx_dma_rx2), + }, + { + .name = LPASS_BE_RX_CDC_DMA_RX_3, + .stream_name = "RX CDC DMA3 Playback", +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + .dynamic_be = 1, +#endif /* CONFIG_AUDIO_QGKI */ + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_RX_CDC_DMA_RX_3, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + .ops = &msm_cdc_dma_be_ops, + SND_SOC_DAILINK_REG(rx_dma_rx3), + }, + /* TX CDC DMA Backend DAI Links */ + { + .name = LPASS_BE_TX_CDC_DMA_TX_3, + .stream_name = "TX CDC DMA3 Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_TX_CDC_DMA_TX_3, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + .ops = &msm_cdc_dma_be_ops, + SND_SOC_DAILINK_REG(tx_dma_tx3), + }, + { + .name = LPASS_BE_TX_CDC_DMA_TX_4, + .stream_name = "TX CDC DMA4 Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_TX_CDC_DMA_TX_4, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + .ops = &msm_cdc_dma_be_ops, + SND_SOC_DAILINK_REG(tx_dma_tx4), + }, +}; + +static struct snd_soc_dai_link msm_va_cdc_dma_be_dai_links[] = { + { + .name = LPASS_BE_VA_CDC_DMA_TX_0, + .stream_name = "VA CDC DMA0 Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_VA_CDC_DMA_TX_0, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + .ops = &msm_cdc_dma_be_ops, + SND_SOC_DAILINK_REG(va_dma_tx0), + .init = &msm_int_audrx_init, + }, + { + .name = LPASS_BE_VA_CDC_DMA_TX_1, + .stream_name = "VA CDC DMA1 Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_VA_CDC_DMA_TX_1, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + .ops = &msm_cdc_dma_be_ops, + SND_SOC_DAILINK_REG(va_dma_tx1), + }, + { + .name = LPASS_BE_VA_CDC_DMA_TX_2, + .stream_name = "VA CDC DMA2 Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_VA_CDC_DMA_TX_2, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + .ops = &msm_cdc_dma_be_ops, + SND_SOC_DAILINK_REG(va_dma_tx2), + }, +}; + +static struct snd_soc_dai_link msm_afe_rxtx_lb_be_dai_link[] = { + { + .name = LPASS_BE_AFE_LOOPBACK_TX, + .stream_name = "AFE Loopback Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_AFE_LOOPBACK_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(afe_loopback_tx), + }, +}; + +static struct snd_soc_dai_link msm_holi_dai_links[ + ARRAY_SIZE(msm_common_dai_links) + + ARRAY_SIZE(msm_common_misc_fe_dai_links) + + ARRAY_SIZE(msm_common_be_dai_links) + + ARRAY_SIZE(msm_mi2s_be_dai_links) + + ARRAY_SIZE(msm_auxpcm_be_dai_links) + + ARRAY_SIZE(msm_rx_tx_cdc_dma_be_dai_links) + + ARRAY_SIZE(msm_va_cdc_dma_be_dai_links) + + ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link) + + ARRAY_SIZE(msm_wcn_btfm_be_dai_links)]; + +static int msm_populate_dai_link_component_of_node( + struct snd_soc_card *card) +{ + int i, j, index, ret = 0; + struct device *cdev = card->dev; + struct snd_soc_dai_link *dai_link = card->dai_link; + struct device_node *np = NULL; + int codecs_enabled = 0; + struct snd_soc_dai_link_component *codecs_comp = NULL; + + if (!cdev) { + dev_err(cdev, "%s: Sound card device memory NULL\n", __func__); + return -ENODEV; + } + + for (i = 0; i < card->num_links; i++) { + if (dai_link[i].platforms->of_node && dai_link[i].cpus->of_node) + continue; + + /* populate platform_of_node for snd card dai links */ + if (dai_link[i].platforms->name && + !dai_link[i].platforms->of_node) { + index = of_property_match_string(cdev->of_node, + "asoc-platform-names", + dai_link[i].platforms->name); + if (index < 0) { + dev_err(cdev, "%s: No match found for platform name: %s\n", + __func__, dai_link[i].platforms->name); + ret = index; + goto err; + } + np = of_parse_phandle(cdev->of_node, "asoc-platform", + index); + if (!np) { + dev_err(cdev, "%s: retrieving phandle for platform %s, index %d failed\n", + __func__, dai_link[i].platforms->name, + index); + ret = -ENODEV; + goto err; + } + dai_link[i].platforms->of_node = np; + dai_link[i].platforms->name = NULL; + } + + /* populate cpu_of_node for snd card dai links */ + if (dai_link[i].cpus->dai_name && !dai_link[i].cpus->of_node) { + index = of_property_match_string(cdev->of_node, + "asoc-cpu-names", + dai_link[i].cpus->dai_name); + if (index >= 0) { + np = of_parse_phandle(cdev->of_node, "asoc-cpu", + index); + if (!np) { + dev_err(cdev, "%s: retrieving phandle for cpu dai %s failed\n", + __func__, + dai_link[i].cpus->dai_name); + ret = -ENODEV; + goto err; + } + dai_link[i].cpus->of_node = np; + dai_link[i].cpus->dai_name = NULL; + } + } + + /* populate codec_of_node for snd card dai links */ + if (dai_link[i].num_codecs > 0) { + for (j = 0; j < dai_link[i].num_codecs; j++) { + if (dai_link[i].codecs[j].of_node || + !dai_link[i].codecs[j].name) + continue; + + index = of_property_match_string(cdev->of_node, + "asoc-codec-names", + dai_link[i].codecs[j].name); + if (index < 0) + continue; + np = of_parse_phandle(cdev->of_node, + "asoc-codec", + index); + if (!np) { + dev_err(cdev, "%s: retrieving phandle for codec %s failed\n", + __func__, + dai_link[i].codecs[j].name); + ret = -ENODEV; + goto err; + } + dai_link[i].codecs[j].of_node = np; + dai_link[i].codecs[j].name = NULL; + } + } + } + + /* In multi-codec scenario, check if codecs are enabled for this platform */ + for (i = 0; i < card->num_links; i++) { + codecs_enabled = 0; + if (dai_link[i].num_codecs > 1) { + for (j = 0; j < dai_link[i].num_codecs; j++) { + if (!dai_link[i].codecs[j].of_node) + continue; + + np = dai_link[i].codecs[j].of_node; + if (!of_device_is_available(np)) { + dev_err(cdev, "%s: codec is disabled: %s\n", + __func__, + np->full_name); + dai_link[i].codecs[j].of_node = NULL; + continue; + } + + codecs_enabled++; + } + if (codecs_enabled > 0 && + codecs_enabled < dai_link[i].num_codecs) { + codecs_comp = devm_kzalloc(cdev, + sizeof(struct snd_soc_dai_link_component) + * codecs_enabled, GFP_KERNEL); + if (!codecs_comp) { + dev_err(cdev, "%s: %s dailink codec component alloc failed\n", + __func__, dai_link[i].name); + ret = -ENOMEM; + goto err; + } + index = 0; + for (j = 0; j < dai_link[i].num_codecs; j++) { + if (dai_link[i].codecs[j].of_node) { + codecs_comp[index].of_node = + dai_link[i].codecs[j].of_node; + codecs_comp[index].dai_name = + dai_link[i].codecs[j].dai_name; + codecs_comp[index].name = NULL; + index++; + } + } + dai_link[i].codecs = codecs_comp; + dai_link[i].num_codecs = codecs_enabled; + } + } + } + +err: + return ret; +} + +static int msm_audrx_stub_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret = -EINVAL; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, "msm-stub-codec"); + + if (!component) { + pr_err("* %s: No match for msm-stub-codec component\n", __func__); + return ret; + } + + ret = snd_soc_add_component_controls(component, msm_snd_controls, + ARRAY_SIZE(msm_snd_controls)); + if (ret < 0) { + dev_err(component->dev, + "%s: add_codec_controls failed, err = %d\n", + __func__, ret); + return ret; + } + + return ret; +} + +static int msm_snd_stub_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + return 0; +} + +static struct snd_soc_ops msm_stub_be_ops = { + .hw_params = msm_snd_stub_hw_params, +}; + +struct snd_soc_card snd_soc_card_stub_msm = { + .name = "holi-stub-snd-card", +}; + +static struct snd_soc_dai_link msm_stub_fe_dai_links[] = { + /* FrontEnd DAI Links */ + { + .name = "MSMSTUB Media1", + .stream_name = "MultiMedia1", + .dynamic = 1, +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, +#endif /* CONFIG_AUDIO_QGKI */ + .dpcm_playback = 1, + .dpcm_capture = 1, + .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_MULTIMEDIA1, + SND_SOC_DAILINK_REG(multimedia1), + }, +}; + +static struct snd_soc_dai_link msm_stub_be_dai_links[] = { + /* Backend DAI Links */ + { + .name = LPASS_BE_AUXPCM_RX, + .stream_name = "AUX PCM Playback", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_AUXPCM_RX, + .init = &msm_audrx_stub_init, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + .ops = &msm_stub_be_ops, + SND_SOC_DAILINK_REG(auxpcm_rx), + }, + { + .name = LPASS_BE_AUXPCM_TX, + .stream_name = "AUX PCM Capture", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_AUXPCM_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + .ops = &msm_stub_be_ops, + SND_SOC_DAILINK_REG(auxpcm_tx), + }, +}; + +static struct snd_soc_dai_link msm_stub_dai_links[ + ARRAY_SIZE(msm_stub_fe_dai_links) + + ARRAY_SIZE(msm_stub_be_dai_links)]; + +static const struct of_device_id holi_asoc_machine_of_match[] = { + { .compatible = "qcom,holi-asoc-snd", + .data = "codec"}, + { .compatible = "qcom,holi-asoc-snd-stub", + .data = "stub_codec"}, + {}, +}; + +static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) +{ + struct snd_soc_card *card = NULL; + struct snd_soc_dai_link *dailink = NULL; + int len_1 = 0; + int len_2 = 0; + int total_links = 0; + int rc = 0; + u32 mi2s_audio_intf = 0; + u32 auxpcm_audio_intf = 0; + u32 val = 0; + u32 wcn_btfm_intf = 0; + const struct of_device_id *match; + + match = of_match_node(holi_asoc_machine_of_match, dev->of_node); + if (!match) { + dev_err(dev, "%s: No DT match found for sound card\n", + __func__); + return NULL; + } + + if (!strcmp(match->data, "codec")) { + card = &snd_soc_card_holi_msm; + + memcpy(msm_holi_dai_links + total_links, + msm_common_dai_links, + sizeof(msm_common_dai_links)); + total_links += ARRAY_SIZE(msm_common_dai_links); + + memcpy(msm_holi_dai_links + total_links, + msm_common_misc_fe_dai_links, + sizeof(msm_common_misc_fe_dai_links)); + total_links += ARRAY_SIZE(msm_common_misc_fe_dai_links); + + memcpy(msm_holi_dai_links + total_links, + msm_common_be_dai_links, + sizeof(msm_common_be_dai_links)); + total_links += ARRAY_SIZE(msm_common_be_dai_links); + + memcpy(msm_holi_dai_links + total_links, + msm_rx_tx_cdc_dma_be_dai_links, + sizeof(msm_rx_tx_cdc_dma_be_dai_links)); + total_links += + ARRAY_SIZE(msm_rx_tx_cdc_dma_be_dai_links); + + memcpy(msm_holi_dai_links + total_links, + msm_va_cdc_dma_be_dai_links, + sizeof(msm_va_cdc_dma_be_dai_links)); + total_links += + ARRAY_SIZE(msm_va_cdc_dma_be_dai_links); + + rc = of_property_read_u32(dev->of_node, "qcom,mi2s-audio-intf", + &mi2s_audio_intf); + if (rc) { + dev_dbg(dev, "%s: No DT match MI2S audio interface\n", + __func__); + } else { + if (mi2s_audio_intf) { + memcpy(msm_holi_dai_links + total_links, + msm_mi2s_be_dai_links, + sizeof(msm_mi2s_be_dai_links)); + total_links += + ARRAY_SIZE(msm_mi2s_be_dai_links); + } + } + + rc = of_property_read_u32(dev->of_node, + "qcom,auxpcm-audio-intf", + &auxpcm_audio_intf); + if (rc) { + dev_dbg(dev, "%s: No DT match Aux PCM interface\n", + __func__); + } else { + if (auxpcm_audio_intf) { + memcpy(msm_holi_dai_links + total_links, + msm_auxpcm_be_dai_links, + sizeof(msm_auxpcm_be_dai_links)); + total_links += + ARRAY_SIZE(msm_auxpcm_be_dai_links); + } + } + + rc = of_property_read_u32(dev->of_node, "qcom,afe-rxtx-lb", + &val); + if (!rc && val) { + memcpy(msm_holi_dai_links + total_links, + msm_afe_rxtx_lb_be_dai_link, + sizeof(msm_afe_rxtx_lb_be_dai_link)); + total_links += + ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link); + } + + rc = of_property_read_u32(dev->of_node, "qcom,wcn-btfm", + &wcn_btfm_intf); + if (rc) { + dev_dbg(dev, "%s: No DT match wcn btfm interface\n", + __func__); + } else { + if (wcn_btfm_intf) { + memcpy(msm_holi_dai_links + total_links, + msm_wcn_btfm_be_dai_links, + sizeof(msm_wcn_btfm_be_dai_links)); + total_links += + ARRAY_SIZE(msm_wcn_btfm_be_dai_links); + } + } + dailink = msm_holi_dai_links; + } else if (!strcmp(match->data, "stub_codec")) { + card = &snd_soc_card_stub_msm; + len_1 = ARRAY_SIZE(msm_stub_fe_dai_links); + len_2 = len_1 + ARRAY_SIZE(msm_stub_be_dai_links); + + memcpy(msm_stub_dai_links, + msm_stub_fe_dai_links, + sizeof(msm_stub_fe_dai_links)); + memcpy(msm_stub_dai_links + len_1, + msm_stub_be_dai_links, + sizeof(msm_stub_be_dai_links)); + + dailink = msm_stub_dai_links; + total_links = len_2; + } + + if (card) { + card->dai_link = dailink; + card->num_links = total_links; + } + + return card; +} + +static int msm_int_audrx_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *component = NULL; + struct snd_soc_dapm_context *dapm = NULL; + struct snd_card *card = NULL; + struct snd_info_entry *entry = NULL; + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(rtd->card); + int ret = 0; + + component = snd_soc_rtdcom_lookup(rtd, "bolero_codec"); + if (!component) { + pr_err("%s: could not find component for bolero_codec\n", + __func__); + return ret; + } + + dapm = snd_soc_component_get_dapm(component); + + ret = snd_soc_add_component_controls(component, msm_int_snd_controls, + ARRAY_SIZE(msm_int_snd_controls)); + if (ret < 0) { + pr_err("%s: add_component_controls failed: %d\n", + __func__, ret); + return ret; + } + ret = snd_soc_add_component_controls(component, msm_common_snd_controls, + ARRAY_SIZE(msm_common_snd_controls)); + if (ret < 0) { + pr_err("%s: add common snd controls failed: %d\n", + __func__, ret); + return ret; + } + + snd_soc_dapm_new_controls(dapm, msm_int_dapm_widgets, + ARRAY_SIZE(msm_int_dapm_widgets)); + + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic0"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic3"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic4"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic5"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic6"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic7"); + + snd_soc_dapm_ignore_suspend(dapm, "Analog Mic1"); + snd_soc_dapm_ignore_suspend(dapm, "Analog Mic2"); + snd_soc_dapm_ignore_suspend(dapm, "Analog Mic3"); + snd_soc_dapm_ignore_suspend(dapm, "Analog Mic4"); + snd_soc_dapm_ignore_suspend(dapm, "Analog Mic5"); + + + snd_soc_dapm_sync(dapm); + + card = rtd->card->snd_card; + if (!pdata->codec_root) { + entry = msm_snd_info_create_subdir(card->module, "codecs", + card->proc_root); + if (!entry) { + pr_debug("%s: Cannot create codecs module entry\n", + __func__); + ret = 0; + goto err; + } + pdata->codec_root = entry; + } + bolero_info_create_codec_entry(pdata->codec_root, component); + bolero_register_wake_irq(component, false); + codec_reg_done = true; + +err: + return ret; +} + +static int msm_aux_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *bolero_component = NULL; + struct snd_soc_component *component = NULL; + struct snd_soc_dapm_context *dapm = NULL; + int ret = 0; + int codec_variant = -1; + void *mbhc_calibration; + struct snd_info_entry *entry; + struct snd_card *card = NULL; + struct msm_asoc_mach_data *pdata; + + pdata = snd_soc_card_get_drvdata(rtd->card); + if(!pdata) + return -EINVAL; + + bolero_component = snd_soc_rtdcom_lookup(rtd, "bolero_codec"); + if (!bolero_component) { + pr_err("%s: could not find component for bolero_codec\n", + __func__); + return -EINVAL; + } + + if (pdata->wcd_disabled) { + bolero_set_port_map(bolero_component, + ARRAY_SIZE(sm_port_map), sm_port_map); + return 0; + } + + component = snd_soc_rtdcom_lookup(rtd, WCD938X_DRV_NAME); + if (!component) { + component = snd_soc_rtdcom_lookup(rtd, WCD937X_DRV_NAME); + } + if (!component) { + pr_err("%s component is NULL\n", __func__); + return -EINVAL; + } + dapm = snd_soc_component_get_dapm(component); + card = component->card->snd_card; + + snd_soc_dapm_ignore_suspend(dapm, "EAR"); + snd_soc_dapm_ignore_suspend(dapm, "AUX"); + snd_soc_dapm_ignore_suspend(dapm, "HPHL"); + snd_soc_dapm_ignore_suspend(dapm, "HPHR"); + snd_soc_dapm_ignore_suspend(dapm, "AMIC1"); + snd_soc_dapm_ignore_suspend(dapm, "AMIC2"); + snd_soc_dapm_ignore_suspend(dapm, "AMIC3"); + snd_soc_dapm_ignore_suspend(dapm, "AMIC4"); + snd_soc_dapm_sync(dapm); + + if (!pdata->codec_root) { + entry = msm_snd_info_create_subdir(card->module, "codecs", + card->proc_root); + if (!entry) { + dev_dbg(component->dev, "%s: Cannot create codecs module entry\n", + __func__); + ret = 0; + goto mbhc_cfg_cal; + } + pdata->codec_root = entry; + } + + if (!strncmp(component->driver->name, WCD937X_DRV_NAME, 13)) { + wcd937x_info_create_codec_entry(pdata->codec_root, component); + ret = snd_soc_add_component_controls(component, + msm_int_wcd937x_snd_controls, + ARRAY_SIZE(msm_int_wcd937x_snd_controls)); + bolero_set_port_map(bolero_component, + ARRAY_SIZE(sm_port_map_wcd937x), sm_port_map_wcd937x); + } else if (!strncmp(component->driver->name, WCD938X_DRV_NAME, 13)) { + wcd938x_info_create_codec_entry(pdata->codec_root, component); + + codec_variant = wcd938x_get_codec_variant(component); + dev_dbg(component->dev, "%s: variant %d\n", + __func__, codec_variant); + if (codec_variant == WCD9380) + ret = snd_soc_add_component_controls(component, + msm_int_wcd9380_snd_controls, + ARRAY_SIZE(msm_int_wcd9380_snd_controls)); + else if (codec_variant == WCD9385) + ret = snd_soc_add_component_controls(component, + msm_int_wcd9385_snd_controls, + ARRAY_SIZE(msm_int_wcd9385_snd_controls)); + bolero_set_port_map(bolero_component, ARRAY_SIZE(sm_port_map), + sm_port_map); + } else { + bolero_set_port_map(bolero_component, ARRAY_SIZE(sm_port_map), + sm_port_map); + } + + if (ret < 0) { + dev_err(component->dev, + "%s: add codec specific snd controls failed: %d\n", + __func__, ret); + return ret; + } + + +mbhc_cfg_cal: + mbhc_calibration = def_wcd_mbhc_cal(); + if (!mbhc_calibration) + return -ENOMEM; + wcd_mbhc_cfg.calibration = mbhc_calibration; + ret = wcd938x_mbhc_hs_detect(component, &wcd_mbhc_cfg); + if (ret) { + dev_err(component->dev, "%s: mbhc hs detect failed, err:%d\n", + __func__, ret); + goto err_hs_detect; + } + return 0; + +err_hs_detect: + kfree(mbhc_calibration); + return ret; +} + +static void msm_i2s_auxpcm_init(struct platform_device *pdev) +{ + int count = 0; + u32 mi2s_master_slave[MI2S_MAX]; + int ret = 0; + + for (count = 0; count < MI2S_MAX; count++) { + mutex_init(&mi2s_intf_conf[count].lock); + mi2s_intf_conf[count].ref_cnt = 0; + } + + ret = of_property_read_u32_array(pdev->dev.of_node, + "qcom,msm-mi2s-master", + mi2s_master_slave, MI2S_MAX); + if (ret) { + dev_dbg(&pdev->dev, "%s: no qcom,msm-mi2s-master in DT node\n", + __func__); + } else { + for (count = 0; count < MI2S_MAX; count++) { + mi2s_intf_conf[count].msm_is_mi2s_master = + mi2s_master_slave[count]; + } + } +} + +static void msm_i2s_auxpcm_deinit(void) +{ + int count = 0; + + for (count = 0; count < MI2S_MAX; count++) { + mutex_destroy(&mi2s_intf_conf[count].lock); + mi2s_intf_conf[count].ref_cnt = 0; + mi2s_intf_conf[count].msm_is_mi2s_master = 0; + } +} + +static int holi_ssr_enable(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct snd_soc_card *card = platform_get_drvdata(pdev); + int ret = 0; + + if (!card) { + dev_err(dev, "%s: card is NULL\n", __func__); + ret = -EINVAL; + goto err; + } + + if (!strcmp(card->name, "holi-stub-snd-card")) { + /* TODO */ + dev_dbg(dev, "%s: TODO \n", __func__); + } + +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + snd_soc_card_change_online_state(card, 1); +#endif /* CONFIG_AUDIO_QGKI */ + dev_dbg(dev, "%s: setting snd_card to ONLINE\n", __func__); + +err: + return ret; +} + +static void holi_ssr_disable(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct snd_soc_card *card = platform_get_drvdata(pdev); + + if (!card) { + dev_err(dev, "%s: card is NULL\n", __func__); + return; + } + + dev_dbg(dev, "%s: setting snd_card to OFFLINE\n", __func__); +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + snd_soc_card_change_online_state(card, 0); +#endif /* CONFIG_AUDIO_QGKI */ + + if (!strcmp(card->name, "holi-stub-snd-card")) { + /* TODO */ + dev_dbg(dev, "%s: TODO \n", __func__); + } +} + +static const struct snd_event_ops holi_ssr_ops = { + .enable = holi_ssr_enable, + .disable = holi_ssr_disable, +}; + +static int msm_audio_ssr_compare(struct device *dev, void *data) +{ + struct device_node *node = data; + + dev_dbg(dev, "%s: dev->of_node = 0x%p, node = 0x%p\n", + __func__, dev->of_node, node); + return (dev->of_node && dev->of_node == node); +} + +static int msm_audio_ssr_register(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct snd_event_clients *ssr_clients = NULL; + struct device_node *node = NULL; + int ret = 0; + int i = 0; + + for (i = 0; ; i++) { + node = of_parse_phandle(np, "qcom,msm_audio_ssr_devs", i); + if (!node) + break; + snd_event_mstr_add_client(&ssr_clients, + msm_audio_ssr_compare, node); + } + + ret = snd_event_master_register(dev, &holi_ssr_ops, + ssr_clients, NULL); + if (!ret) + snd_event_notify(dev, SND_EVENT_UP); + + return ret; +} + +static int msm_asoc_machine_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = NULL; + struct msm_asoc_mach_data *pdata = NULL; + const char *mbhc_audio_jack_type = NULL; + int ret = 0; + uint index = 0; + struct clk *lpass_audio_hw_vote = NULL; + + if (!pdev->dev.of_node) { + dev_err(&pdev->dev, + "%s: No platform supplied from device tree\n", __func__); + return -EINVAL; + } + + pdata = devm_kzalloc(&pdev->dev, + sizeof(struct msm_asoc_mach_data), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + of_property_read_u32(pdev->dev.of_node, + "qcom,wcd-disabled", + &pdata->wcd_disabled); + + card = populate_snd_card_dailinks(&pdev->dev); + if (!card) { + dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__); + ret = -EINVAL; + goto err; + } + + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, pdata); + + ret = snd_soc_of_parse_card_name(card, "qcom,model"); + if (ret) { + dev_err(&pdev->dev, "%s: parse card name failed, err:%d\n", + __func__, ret); + goto err; + } + + ret = snd_soc_of_parse_audio_routing(card, "qcom,audio-routing"); + if (ret) { + dev_err(&pdev->dev, "%s: parse audio routing failed, err:%d\n", + __func__, ret); + goto err; + } + + ret = msm_populate_dai_link_component_of_node(card); + if (ret) { + ret = -EPROBE_DEFER; + goto err; + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret == -EPROBE_DEFER) { + if (codec_reg_done) + ret = -EINVAL; + goto err; + } else if (ret) { + dev_err(&pdev->dev, "%s: snd_soc_register_card failed (%d)\n", + __func__, ret); + goto err; + } + dev_info(&pdev->dev, "%s: Sound card %s registered\n", + __func__, card->name); + + pdata->hph_en1_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,hph-en1-gpio", 0); + if (!pdata->hph_en1_gpio_p) { + dev_dbg(&pdev->dev, "%s: property %s not detected in node %s\n", + __func__, "qcom,hph-en1-gpio", + pdev->dev.of_node->full_name); + } + + pdata->hph_en0_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,hph-en0-gpio", 0); + if (!pdata->hph_en0_gpio_p) { + dev_dbg(&pdev->dev, "%s: property %s not detected in node %s\n", + __func__, "qcom,hph-en0-gpio", + pdev->dev.of_node->full_name); + } + + ret = of_property_read_string(pdev->dev.of_node, + "qcom,mbhc-audio-jack-type", &mbhc_audio_jack_type); + if (ret) { + dev_dbg(&pdev->dev, "%s: Looking up %s property in node %s failed\n", + __func__, "qcom,mbhc-audio-jack-type", + pdev->dev.of_node->full_name); + dev_dbg(&pdev->dev, "Jack type properties set to default\n"); + } else { + if (!strcmp(mbhc_audio_jack_type, "4-pole-jack")) { + wcd_mbhc_cfg.enable_anc_mic_detect = false; + dev_dbg(&pdev->dev, "This hardware has 4 pole jack"); + } else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack")) { + wcd_mbhc_cfg.enable_anc_mic_detect = true; + dev_dbg(&pdev->dev, "This hardware has 5 pole jack"); + } else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack")) { + wcd_mbhc_cfg.enable_anc_mic_detect = true; + dev_dbg(&pdev->dev, "This hardware has 6 pole jack"); + } else { + wcd_mbhc_cfg.enable_anc_mic_detect = false; + dev_dbg(&pdev->dev, "Unknown value, set to default\n"); + } + } + /* + * Parse US-Euro gpio info from DT. Report no error if us-euro + * entry is not found in DT file as some targets do not support + * US-Euro detection + */ + pdata->us_euro_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,us-euro-gpios", 0); + if (!pdata->us_euro_gpio_p) { + dev_dbg(&pdev->dev, "property %s not detected in node %s", + "qcom,us-euro-gpios", pdev->dev.of_node->full_name); + } else { + dev_dbg(&pdev->dev, "%s detected\n", + "qcom,us-euro-gpios"); + wcd_mbhc_cfg.swap_gnd_mic = msm_swap_gnd_mic; + } + + if (wcd_mbhc_cfg.enable_usbc_analog) + wcd_mbhc_cfg.swap_gnd_mic = msm_usbc_swap_gnd_mic; + + pdata->fsa_handle = of_parse_phandle(pdev->dev.of_node, + "fsa4480-i2c-handle", 0); + if (!pdata->fsa_handle) + dev_dbg(&pdev->dev, "property %s not detected in node %s\n", + "fsa4480-i2c-handle", pdev->dev.of_node->full_name); + + msm_i2s_auxpcm_init(pdev); + pdata->dmic01_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,cdc-dmic01-gpios", + 0); + pdata->dmic23_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,cdc-dmic23-gpios", + 0); + pdata->dmic45_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,cdc-dmic45-gpios", + 0); + if (pdata->dmic01_gpio_p) + msm_cdc_pinctrl_set_wakeup_capable(pdata->dmic01_gpio_p, false); + if (pdata->dmic23_gpio_p) + msm_cdc_pinctrl_set_wakeup_capable(pdata->dmic23_gpio_p, false); + if (pdata->dmic45_gpio_p) + msm_cdc_pinctrl_set_wakeup_capable(pdata->dmic45_gpio_p, false); + + pdata->mi2s_gpio_p[PRIM_MI2S] = of_parse_phandle(pdev->dev.of_node, + "qcom,pri-mi2s-gpios", 0); + pdata->mi2s_gpio_p[SEC_MI2S] = of_parse_phandle(pdev->dev.of_node, + "qcom,sec-mi2s-gpios", 0); + pdata->mi2s_gpio_p[TERT_MI2S] = of_parse_phandle(pdev->dev.of_node, + "qcom,tert-mi2s-gpios", 0); + pdata->mi2s_gpio_p[QUAT_MI2S] = of_parse_phandle(pdev->dev.of_node, + "qcom,quat-mi2s-gpios", 0); + for (index = PRIM_MI2S; index < MI2S_MAX; index++) + atomic_set(&(pdata->mi2s_gpio_ref_count[index]), 0); + + /* Register LPASS audio hw vote */ + lpass_audio_hw_vote = devm_clk_get(&pdev->dev, "lpass_audio_hw_vote"); + if (IS_ERR(lpass_audio_hw_vote)) { + ret = PTR_ERR(lpass_audio_hw_vote); + dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n", + __func__, "lpass_audio_hw_vote", ret); + lpass_audio_hw_vote = NULL; + ret = 0; + } + pdata->lpass_audio_hw_vote = lpass_audio_hw_vote; + pdata->core_audio_vote_count = 0; + + ret = msm_audio_ssr_register(&pdev->dev); + if (ret) + pr_err("%s: Registration with SND event FWK failed ret = %d\n", + __func__, ret); + + is_initial_boot = true; + + /* Add QoS request for audio tasks */ + msm_audio_add_qos_request(); + + return 0; +err: + devm_kfree(&pdev->dev, pdata); + return ret; +} + +static int msm_asoc_machine_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + snd_event_master_deregister(&pdev->dev); + snd_soc_unregister_card(card); + msm_i2s_auxpcm_deinit(); + msm_audio_remove_qos_request(); + + return 0; +} + +static struct platform_driver holi_asoc_machine_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = holi_asoc_machine_of_match, + .suppress_bind_attrs = true, + }, + .probe = msm_asoc_machine_probe, + .remove = msm_asoc_machine_remove, +}; +module_platform_driver(holi_asoc_machine_driver); + +MODULE_SOFTDEP("pre: bt_fm_slim"); +MODULE_DESCRIPTION("ALSA SoC msm"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, holi_asoc_machine_of_match); diff --git a/asoc/lahaina-port-config.h b/asoc/lahaina-port-config.h index 9e9c2be047..6a0afd4103 100644 --- a/asoc/lahaina-port-config.h +++ b/asoc/lahaina-port-config.h @@ -46,13 +46,35 @@ static struct port_params rx_frame_params_default[SWR_MSTR_PORT_LEN] = { /* TX UC1: TX1: 1ch, TX2: 2chs, TX3: 1ch(MBHC) */ static struct port_params tx_frame_params_default[SWR_MSTR_PORT_LEN] = { + {7, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX1 */ + {3, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0x00, 0x00}, /* TX2 */ + {7, 5, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX3 */ +}; + +/* TX UC1: TX1: 1ch, TX2: 2chs, TX3: 1ch(MBHC) */ +static struct port_params tx_frame_params_shima[SWR_MSTR_PORT_LEN] = { {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX1 */ - {3, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX2 */ - {7, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX3 */ + {3, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0x00, 0x00}, /* TX2 */ + {7, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX3 */ +}; + +/* 4.8 MHz clock */ +static struct port_params tx_frame_params_4p8MHz[SWR_MSTR_PORT_LEN] = { + {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX1 */ + {3, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0x00, 0x00}, /* TX2 */ + {3, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX3 */ }; static struct swr_mstr_port_map sm_port_map[] = { {TX_MACRO, SWR_UC0, tx_frame_params_default}, + {TX_MACRO, SWR_UC1, tx_frame_params_4p8MHz}, + {RX_MACRO, SWR_UC0, rx_frame_params_default}, + {RX_MACRO, SWR_UC1, rx_frame_params_dsd}, + {WSA_MACRO, SWR_UC0, wsa_frame_params_default}, +}; + +static struct swr_mstr_port_map sm_port_map_shima[] = { + {TX_MACRO, SWR_UC0, tx_frame_params_shima}, {RX_MACRO, SWR_UC0, rx_frame_params_default}, {RX_MACRO, SWR_UC1, rx_frame_params_dsd}, {WSA_MACRO, SWR_UC0, wsa_frame_params_default}, diff --git a/asoc/msm_dailink.h b/asoc/msm_dailink.h index 44179588e7..1217e41022 100644 --- a/asoc/msm_dailink.h +++ b/asoc/msm_dailink.h @@ -5,6 +5,7 @@ #include + SND_SOC_DAILINK_DEFS(usb_audio_rx, DAILINK_COMP_ARRAY(COMP_CPU("snd-soc-dummy-dai")), DAILINK_COMP_ARRAY(COMP_DUMMY()), @@ -145,4 +146,4 @@ SND_SOC_DAILINK_DEFS(proxy_tx, SND_SOC_DAILINK_DEFS(proxy_rx, DAILINK_COMP_ARRAY(COMP_CPU("snd-soc-dummy-dai")), DAILINK_COMP_ARRAY(COMP_DUMMY()), - DAILINK_COMP_ARRAY(COMP_PLATFORM("snd-soc-dummy"))); + DAILINK_COMP_ARRAY(COMP_PLATFORM("snd-soc-dummy"))); \ No newline at end of file diff --git a/asoc/msm_holi_dailink.h b/asoc/msm_holi_dailink.h new file mode 100644 index 0000000000..513a745f25 --- /dev/null +++ b/asoc/msm_holi_dailink.h @@ -0,0 +1,471 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include + +/* FE dai-links */ +SND_SOC_DAILINK_DEFS(multimedia1, + DAILINK_COMP_ARRAY(COMP_CPU("MultiMedia1")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-dsp.0"))); + +SND_SOC_DAILINK_DEFS(multimedia2, + DAILINK_COMP_ARRAY(COMP_CPU("MultiMedia2")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-dsp.0"))); + +SND_SOC_DAILINK_DEFS(voicemmode1, + DAILINK_COMP_ARRAY(COMP_CPU("VoiceMMode1")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-voice"))); + +SND_SOC_DAILINK_DEFS(msmvoip, + DAILINK_COMP_ARRAY(COMP_CPU("VoIP")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-voip-dsp"))); + +SND_SOC_DAILINK_DEFS(multimedia3, + DAILINK_COMP_ARRAY(COMP_CPU("MultiMedia3")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-dsp.2"))); + +SND_SOC_DAILINK_DEFS(afepcm_rx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-dev.241")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-afe"))); + +SND_SOC_DAILINK_DEFS(afepcm_tx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-dev.240")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-afe"))); + +SND_SOC_DAILINK_DEFS(multimedia4, + DAILINK_COMP_ARRAY(COMP_CPU("MultiMedia4")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-compress-dsp"))); + +SND_SOC_DAILINK_DEFS(auxpcm_hostless, + DAILINK_COMP_ARRAY(COMP_CPU("AUXPCM_HOSTLESS")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-hostless"))); + +SND_SOC_DAILINK_DEFS(multimedia5, + DAILINK_COMP_ARRAY(COMP_CPU("MultiMedia5")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-dsp.1"))); + +SND_SOC_DAILINK_DEFS(listen1, + DAILINK_COMP_ARRAY(COMP_CPU("LSM1")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-lsm-client"))); + +SND_SOC_DAILINK_DEFS(multimedia7, + DAILINK_COMP_ARRAY(COMP_CPU("MultiMedia7")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-compress-dsp"))); + +SND_SOC_DAILINK_DEFS(multimedia10, + DAILINK_COMP_ARRAY(COMP_CPU("MultiMedia10")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-dsp.1"))); + +SND_SOC_DAILINK_DEFS(multimedia8, + DAILINK_COMP_ARRAY(COMP_CPU("MultiMedia8")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-dsp-noirq"))); + +SND_SOC_DAILINK_DEFS(hdmi_rx_hostless, + DAILINK_COMP_ARRAY(COMP_CPU("HDMI_HOSTLESS")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-hostless"))); + +SND_SOC_DAILINK_DEFS(voicemmode2, + DAILINK_COMP_ARRAY(COMP_CPU("VoiceMMode2")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-voice"))); + +SND_SOC_DAILINK_DEFS(listen2, + DAILINK_COMP_ARRAY(COMP_CPU("LSM2")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-lsm-client"))); + +SND_SOC_DAILINK_DEFS(listen3, + DAILINK_COMP_ARRAY(COMP_CPU("LSM3")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-lsm-client"))); + +SND_SOC_DAILINK_DEFS(listen4, + DAILINK_COMP_ARRAY(COMP_CPU("LSM4")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-lsm-client"))); + +SND_SOC_DAILINK_DEFS(listen5, + DAILINK_COMP_ARRAY(COMP_CPU("LSM5")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-lsm-client"))); + +SND_SOC_DAILINK_DEFS(listen6, + DAILINK_COMP_ARRAY(COMP_CPU("LSM6")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-lsm-client"))); + +SND_SOC_DAILINK_DEFS(listen7, + DAILINK_COMP_ARRAY(COMP_CPU("LSM7")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-lsm-client"))); + +SND_SOC_DAILINK_DEFS(listen8, + DAILINK_COMP_ARRAY(COMP_CPU("LSM8")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-lsm-client"))); + +SND_SOC_DAILINK_DEFS(multimedia9, + DAILINK_COMP_ARRAY(COMP_CPU("MultiMedia9")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-dsp.0"))); + +SND_SOC_DAILINK_DEFS(multimedia11, + DAILINK_COMP_ARRAY(COMP_CPU("MultiMedia11")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-compress-dsp"))); + +SND_SOC_DAILINK_DEFS(multimedia12, + DAILINK_COMP_ARRAY(COMP_CPU("MultiMedia12")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-compress-dsp"))); + +SND_SOC_DAILINK_DEFS(multimedia13, + DAILINK_COMP_ARRAY(COMP_CPU("MultiMedia13")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-compress-dsp"))); + +SND_SOC_DAILINK_DEFS(multimedia14, + DAILINK_COMP_ARRAY(COMP_CPU("MultiMedia14")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-compress-dsp"))); + +SND_SOC_DAILINK_DEFS(multimedia15, + DAILINK_COMP_ARRAY(COMP_CPU("MultiMedia15")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-compress-dsp"))); + +SND_SOC_DAILINK_DEFS(multimedia16, + DAILINK_COMP_ARRAY(COMP_CPU("MultiMedia16")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-dsp-noirq"))); + +SND_SOC_DAILINK_DEFS(cdcdma_hostless, + DAILINK_COMP_ARRAY(COMP_CPU("CDC_DMA_HOSTLESS")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-hostless"))); + +SND_SOC_DAILINK_DEFS(tx3_cdcdma_hostless, + DAILINK_COMP_ARRAY(COMP_CPU("TX3_CDC_DMA_HOSTLESS")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-hostless"))); + +SND_SOC_DAILINK_DEFS(tert_mi2s_tx_hostless, + DAILINK_COMP_ARRAY(COMP_CPU("TERT_MI2S_TX_HOSTLESS")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-hostless"))); + +SND_SOC_DAILINK_DEFS(multimedia6, + DAILINK_COMP_ARRAY(COMP_CPU("MultiMedia6")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-loopback"))); + +SND_SOC_DAILINK_DEFS(usbaudio_hostless, + DAILINK_COMP_ARRAY(COMP_CPU("USBAUDIO_HOSTLESS")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-hostless"))); + +SND_SOC_DAILINK_DEFS(slimbus7_hostless, + DAILINK_COMP_ARRAY(COMP_CPU("SLIMBUS7_HOSTLESS")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-hostless"))); + +SND_SOC_DAILINK_DEFS(multimedia17, + DAILINK_COMP_ARRAY(COMP_CPU("MultiMedia17")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-compress-dsp"))); + +SND_SOC_DAILINK_DEFS(slimbus8_hostless, + DAILINK_COMP_ARRAY(COMP_CPU("SLIMBUS8_HOSTLESS")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-hostless"))); + +SND_SOC_DAILINK_DEFS(tx_cdcdma5_tx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-cdc-dma-dev.45115")), + DAILINK_COMP_ARRAY(COMP_CODEC("bolero_codec", "tx_macro_tx3"), + COMP_CODEC("wcd938x_codec", "wcd938x_cdc")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-hostless"))); + +SND_SOC_DAILINK_DEFS(multimedia31, + DAILINK_COMP_ARRAY(COMP_CPU("MultiMedia31")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-dsp.0"))); + +SND_SOC_DAILINK_DEFS(multimedia32, + DAILINK_COMP_ARRAY(COMP_CPU("MultiMedia32")), + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-dsp.0"))); + +SND_SOC_DAILINK_DEFS(afepcm_tx1, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-dev.242")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-afe"))); + +/* BE dai-links */ +SND_SOC_DAILINK_DEFS(afe_pcm_rx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-dev.224")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(afe_pcm_tx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-dev.225")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(incall_record_tx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-dev.32772")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(incall_record_rx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-dev.32771")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(voice_playback_tx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-dev.32773")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(voice2_playback_tx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-dev.32770")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(usb_audio_rx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-dev.28672")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(usb_audio_tx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-dev.28673")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(pri_tdm_rx_0, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-tdm.36864")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(pri_tdm_tx_0, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-tdm.36865")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(sec_tdm_rx_0, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-tdm.36880")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(sec_tdm_tx_0, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-tdm.36881")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(tert_tdm_rx_0, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-tdm.36896")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(tert_tdm_tx_0, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-tdm.36897")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(quat_tdm_rx_0, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-tdm.36912")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(quat_tdm_tx_0, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-tdm.36913")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(slimbus_7_rx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-dev.16398")), + DAILINK_COMP_ARRAY(COMP_CODEC("btfmslim_slave", + "btfm_bt_sco_a2dp_slim_rx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(slimbus_7_tx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-dev.16399")), + DAILINK_COMP_ARRAY(COMP_CODEC("btfmslim_slave", + "btfm_bt_sco_slim_tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(slimbus_8_tx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-dev.16401")), + DAILINK_COMP_ARRAY(COMP_CODEC("btfmslim_slave", + "btfm_fm_slim_tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(pri_mi2s_rx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.0")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(pri_mi2s_tx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.0")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(sec_mi2s_rx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.1")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(sec_mi2s_tx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.1")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(tert_mi2s_rx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.2")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(tert_mi2s_tx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.2")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(quat_mi2s_rx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.3")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(quat_mi2s_tx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.3")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(auxpcm_rx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-auxpcm.1")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(auxpcm_tx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-auxpcm.1")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(sec_auxpcm_rx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-auxpcm.2")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(sec_auxpcm_tx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-auxpcm.2")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(tert_auxpcm_rx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-auxpcm.3")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(tert_auxpcm_tx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-auxpcm.3")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(quat_auxpcm_rx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-auxpcm.4")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(quat_auxpcm_tx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-auxpcm.4")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(rx_dma_rx0, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-cdc-dma-dev.45104")), + DAILINK_COMP_ARRAY(COMP_CODEC("bolero_codec", "rx_macro_rx1"), + COMP_CODEC("wcd938x_codec", "wcd938x_cdc"), + COMP_CODEC("wcd937x_codec", "wcd937x_cdc")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(rx_dma_rx1, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-cdc-dma-dev.45106")), + DAILINK_COMP_ARRAY(COMP_CODEC("bolero_codec", "rx_macro_rx2"), + COMP_CODEC("wsa-codec0", "wsa_rx0"), + COMP_CODEC("wsa-codec1", "wsa_rx1"), + COMP_CODEC("wcd938x_codec", "wcd938x_cdc"), + COMP_CODEC("wcd937x_codec", "wcd937x_cdc")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(rx_dma_rx2, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-cdc-dma-dev.45108")), + DAILINK_COMP_ARRAY(COMP_CODEC("bolero_codec", "rx_macro_rx3"), + COMP_CODEC("wcd938x_codec", "wcd938x_cdc"), + COMP_CODEC("wcd937x_codec", "wcd937x_cdc")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(rx_dma_rx3, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-cdc-dma-dev.45110")), + DAILINK_COMP_ARRAY(COMP_CODEC("bolero_codec", "rx_macro_rx4"), + COMP_CODEC("wcd938x_codec", "wcd938x_cdc"), + COMP_CODEC("wcd937x_codec", "wcd937x_cdc")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(tx_dma_tx3, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-cdc-dma-dev.45111")), + DAILINK_COMP_ARRAY(COMP_CODEC("bolero_codec", "tx_macro_tx1"), + COMP_CODEC("wcd938x_codec", "wcd938x_cdc"), + COMP_CODEC("wcd937x_codec", "wcd937x_cdc")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(tx_dma_tx4, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-cdc-dma-dev.45113")), + DAILINK_COMP_ARRAY(COMP_CODEC("bolero_codec", "tx_macro_tx2"), + COMP_CODEC("wcd938x_codec", "wcd938x_cdc"), + COMP_CODEC("wcd937x_codec", "wcd937x_cdc")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(va_dma_tx0, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-cdc-dma-dev.45089")), + DAILINK_COMP_ARRAY(COMP_CODEC("bolero_codec", "va_macro_tx1")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(va_dma_tx1, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-cdc-dma-dev.45091")), + DAILINK_COMP_ARRAY(COMP_CODEC("bolero_codec", "va_macro_tx2")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(va_dma_tx2, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-cdc-dma-dev.45093")), + DAILINK_COMP_ARRAY(COMP_CODEC("bolero_codec", "va_macro_tx3")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(afe_loopback_tx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-dev.24577")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(proxy_tx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-dev.8195")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); + +SND_SOC_DAILINK_DEFS(proxy_rx, + DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-dev.8194")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); diff --git a/config/holiauto.conf b/config/holiauto.conf new file mode 100644 index 0000000000..770c90b81a --- /dev/null +++ b/config/holiauto.conf @@ -0,0 +1,34 @@ +export CONFIG_PINCTRL_LPI=m +export CONFIG_AUDIO_EXT_CLK=m +export CONFIG_SND_SOC_WCD9XXX_V2=m +export CONFIG_SND_SOC_WCD_MBHC=m +export CONFIG_WCD9XXX_CODEC_CORE_V2=m +export CONFIG_MSM_CDC_PINCTRL=m +export CONFIG_MSM_QDSP6V2_CODECS=m +export CONFIG_MSM_QDSP6_APRV2_RPMSG=m +export CONFIG_MSM_ADSP_LOADER=m +export CONFIG_REGMAP_SWR=m +export CONFIG_MSM_QDSP6_SSR=m +export CONFIG_MSM_QDSP6_PDR=m +export CONFIG_MSM_QDSP6_NOTIFIER=m +export CONFIG_SND_SOC_MSM_QDSP6V2_INTF=m +export CONFIG_SOUNDWIRE=m +export CONFIG_SOUNDWIRE_MSTR_CTRL=m +export CONFIG_SND_SOC_QDSP6V2=m +export CONFIG_SND_SOC_WCD_MBHC_ADC=m +export CONFIG_QTI_PP=m +export CONFIG_SND_HWDEP_ROUTING=m +export CONFIG_SND_SOC_MSM_STUB=m +export CONFIG_SND_SOC_BOLERO=m +export CONFIG_VA_MACRO=m +export CONFIG_RX_MACRO=m +export CONFIG_TX_MACRO=m +export CONFIG_SND_SOC_WCD_IRQ=m +export CONFIG_SND_SOC_WCD938X=m +export CONFIG_SND_SOC_WCD938X_SLAVE=m +export CONFIG_SND_SOC_WCD937X=m +export CONFIG_SND_SOC_WCD937X_SLAVE=m +export CONFIG_SND_SOC_WSA881X_ANALOG=m +export CONFIG_SND_SOC_HOLI=m +export CONFIG_SND_EVENT=m +export CONFIG_DIGITAL_CDC_RSC_MGR=m diff --git a/config/holiautoconf.h b/config/holiautoconf.h new file mode 100644 index 0000000000..6bbf12e2df --- /dev/null +++ b/config/holiautoconf.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#define CONFIG_PINCTRL_LPI 1 +#define CONFIG_AUDIO_EXT_CLK 1 +#define CONFIG_SND_SOC_WCD9XXX_V2 1 +#define CONFIG_SND_SOC_WCD_MBHC 1 +#define CONFIG_WCD9XXX_CODEC_CORE_V2 1 +#define CONFIG_MSM_CDC_PINCTRL 1 +#define CONFIG_MSM_QDSP6V2_CODECS 1 +#define CONFIG_MSM_QDSP6_APRV2_RPMSG 1 +#define CONFIG_SND_SOC_MSM_QDSP6V2_INTF 1 +#define CONFIG_MSM_ADSP_LOADER 1 +#define CONFIG_REGMAP_SWR 1 +#define CONFIG_MSM_QDSP6_SSR 1 +#define CONFIG_MSM_QDSP6_PDR 1 +#define CONFIG_MSM_QDSP6_NOTIFIER 1 +#define CONFIG_SOUNDWIRE 1 +#define CONFIG_SOUNDWIRE_MSTR_CTRL 1 +#define CONFIG_SND_SOC_WCD_MBHC_ADC 1 +#define CONFIG_SND_SOC_QDSP6V2 1 +#define CONFIG_QTI_PP 1 +#define CONFIG_SND_HWDEP_ROUTING 1 +#define CONFIG_SND_SOC_MSM_STUB 1 +#define CONFIG_SND_SOC_BOLERO 1 +#define CONFIG_VA_MACRO 1 +#define CONFIG_RX_MACRO 1 +#define CONFIG_TX_MACRO 1 +#define CONFIG_SND_SOC_WCD_IRQ 1 +#define CONFIG_SND_SOC_WCD938X 1 +#define CONFIG_SND_SOC_WCD938X_SLAVE 1 +#define CONFIG_SND_SOC_WCD937X 1 +#define CONFIG_SND_SOC_WCD937X_SLAVE 1 +#define CONFIG_SND_SOC_WSA881X_ANALOG 1 +#define CONFIG_SND_SOC_HOLI 1 +#define CONFIG_SND_EVENT 1 +#define CONFIG_DIGITAL_CDC_RSC_MGR 1 diff --git a/dsp/adsp-loader.c b/dsp/adsp-loader.c index 783a93d0c9..71a6c6271c 100644 --- a/dsp/adsp-loader.c +++ b/dsp/adsp-loader.c @@ -404,7 +404,7 @@ static int adsp_loader_probe(struct platform_device *pdev) &adsp_fuse_not_supported); if (ret) { dev_dbg(&pdev->dev, - "%s: adsp_fuse_not_supported prop not found", + "%s: adsp_fuse_not_supported prop not found %d\n", __func__, ret); goto wqueue; } diff --git a/dsp/msm_audio_ion.c b/dsp/msm_audio_ion.c index ebfc3830b8..8682585316 100644 --- a/dsp/msm_audio_ion.c +++ b/dsp/msm_audio_ion.c @@ -41,6 +41,7 @@ struct msm_audio_ion_private { bool smmu_enabled; struct device *cb_dev; + struct device *cb_cma_dev; u8 device_status; struct list_head alloc_list; struct mutex list_mutex; @@ -127,7 +128,8 @@ exit: } static int msm_audio_dma_buf_map(struct dma_buf *dma_buf, - dma_addr_t *addr, size_t *len, bool is_iova) + dma_addr_t *addr, size_t *len, bool is_iova, + bool cma_mem) { struct msm_audio_alloc_data *alloc_data; @@ -136,7 +138,10 @@ static int msm_audio_dma_buf_map(struct dma_buf *dma_buf, int rc = 0; void *vaddr = NULL; - cb_dev = msm_audio_ion_data.cb_dev; + if (cma_mem) + cb_dev = msm_audio_ion_data.cb_cma_dev; + else + cb_dev = msm_audio_ion_data.cb_dev; /* Data required per buffer mapping */ alloc_data = kzalloc(sizeof(*alloc_data), GFP_KERNEL); @@ -213,14 +218,18 @@ free_alloc_data: return rc; } -static int msm_audio_dma_buf_unmap(struct dma_buf *dma_buf) +static int msm_audio_dma_buf_unmap(struct dma_buf *dma_buf, bool cma_mem) { int rc = 0; struct msm_audio_alloc_data *alloc_data = NULL; struct list_head *ptr, *next; - struct device *cb_dev = msm_audio_ion_data.cb_dev; + struct device *cb_dev; bool found = false; + if (cma_mem) + cb_dev = msm_audio_ion_data.cb_cma_dev; + else + cb_dev = msm_audio_ion_data.cb_dev; /* * Though list_for_each_safe is delete safe, lock * should be explicitly acquired to avoid race condition @@ -266,7 +275,7 @@ static int msm_audio_ion_get_phys(struct dma_buf *dma_buf, { int rc = 0; - rc = msm_audio_dma_buf_map(dma_buf, addr, len, is_iova); + rc = msm_audio_dma_buf_map(dma_buf, addr, len, is_iova, false); if (rc) { pr_err("%s: failed to map DMA buf, err = %d\n", __func__, rc); @@ -364,7 +373,7 @@ static int msm_audio_ion_map_buf(struct dma_buf *dma_buf, dma_addr_t *paddr, if (IS_ERR_OR_NULL(*vaddr)) { pr_err("%s: ION memory mapping for AUDIO failed\n", __func__); rc = -ENOMEM; - msm_audio_dma_buf_unmap(dma_buf); + msm_audio_dma_buf_unmap(dma_buf, false); goto err; } @@ -606,7 +615,7 @@ void msm_audio_get_handle(int fd, void **handle) * @bufsz: buffer size * @paddr: Physical address to be assigned with allocated region * @plen: length of allocated region to be assigned - * vaddr: virtual address to be assigned + * @vaddr: virtual address to be assigned * * Returns 0 on success or error on failure */ @@ -662,6 +671,67 @@ err: } EXPORT_SYMBOL(msm_audio_ion_import); +/** + * msm_audio_ion_import_cma- + * Import ION buffer with given file descriptor + * + * @dma_buf: dma_buf for the ION memory + * @fd: file descriptor for the ION memory + * @ionflag: flags associated with ION buffer + * @bufsz: buffer size + * @paddr: Physical address to be assigned with allocated region + * @plen: length of allocated region to be assigned + * vaddr: virtual address to be assigned + * + * Returns 0 on success or error on failure + */ +int msm_audio_ion_import_cma(struct dma_buf **dma_buf, int fd, + unsigned long *ionflag, size_t bufsz, + dma_addr_t *paddr, size_t *plen, void **vaddr) +{ + int rc = 0; + + if (!(msm_audio_ion_data.device_status & MSM_AUDIO_ION_PROBED)) { + pr_debug("%s: probe is not done, deferred\n", __func__); + return -EPROBE_DEFER; + } + + if (!dma_buf || !paddr || !vaddr || !plen || + !msm_audio_ion_data.cb_cma_dev) { + pr_err("%s: Invalid params\n", __func__); + return -EINVAL; + } + + /* bufsz should be 0 and fd shouldn't be 0 as of now */ + *dma_buf = dma_buf_get(fd); + pr_debug("%s: dma_buf =%pK, fd=%d\n", __func__, *dma_buf, fd); + if (IS_ERR_OR_NULL((void *)(*dma_buf))) { + pr_err("%s: dma_buf_get failed\n", __func__); + rc = -EINVAL; + goto err; + } + + if (ionflag != NULL) { + rc = dma_buf_get_flags(*dma_buf, ionflag); + if (rc) { + pr_err("%s: could not get flags for the dma_buf\n", + __func__); + goto err_ion_flag; + } + } + + msm_audio_dma_buf_map(*dma_buf, paddr, plen, true, true); + + return 0; + +err_ion_flag: + dma_buf_put(*dma_buf); +err: + *dma_buf = NULL; + return rc; +} +EXPORT_SYMBOL(msm_audio_ion_import_cma); + /** * msm_audio_ion_free - * fress ION memory for given client and handle @@ -683,7 +753,7 @@ int msm_audio_ion_free(struct dma_buf *dma_buf) if (ret) return ret; - msm_audio_dma_buf_unmap(dma_buf); + msm_audio_dma_buf_unmap(dma_buf, false); return 0; } @@ -717,6 +787,27 @@ void msm_audio_ion_crash_handler(void) } EXPORT_SYMBOL(msm_audio_ion_crash_handler); +/** + * msm_audio_ion_free_cma - + * fress ION memory for given client and handle + * + * @dma_buf: dma_buf for the ION memory + * + * Returns 0 on success or error on failure + */ +int msm_audio_ion_free_cma(struct dma_buf *dma_buf) +{ + if (!dma_buf) { + pr_err("%s: dma_buf invalid\n", __func__); + return -EINVAL; + } + + msm_audio_dma_buf_unmap(dma_buf, true); + + return 0; +} +EXPORT_SYMBOL(msm_audio_ion_free_cma); + /** * msm_audio_ion_mmap - * Audio ION memory map @@ -954,6 +1045,7 @@ static int msm_audio_smmu_init(struct device *dev) static const struct of_device_id msm_audio_ion_dt_match[] = { { .compatible = "qcom,msm-audio-ion" }, + { .compatible = "qcom,msm-audio-ion-cma"}, { } }; MODULE_DEVICE_TABLE(of, msm_audio_ion_dt_match); @@ -1047,6 +1139,10 @@ static int msm_audio_ion_probe(struct platform_device *pdev) msm_audio_ion_non_hyp); msm_audio_ion_data.is_non_hypervisor = is_non_hypervisor_en; + if (of_device_is_compatible(dev->of_node, "qcom,msm-audio-ion-cma")) { + msm_audio_ion_data.cb_cma_dev = dev; + return 0; + } smmu_enabled = of_property_read_bool(dev->of_node, msm_audio_ion_dt); msm_audio_ion_data.smmu_enabled = smmu_enabled; diff --git a/include/asoc/msm-cdc-supply.h b/include/asoc/msm-cdc-supply.h index c740400754..3b19387d47 100644 --- a/include/asoc/msm-cdc-supply.h +++ b/include/asoc/msm-cdc-supply.h @@ -69,5 +69,10 @@ extern int msm_cdc_init_supplies_v2(struct device *dev, int msm_cdc_init_wcd_supply(struct device_node *np, const char *name, struct cdc_wcd_supply *cdc_supply); int msm_cdc_enable_wcd_supply(struct cdc_wcd_supply *cdc_supply, bool enable); +extern int msm_cdc_set_supply_min_voltage(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies, char *supply_name, + int vval_min, bool override_min_vol); #endif diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h index 090bceb4d5..97c81d0394 100644 --- a/include/dsp/apr_audio-v2.h +++ b/include/dsp/apr_audio-v2.h @@ -5467,6 +5467,7 @@ struct afe_param_id_lpass_core_shared_clk_cfg { #define ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX 0x10015002 #define ADM_CMD_COPP_OPEN_TOPOLOGY_ID_AUDIOSPHERE 0x10028000 #define VPM_TX_DM_FLUENCE_EF_COPP_TOPOLOGY 0x10000005 +#define AUDIO_RX_MONO_VOIP_COPP_TOPOLOGY 0x11000101 /* Memory map regions command payload used by the * #ASM_CMD_SHARED_MEM_MAP_REGIONS ,#ADM_CMD_SHARED_MEM_MAP_REGIONS @@ -11717,6 +11718,10 @@ struct avcs_fwk_ver_info { #define LSM_SESSION_CMD_SET_PARAMS (0x00012A83) #define LSM_SESSION_CMD_SET_PARAMS_V2 (0x00012A8F) #define LSM_SESSION_CMD_SET_PARAMS_V3 (0x00012A92) +#define LSM_SESSION_CMD_GET_PARAMS_V2 (0x00012A90) +#define LSM_SESSION_CMDRSP_GET_PARAMS_V2 (0x00012A91) +#define LSM_SESSION_CMD_GET_PARAMS_V3 (0x00012A93) +#define LSM_SESSION_CMDRSP_GET_PARAMS_V3 (0x00012A94) #define LSM_SESSION_CMD_REGISTER_SOUND_MODEL (0x00012A84) #define LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL (0x00012A85) #define LSM_SESSION_CMD_START (0x00012A86) diff --git a/include/dsp/audio_cal_utils.h b/include/dsp/audio_cal_utils.h index 71981d11c8..0ef02ef7e8 100644 --- a/include/dsp/audio_cal_utils.h +++ b/include/dsp/audio_cal_utils.h @@ -30,6 +30,7 @@ struct cal_block_data { struct list_head list; struct cal_data cal_data; bool cal_stale; + bool cma_mem; struct mem_map_data map_data; int32_t buffer_number; }; diff --git a/include/dsp/msm_audio_ion.h b/include/dsp/msm_audio_ion.h index f07fb96fbc..a61316ab9b 100644 --- a/include/dsp/msm_audio_ion.h +++ b/include/dsp/msm_audio_ion.h @@ -34,6 +34,10 @@ int msm_audio_ion_import(struct dma_buf **dma_buf, int fd, unsigned long *ionflag, size_t bufsz, dma_addr_t *paddr, size_t *pa_len, void **vaddr); int msm_audio_ion_free(struct dma_buf *dma_buf); +int msm_audio_ion_import_cma(struct dma_buf **dma_buf, int fd, + unsigned long *ionflag, size_t bufsz, + dma_addr_t *paddr, size_t *pa_len, void **vaddr); +int msm_audio_ion_free_cma(struct dma_buf *dma_buf); int msm_audio_ion_mmap(struct audio_buffer *abuff, struct vm_area_struct *vma); int msm_audio_ion_cache_operations(struct audio_buffer *abuff, int cache_op); diff --git a/include/uapi/audio/linux/msm_audio_calibration.h b/include/uapi/audio/linux/msm_audio_calibration.h index 686603f5a5..d5093c8d5c 100644 --- a/include/uapi/audio/linux/msm_audio_calibration.h +++ b/include/uapi/audio/linux/msm_audio_calibration.h @@ -126,6 +126,7 @@ enum { #define TOPOLOGY_SPECIFIC_CHANNEL_INFO #define MSM_SPKR_PROT_SPV3 #define MSM_SPKR_PROT_SPV4 +#define MSM_CMA_MEM_ALLOC enum { VERSION_0_0, @@ -156,7 +157,10 @@ struct audio_cal_data { __s32 cal_size; /* If mem_handle if shared memory is used*/ __s32 mem_handle; - /* size of virtual memory if shared memory not used */ +#ifdef MSM_CMA_MEM_ALLOC + /* cma allocation flag if cma heap memory is used */ + __u32 cma_mem; +#endif }; diff --git a/include/uapi/audio/sound/audio_compressed_formats.h b/include/uapi/audio/sound/audio_compressed_formats.h new file mode 100644 index 0000000000..29c4a1ce65 --- /dev/null +++ b/include/uapi/audio/sound/audio_compressed_formats.h @@ -0,0 +1,90 @@ +#ifndef __AUDIO_COMPRESSED_FORMATS_H +#define __AUDIO_COMPRESSED_FORMATS_H + +#include + +#define AUDIO_COMP_FORMAT_ALAC 0x1 +#define AUDIO_COMP_FORMAT_APE 0x2 +#define AUDIO_COMP_FORMAT_APTX 0x3 +#define AUDIO_COMP_FORMAT_DSD 0x4 +#define AUDIO_COMP_FORMAT_FLAC 0x5 +#define AUDIO_COMP_FORMAT_VORBIS 0x6 +#define AUDIO_COMP_FORMAT_WMA 0x7 +#define AUDIO_COMP_FORMAT_WMA_PRO 0x8 + +#define SND_COMPRESS_DEC_HDR +struct snd_generic_dec_aac { + __u16 audio_obj_type; + __u16 pce_bits_size; +} __attribute__((packed, aligned(4))); + +struct snd_generic_dec_flac { + __u16 sample_size; + __u16 min_blk_size; + __u16 max_blk_size; + __u16 min_frame_size; + __u16 max_frame_size; +} __attribute__((packed, aligned(4))); + +struct snd_generic_dec_alac { + __u32 frame_length; + __u8 compatible_version; + __u8 bit_depth; + __u8 pb; + __u8 mb; + __u8 kb; + __u8 num_channels; + __u16 max_run; + __u32 max_frame_bytes; + __u32 avg_bit_rate; + __u32 sample_rate; + __u32 channel_layout_tag; +} __attribute__((packed, aligned(4))); + +struct snd_generic_dec_ape { + __u16 compatible_version; + __u16 compression_level; + __u32 format_flags; + __u32 blocks_per_frame; + __u32 final_frame_blocks; + __u32 total_frames; + __u16 bits_per_sample; + __u16 num_channels; + __u32 sample_rate; + __u32 seek_table_present; +} __attribute__((packed, aligned(4))); + +struct snd_generic_dec_wma { + __u32 super_block_align; + __u32 bits_per_sample; + __u32 channelmask; + __u32 encodeopt; + __u32 encodeopt1; + __u32 encodeopt2; + __u32 avg_bit_rate; +} __attribute__((packed, aligned(4))); + +#define SND_DEC_WMA_EXTENTED_SUPPORT + +struct snd_generic_dec_aptx { + __u32 lap; + __u32 uap; + __u32 nap; +} __attribute__((packed, aligned(4))); + +struct snd_generic_dec_vorbis { + __u32 bit_stream_fmt; +} __attribute__((packed, aligned(4))); + +/** struct snd_generic_dec_dsd - codec for DSD format + * @blk_size - dsd channel block size + */ +struct snd_generic_dec_dsd { + __u32 blk_size; +} __attribute__((packed, aligned(4))); + +struct snd_generic_dec_amrwb_plus { + __u32 bit_stream_fmt; +} __attribute__((packed, aligned(4))); + +#endif diff --git a/include/uapi/audio/sound/lsm_params.h b/include/uapi/audio/sound/lsm_params.h index 722d3ba726..c5945e19e8 100644 --- a/include/uapi/audio/sound/lsm_params.h +++ b/include/uapi/audio/sound/lsm_params.h @@ -36,7 +36,8 @@ #define LSM_REG_MULTI_SND_MODEL (10) #define LSM_DEREG_MULTI_SND_MODEL (11) #define LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS (12) -#define LSM_PARAMS_MAX (LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS + 1) +#define LSM_GET_CUSTOM_PARAMS (13) +#define LSM_PARAMS_MAX (LSM_GET_CUSTOM_PARAMS + 1) #define LSM_EVENT_NON_TIME_STAMP_MODE (0) #define LSM_EVENT_TIME_STAMP_MODE (1) @@ -288,6 +289,29 @@ struct snd_lsm_input_hw_params { __u16 num_channels; } __packed; +/* + * Param get info for each parameter type + * add "for SNDRV_LSM_GET_MODULE_PARAMS ioctl" + * Existing member variables: + * @module_id: Module to which parameter is to be set + * @instance_id: instance id of the param to which parameter is to be set + * @param_id: Parameter that is to be set + * @param_size: size of requested param + * @param_type: Parameter type as defined in values upto LSM_PARAMS_MAX + * @stage_idx: detection stage for which the param is applicable + * @payload: memory where requested param info will be populated + */ +struct lsm_params_get_info { + __u32 module_id; + __u16 instance_id; + __u16 reserved; + __u32 param_id; + __u32 param_size; + __u32 param_type; + __u16 stage_idx; + __u8 payload[0]; +} __packed; + #define SNDRV_LSM_DEREG_SND_MODEL _IOW('U', 0x01, int) #define SNDRV_LSM_EVENT_STATUS _IOW('U', 0x02, struct snd_lsm_event_status) #define SNDRV_LSM_ABORT_EVENT _IOW('U', 0x03, int) @@ -315,5 +339,6 @@ struct snd_lsm_input_hw_params { struct snd_lsm_session_data_v2) #define SNDRV_LSM_SET_MODULE_PARAMS_V2 _IOW('U', 0x13, \ struct snd_lsm_module_params) - +#define SNDRV_LSM_GET_MODULE_PARAMS _IOWR('U', 0x14, \ + struct lsm_params_get_info) #endif diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c index 3089a0d711..e18ff73a9a 100644 --- a/soc/swr-mstr-ctrl.c +++ b/soc/swr-mstr-ctrl.c @@ -26,6 +26,7 @@ #include "swr-slave-registers.h" #include #include "swr-mstr-ctrl.h" +#include "swr-slave-port-config.h" #define SWR_NUM_PORTS 4 /* TODO - Get this info from DT */ @@ -80,6 +81,8 @@ #define SWRM_DP_PORT_CTRL_OFFSET2_SHFT 0x10 #define SWRM_DP_PORT_CTRL_OFFSET1_SHFT 0x08 +#define SWR_OVERFLOW_RETRY_COUNT 30 + /* pm runtime auto suspend timer in msecs */ static int auto_suspend_timer = 500; module_param(auto_suspend_timer, int, 0664); @@ -108,6 +111,11 @@ enum { LPASS_AUDIO_CORE, }; +enum { + SWRM_WR_CHECK_AVAIL, + SWRM_RD_CHECK_AVAIL, +}; + #define TRUE 1 #define FALSE 0 @@ -122,6 +130,32 @@ static u32 swr_master_read(struct swr_mstr_ctrl *swrm, unsigned int reg_addr); static void swr_master_write(struct swr_mstr_ctrl *swrm, u16 reg_addr, u32 val); static int swrm_runtime_resume(struct device *dev); +static u64 swrm_phy_dev[] = { + 0, + 0xd01170223, + 0x858350223, + 0x858350222, + 0x858350221, + 0x858350220, +}; + +static u8 swrm_get_device_id(struct swr_mstr_ctrl *swrm, u8 devnum) +{ + int i; + + for (i = 1; i < (swrm->num_dev + 1); i++) { + if (swrm->logical_dev[devnum] == swrm_phy_dev[i]) + break; + } + + if (i == (swrm->num_dev + 1)) { + pr_info("%s: could not find the slave\n", __func__); + i = devnum; + } + + return i; +} + static u8 swrm_get_clk_div(int mclk_freq, int bus_clk_freq) { int clk_div = 0; @@ -719,6 +753,9 @@ static int swrm_get_port_config(struct swr_mstr_ctrl *swrm) (swrm->master_id == MASTER_ID_RX)) usecase = 1; + if (swrm->bus_clk == SWR_CLK_RATE_4P8MHZ) + usecase = 1; + params = swrm->port_param[usecase]; copy_port_tables(swrm, params); @@ -790,6 +827,54 @@ static u32 swrm_get_packed_reg_val(u8 *cmd_id, u8 cmd_data, return val; } +static void swrm_wait_for_fifo_avail(struct swr_mstr_ctrl *swrm, int swrm_rd_wr) +{ + u32 fifo_outstanding_cmd; + u32 fifo_retry_count = SWR_OVERFLOW_RETRY_COUNT; + + if (swrm_rd_wr) { + /* Check for fifo underflow during read */ + /* Check no of outstanding commands in fifo before read */ + fifo_outstanding_cmd = ((swr_master_read(swrm, + SWRM_CMD_FIFO_STATUS) & 0x001F0000) >> 16); + if (fifo_outstanding_cmd == 0) { + while (fifo_retry_count) { + usleep_range(500, 510); + fifo_outstanding_cmd = + ((swr_master_read (swrm, + SWRM_CMD_FIFO_STATUS) & 0x001F0000) + >> 16); + fifo_retry_count--; + if (fifo_outstanding_cmd > 0) + break; + } + } + if (fifo_outstanding_cmd == 0) + dev_err_ratelimited(swrm->dev, + "%s err read underflow\n", __func__); + } else { + /* Check for fifo overflow during write */ + /* Check no of outstanding commands in fifo before write */ + fifo_outstanding_cmd = ((swr_master_read(swrm, + SWRM_CMD_FIFO_STATUS) & 0x00001F00) + >> 8); + if (fifo_outstanding_cmd == swrm->wr_fifo_depth) { + while (fifo_retry_count) { + usleep_range(500, 510); + fifo_outstanding_cmd = + ((swr_master_read(swrm, SWRM_CMD_FIFO_STATUS) + & 0x00001F00) >> 8); + fifo_retry_count--; + if (fifo_outstanding_cmd < swrm->wr_fifo_depth) + break; + } + } + if (fifo_outstanding_cmd == swrm->wr_fifo_depth) + dev_err_ratelimited(swrm->dev, + "%s err write overflow\n", __func__); + } +} + static int swrm_cmd_fifo_rd_cmd(struct swr_mstr_ctrl *swrm, int *cmd_data, u8 dev_addr, u8 cmd_id, u16 reg_addr, u32 len) @@ -803,12 +888,19 @@ static int swrm_cmd_fifo_rd_cmd(struct swr_mstr_ctrl *swrm, int *cmd_data, /* skip delay if read is handled in platform driver */ swr_master_write(swrm, SWRM_CMD_FIFO_RD_CMD, val); } else { + /* + * Check for outstanding cmd wrt. write fifo depth to avoid + * overflow as read will also increase write fifo cnt. + */ + swrm_wait_for_fifo_avail(swrm, SWRM_WR_CHECK_AVAIL); /* wait for FIFO RD to complete to avoid overflow */ usleep_range(100, 105); swr_master_write(swrm, SWRM_CMD_FIFO_RD_CMD, val); /* wait for FIFO RD CMD complete to avoid overflow */ usleep_range(250, 255); } + /* Check if slave responds properly after FIFO RD is complete */ + swrm_wait_for_fifo_avail(swrm, SWRM_RD_CHECK_AVAIL); retry_read: *cmd_data = swr_master_read(swrm, SWRM_CMD_FIFO_RD_FIFO); dev_dbg(swrm->dev, "%s: reg: 0x%x, cmd_id: 0x%x, rcmd_id: 0x%x, \ @@ -855,6 +947,11 @@ static int swrm_cmd_fifo_wr_cmd(struct swr_mstr_ctrl *swrm, u8 cmd_data, dev_dbg(swrm->dev, "%s: reg: 0x%x, cmd_id: 0x%x,wcmd_id: 0x%x, \ dev_num: 0x%x, cmd_data: 0x%x\n", __func__, reg_addr, cmd_id, swrm->wcmd_id,dev_addr, cmd_data); + /* + * Check for outstanding cmd wrt. write fifo depth to avoid + * overflow. + */ + swrm_wait_for_fifo_avail(swrm, SWRM_WR_CHECK_AVAIL); swr_master_write(swrm, SWRM_CMD_FIFO_WR_CMD, val); /* * wait for FIFO WR command to complete to avoid overflow @@ -1102,9 +1199,9 @@ int swrm_get_clk_div_rate(int mclk_freq, int bus_clk_freq) if (bus_clk_freq <= SWR_CLK_RATE_0P6MHZ) bus_clk_freq = SWR_CLK_RATE_0P6MHZ; else if (bus_clk_freq <= SWR_CLK_RATE_1P2MHZ) - bus_clk_freq = SWR_CLK_RATE_1P2MHZ; + bus_clk_freq = SWR_CLK_RATE_4P8MHZ; else if (bus_clk_freq <= SWR_CLK_RATE_2P4MHZ) - bus_clk_freq = SWR_CLK_RATE_2P4MHZ; + bus_clk_freq = SWR_CLK_RATE_4P8MHZ; else if(bus_clk_freq <= SWR_CLK_RATE_4P8MHZ) bus_clk_freq = SWR_CLK_RATE_4P8MHZ; else if(bus_clk_freq <= SWR_CLK_RATE_9P6MHZ) @@ -1235,26 +1332,91 @@ static void swrm_cleanup_disabled_port_reqs(struct swr_master *master) } } } + +static u8 swrm_get_controller_offset1(struct swr_mstr_ctrl *swrm, + u8* dev_offset, u8 off1) +{ + u8 offset1 = 0x0F; + int i = 0; + + if (swrm->master_id == MASTER_ID_TX) { + for (i = 1; i < SWRM_NUM_AUTO_ENUM_SLAVES; i++) { + pr_debug("%s: dev offset: %d\n", + __func__, dev_offset[i]); + if (offset1 > dev_offset[i]) + offset1 = dev_offset[i]; + } + } else { + offset1 = off1; + } + + pr_debug("%s: offset: %d\n", __func__, offset1); + + return offset1; +} + +static void swrm_get_device_frame_shape(struct swr_mstr_ctrl *swrm, + struct swrm_mports *mport, + struct swr_port_info *port_req) +{ + u32 port_id = 0; + u8 dev_num = 0; + struct port_params *pp_dev; + struct port_params *pp_port; + + if ((swrm->master_id == MASTER_ID_TX) && + ((swrm->bus_clk == SWR_CLK_RATE_9P6MHZ) || + (swrm->bus_clk == SWR_CLK_RATE_4P8MHZ))) { + dev_num = swrm_get_device_id(swrm, port_req->dev_num); + port_id = port_req->slave_port_id; + if (swrm->bus_clk == SWR_CLK_RATE_9P6MHZ) + pp_dev = swrdev_frame_params_9p6MHz[dev_num].pp; + else + pp_dev = swrdev_frame_params_4p8MHz[dev_num].pp; + pp_port = &pp_dev[port_id]; + port_req->sinterval = pp_port->si; + port_req->offset1 = pp_port->off1; + port_req->offset2 = pp_port->off2; + port_req->hstart = pp_port->hstart; + port_req->hstop = pp_port->hstop; + port_req->word_length = pp_port->wd_len; + port_req->blk_pack_mode = pp_port->bp_mode; + port_req->blk_grp_count = pp_port->bgp_ctrl; + port_req->lane_ctrl = pp_port->lane_ctrl; + } else { + /* copy master port config to slave */ + port_req->sinterval = mport->sinterval; + port_req->offset1 = mport->offset1; + port_req->offset2 = mport->offset2; + port_req->hstart = mport->hstart; + port_req->hstop = mport->hstop; + port_req->word_length = mport->word_length; + port_req->blk_pack_mode = mport->blk_pack_mode; + port_req->blk_grp_count = mport->blk_grp_count; + port_req->lane_ctrl = mport->lane_ctrl; + } +} + static void swrm_copy_data_port_config(struct swr_master *master, u8 bank) { - u32 value, slv_id; + u32 value = 0, slv_id = 0; struct swr_port_info *port_req; int i; struct swrm_mports *mport; - struct swrm_mports *prev_mport = NULL; u32 reg[SWRM_MAX_PORT_REG]; u32 val[SWRM_MAX_PORT_REG]; int len = 0; - u8 hparams; - u8 offset1 = 0; - + u8 hparams = 0; + u32 controller_offset = 0; struct swr_mstr_ctrl *swrm = swr_get_ctrl_data(master); + u8 dev_offset[SWRM_NUM_AUTO_ENUM_SLAVES]; if (!swrm) { pr_err("%s: swrm is null\n", __func__); return; } + memset(dev_offset, 0xff, SWRM_NUM_AUTO_ENUM_SLAVES); dev_dbg(swrm->dev, "%s: master num_port: %d\n", __func__, master->num_port); @@ -1268,6 +1430,12 @@ static void swrm_copy_data_port_config(struct swr_master *master, u8 bank) list_for_each_entry(port_req, &mport->port_req_list, list) { slv_id = port_req->slave_port_id; + /* Assumption: If different channels in the same port + * on master is enabled for different slaves, then each + * slave offset should be configured differently. + */ + swrm_get_device_frame_shape(swrm, mport, port_req); + reg[len] = SWRM_CMD_FIFO_WR_CMD; val[len++] = SWR_REG_VAL_PACK(port_req->req_ch, port_req->dev_num, 0x00, @@ -1275,36 +1443,36 @@ static void swrm_copy_data_port_config(struct swr_master *master, u8 bank) bank)); reg[len] = SWRM_CMD_FIFO_WR_CMD; - val[len++] = SWR_REG_VAL_PACK(mport->sinterval, + val[len++] = SWR_REG_VAL_PACK( + port_req->sinterval & 0xFF, port_req->dev_num, 0x00, SWRS_DP_SAMPLE_CONTROL_1_BANK(slv_id, bank)); - /* Assumption: If different channels in the same port - * on master is enabled for different slaves, then each - * slave offset should be configured differently. - */ - if (prev_mport == mport) - offset1 += mport->offset1; - else { - offset1 = mport->offset1; - prev_mport = mport; - } + reg[len] = SWRM_CMD_FIFO_WR_CMD; - val[len++] = SWR_REG_VAL_PACK(offset1, + val[len++] = SWR_REG_VAL_PACK( + (port_req->sinterval >> 8)& 0xFF, + port_req->dev_num, 0x00, + SWRS_DP_SAMPLE_CONTROL_2_BANK(slv_id, + bank)); + + reg[len] = SWRM_CMD_FIFO_WR_CMD; + val[len++] = SWR_REG_VAL_PACK(port_req->offset1, port_req->dev_num, 0x00, SWRS_DP_OFFSET_CONTROL_1_BANK(slv_id, bank)); - if (mport->offset2 != SWR_INVALID_PARAM) { + if (port_req->offset2 != SWR_INVALID_PARAM) { reg[len] = SWRM_CMD_FIFO_WR_CMD; - val[len++] = SWR_REG_VAL_PACK(mport->offset2, + val[len++] = SWR_REG_VAL_PACK(port_req->offset2, port_req->dev_num, 0x00, SWRS_DP_OFFSET_CONTROL_2_BANK( slv_id, bank)); } - if (mport->hstart != SWR_INVALID_PARAM - && mport->hstop != SWR_INVALID_PARAM) { - hparams = (mport->hstart << 4) | mport->hstop; + if (port_req->hstart != SWR_INVALID_PARAM + && port_req->hstop != SWR_INVALID_PARAM) { + hparams = (port_req->hstart << 4) | + port_req->hstop; reg[len] = SWRM_CMD_FIFO_WR_CMD; val[len++] = SWR_REG_VAL_PACK(hparams, @@ -1312,39 +1480,42 @@ static void swrm_copy_data_port_config(struct swr_master *master, u8 bank) SWRS_DP_HCONTROL_BANK(slv_id, bank)); } - if (mport->word_length != SWR_INVALID_PARAM) { + if (port_req->word_length != SWR_INVALID_PARAM) { reg[len] = SWRM_CMD_FIFO_WR_CMD; val[len++] = - SWR_REG_VAL_PACK(mport->word_length, + SWR_REG_VAL_PACK(port_req->word_length, port_req->dev_num, 0x00, SWRS_DP_BLOCK_CONTROL_1(slv_id)); } - if (mport->blk_pack_mode != SWR_INVALID_PARAM + if (port_req->blk_pack_mode != SWR_INVALID_PARAM && swrm->master_id != MASTER_ID_WSA) { reg[len] = SWRM_CMD_FIFO_WR_CMD; val[len++] = - SWR_REG_VAL_PACK(mport->blk_pack_mode, + SWR_REG_VAL_PACK( + port_req->blk_pack_mode, port_req->dev_num, 0x00, SWRS_DP_BLOCK_CONTROL_3_BANK(slv_id, bank)); } - if (mport->blk_grp_count != SWR_INVALID_PARAM) { + if (port_req->blk_grp_count != SWR_INVALID_PARAM) { reg[len] = SWRM_CMD_FIFO_WR_CMD; val[len++] = - SWR_REG_VAL_PACK(mport->blk_grp_count, + SWR_REG_VAL_PACK( + port_req->blk_grp_count, port_req->dev_num, 0x00, - SWRS_DP_BLOCK_CONTROL_2_BANK(slv_id, - bank)); + SWRS_DP_BLOCK_CONTROL_2_BANK( + slv_id, bank)); } - if (mport->lane_ctrl != SWR_INVALID_PARAM) { + if (port_req->lane_ctrl != SWR_INVALID_PARAM) { reg[len] = SWRM_CMD_FIFO_WR_CMD; val[len++] = - SWR_REG_VAL_PACK(mport->lane_ctrl, + SWR_REG_VAL_PACK(port_req->lane_ctrl, port_req->dev_num, 0x00, - SWRS_DP_LANE_CONTROL_BANK(slv_id, - bank)); + SWRS_DP_LANE_CONTROL_BANK( + slv_id, bank)); } port_req->ch_en = port_req->req_ch; + dev_offset[port_req->dev_num] = port_req->offset1; } value = ((mport->req_ch) << SWRM_DP_PORT_CTRL_EN_CHAN_SHFT); @@ -1352,15 +1523,16 @@ static void swrm_copy_data_port_config(struct swr_master *master, u8 bank) if (mport->offset2 != SWR_INVALID_PARAM) value |= ((mport->offset2) << SWRM_DP_PORT_CTRL_OFFSET2_SHFT); - value |= ((mport->offset1) - << SWRM_DP_PORT_CTRL_OFFSET1_SHFT); + controller_offset = (swrm_get_controller_offset1(swrm, + dev_offset, mport->offset1)); + value |= (controller_offset << SWRM_DP_PORT_CTRL_OFFSET1_SHFT); + mport->offset1 = controller_offset; value |= (mport->sinterval & 0xFF); - reg[len] = SWRM_DP_PORT_CTRL_BANK((i + 1), bank); val[len++] = value; dev_dbg(swrm->dev, "%s: mport :%d, reg: 0x%x, val: 0x%x\n", - __func__, i, + __func__, (i + 1), (SWRM_DP_PORT_CTRL_BANK((i + 1), bank)), value); reg[len] = SWRM_DP_SAMPLECTRL2_BANK((i + 1), bank); @@ -1746,6 +1918,7 @@ static void swrm_enable_slave_irq(struct swr_mstr_ctrl *swrm) { int i; int status = 0; + u32 temp; status = swr_master_read(swrm, SWRM_MCP_SLV_STATUS); if (!status) { @@ -1756,6 +1929,8 @@ static void swrm_enable_slave_irq(struct swr_mstr_ctrl *swrm) dev_dbg(swrm->dev, "%s: slave status: 0x%x\n", __func__, status); for (i = 0; i < (swrm->master.num_dev + 1); i++) { if (status & SWRM_MCP_SLV_STATUS_MASK) { + swrm_cmd_fifo_rd_cmd(swrm, &temp, i, 0x0, + SWRS_SCP_INT_STATUS_CLEAR_1, 1); swrm_cmd_fifo_wr_cmd(swrm, 0xFF, i, 0x0, SWRS_SCP_INT_STATUS_CLEAR_1); swrm_cmd_fifo_wr_cmd(swrm, 0x4, i, 0x0, @@ -1894,10 +2069,7 @@ handle_irq: * as hw will mask host_irq at slave * but will not unmask it afterwards. */ - swrm_cmd_fifo_wr_cmd(swrm, 0xFF, devnum, 0x0, - SWRS_SCP_INT_STATUS_CLEAR_1); - swrm_cmd_fifo_wr_cmd(swrm, 0x4, devnum, 0x0, - SWRS_SCP_INT_STATUS_MASK_1); + swrm->enable_slave_irq = true; } break; case SWR_ATTACHED_OK: @@ -1905,11 +2077,7 @@ handle_irq: "%s: device %d got attached\n", __func__, devnum); /* enable host irq from slave device*/ - swrm_cmd_fifo_wr_cmd(swrm, 0xFF, devnum, 0x0, - SWRS_SCP_INT_STATUS_CLEAR_1); - swrm_cmd_fifo_wr_cmd(swrm, 0x4, devnum, 0x0, - SWRS_SCP_INT_STATUS_MASK_1); - + swrm->enable_slave_irq = true; break; case SWR_ALERT: dev_dbg(swrm->dev, @@ -1931,19 +2099,19 @@ handle_irq: case SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW: value = swr_master_read(swrm, SWRM_CMD_FIFO_STATUS); dev_err(swrm->dev, - "%s: SWR read FIFO overflow fifo status\n", + "%s: SWR read FIFO overflow fifo status %x\n", __func__, value); break; case SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOW: value = swr_master_read(swrm, SWRM_CMD_FIFO_STATUS); dev_err(swrm->dev, - "%s: SWR read FIFO underflow fifo status\n", + "%s: SWR read FIFO underflow fifo status %x\n", __func__, value); break; case SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW: value = swr_master_read(swrm, SWRM_CMD_FIFO_STATUS); dev_err(swrm->dev, - "%s: SWR write FIFO overflow fifo status\n", + "%s: SWR write FIFO overflow fifo status %x\n", __func__, value); swr_master_write(swrm, SWRM_CMD_FIFO_CMD, 0x1); break; @@ -2023,6 +2191,12 @@ handle_irq: swr_master_write(swrm, SWRM_INTERRUPT_CLEAR, intr_sts); swr_master_write(swrm, SWRM_INTERRUPT_CLEAR, 0x0); + if (swrm->enable_slave_irq) { + /* Enable slave irq here */ + swrm_enable_slave_irq(swrm); + swrm->enable_slave_irq = false; + } + intr_sts = swr_master_read(swrm, SWRM_INTERRUPT_STATUS); intr_sts_masked = intr_sts & swrm->intr_mask; @@ -2058,7 +2232,7 @@ static irqreturn_t swrm_wakeup_interrupt(int irq, void *dev) trace_printk("%s enter\n", __func__); mutex_lock(&swrm->devlock); - if (!swrm->dev_up) { + if (swrm->state == SWR_MSTR_SSR || !swrm->dev_up) { if (swrm->wake_irq > 0) { if (unlikely(!irq_get_irq_data(swrm->wake_irq))) { pr_err("%s: irq data is NULL\n", __func__); @@ -2191,6 +2365,7 @@ static int swrm_get_logical_dev_num(struct swr_master *mstr, u64 dev_id, "%s: devnum %d assigned for dev %llx\n", __func__, i, swr_dev->addr); + swrm->logical_dev[i] = swr_dev->addr; } } } @@ -2694,6 +2869,11 @@ static int swrm_probe(struct platform_device *pdev) if (pdev->dev.of_node) of_register_swr_devices(&swrm->master); + swrm->rd_fifo_depth = ((swr_master_read(swrm, SWRM_COMP_PARAMS) + & SWRM_COMP_PARAMS_RD_FIFO_DEPTH) >> 15); + swrm->wr_fifo_depth = ((swr_master_read(swrm, SWRM_COMP_PARAMS) + & SWRM_COMP_PARAMS_WR_FIFO_DEPTH) >> 10); + #ifdef CONFIG_DEBUG_FS swrm->debugfs_swrm_dent = debugfs_create_dir(dev_name(&pdev->dev), 0); if (!IS_ERR(swrm->debugfs_swrm_dent)) { @@ -2737,9 +2917,10 @@ err_mstr_fail: swrm->reg_irq(swrm->handle, swr_mstr_interrupt, swrm, SWR_IRQ_FREE); } else if (swrm->irq) { - irqd_set_trigger_type( - irq_get_irq_data(swrm->irq), - IRQ_TYPE_NONE); + if (irq_get_irq_data(swrm->irq) != NULL) + irqd_set_trigger_type( + irq_get_irq_data(swrm->irq), + IRQ_TYPE_NONE); if (swrm->swr_irq_wakeup_capable) irq_set_irq_wake(swrm->irq, 0); free_irq(swrm->irq, swrm); @@ -2767,9 +2948,10 @@ static int swrm_remove(struct platform_device *pdev) swrm->reg_irq(swrm->handle, swr_mstr_interrupt, swrm, SWR_IRQ_FREE); } else if (swrm->irq) { - irqd_set_trigger_type( - irq_get_irq_data(swrm->irq), - IRQ_TYPE_NONE); + if (irq_get_irq_data(swrm->irq) != NULL) + irqd_set_trigger_type( + irq_get_irq_data(swrm->irq), + IRQ_TYPE_NONE); if (swrm->swr_irq_wakeup_capable) irq_set_irq_wake(swrm->irq, 0); free_irq(swrm->irq, swrm); diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h index 89d35b5423..8aa0d013bb 100644 --- a/soc/swr-mstr-ctrl.h +++ b/soc/swr-mstr-ctrl.h @@ -190,6 +190,10 @@ struct swr_mstr_ctrl { int aud_core_clk_en; int clk_src; u32 disable_div2_clk_switch; + u32 rd_fifo_depth; + u32 wr_fifo_depth; + bool enable_slave_irq; + u64 logical_dev[SWRM_NUM_AUTO_ENUM_SLAVES]; #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_swrm_dent; struct dentry *debugfs_peek; diff --git a/soc/swr-mstr-registers.h b/soc/swr-mstr-registers.h index 90cff792e2..9cb0e5f638 100644 --- a/soc/swr-mstr-registers.h +++ b/soc/swr-mstr-registers.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015, 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2015, 2018-2020 The Linux Foundation. All rights reserved. */ #ifndef _SWRM_REGISTERS_H @@ -108,4 +108,7 @@ #define SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP 0x10000 #define SWRM_INTERRUPT_MAX 0x11 + +#define SWRM_COMP_PARAMS_WR_FIFO_DEPTH 0x00007C00 +#define SWRM_COMP_PARAMS_RD_FIFO_DEPTH 0x000F8000 #endif /* _SWRM_REGISTERS_H */ diff --git a/soc/swr-slave-port-config.h b/soc/swr-slave-port-config.h new file mode 100644 index 0000000000..1c86386e17 --- /dev/null +++ b/soc/swr-slave-port-config.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _SWR_SLAVE_PORT_CONFIG +#define _SWR_SLAVE_PORT_CONFIG + +#include + +#define WSA_MSTR_PORT_MASK 0xFF +/* + * Add port configuration in the format + *{ si, off1, off2, hstart, hstop, wd_len, bp_mode, bgp_ctrl, lane_ctrl, dir, + * stream_type} + */ + +/* DUMMY */ +static struct port_params tx_dummy[SWR_MSTR_PORT_LEN] = { + {0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX1 */ + {0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX2 */ + {0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX3 */ +}; + +/* AMIC 9.6 MHz clock */ +static struct port_params tx_wcd_9p6MHz[SWR_MSTR_PORT_LEN] = { + {3, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0x00, 0x00}, /* TX1 */ + {7, 5, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX2 */ + {7, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX3 */ + {7, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX4 */ +}; + +/* AMIC 4.8 MHz clock */ +static struct port_params tx_wcd_4p8MHz[SWR_MSTR_PORT_LEN] = { + {3, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0x00, 0x00}, /* TX1 */ + {3, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX2 */ + {7, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX3 */ + {3, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX4 */ +}; + +/* 4 Channel configuration */ +/* SWR DMIC0 */ +static struct port_params tx_bottom_mic_9p6MHz[SWR_MSTR_PORT_LEN] = { + {7, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX1 */ + {7, 6, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX2 */ +}; + +/* SWR DMIC1 */ +static struct port_params tx_receiver_mic_9p6MHz[SWR_MSTR_PORT_LEN] = { + {7, 4, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX1 */ + {7, 7, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX2 */ +}; + +/* SWR DMIC2 */ +static struct port_params tx_back_mic_9p6MHz[SWR_MSTR_PORT_LEN] = { + {7, 3, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX1 */ + {7, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX2 */ +}; + +/* SWR DMIC3 */ +static struct port_params tx_top_mic_9p6MHz[SWR_MSTR_PORT_LEN] = { + {7, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX1 */ + {7, 5, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX2 */ +}; + +/* 3 Channel configuration */ +/* SWR DMIC0 */ +static struct port_params tx_bottom_mic_4p8MHz[SWR_MSTR_PORT_LEN] = { + {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX1 */ + {3, 3, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX2 */ +}; + +/* SWR DMIC1 */ +static struct port_params tx_receiver_mic_4p8MHz[SWR_MSTR_PORT_LEN] = { + {3, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX1 */ + {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX2 */ +}; + +/* SWR DMIC2 */ +static struct port_params tx_back_mic_4p8MHz[SWR_MSTR_PORT_LEN] = { + {3, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX1 */ + {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX2 */ +}; + +/* SWR DMIC3 */ +static struct port_params tx_top_mic_4p8MHz[SWR_MSTR_PORT_LEN] = { + {3, 3, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX1 */ + {3, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX2 */ +}; + +struct swr_dev_frame_config { + struct port_params *pp; +}; + +static struct swr_dev_frame_config swrdev_frame_params_9p6MHz[] = { + {tx_dummy}, + {tx_wcd_9p6MHz}, + {tx_top_mic_9p6MHz}, + {tx_back_mic_9p6MHz}, + {tx_receiver_mic_9p6MHz}, + {tx_bottom_mic_9p6MHz}, +}; + +static struct swr_dev_frame_config swrdev_frame_params_4p8MHz[] = { + {tx_dummy}, + {tx_wcd_4p8MHz}, + {tx_top_mic_4p8MHz}, + {tx_back_mic_4p8MHz}, + {tx_receiver_mic_4p8MHz}, + {tx_bottom_mic_4p8MHz}, +}; + +#endif /* _LAHAINA_PORT_CONFIG */ diff --git a/soc/swrm_registers.h b/soc/swrm_registers.h index fcfabb2ce4..ee9a12e6a8 100644 --- a/soc/swrm_registers.h +++ b/soc/swrm_registers.h @@ -232,6 +232,8 @@ SWRS_DP_REG_OFFSET(n, m)) #define SWRS_DP_SAMPLE_CONTROL_1_BANK(n, m) (SWRS_BASE_ADDRESS + 0x122 + \ SWRS_DP_REG_OFFSET(n, m)) +#define SWRS_DP_SAMPLE_CONTROL_2_BANK(n, m) (SWRS_BASE_ADDRESS + 0x123 + \ + SWRS_DP_REG_OFFSET(n, m)) #define SWRS_DP_OFFSET_CONTROL_1_BANK(n, m) (SWRS_BASE_ADDRESS + 0x124 + \ SWRS_DP_REG_OFFSET(n, m)) #define SWRS_DP_OFFSET_CONTROL_2_BANK(n, m) (SWRS_BASE_ADDRESS + 0x125 + \