Kaynağa Gözat

asoc: codecs: update max sampling rate of wsa881x analog driver

Updated the wsa dailink to support 384Khz HS playback.

Picked latest codec fixes to kernel6.0.

Change-Id: Ia570dc3f3ed55415ac374e1ba3bb6f2277dade96
Signed-off-by: Sairam Peri<[email protected]>
Sairam Peri 1 yıl önce
ebeveyn
işleme
6e38fad118

+ 51 - 9
asoc/codecs/bolero/bolero-cdc.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/of_platform.h>
@@ -21,6 +21,7 @@
 #include "internal.h"
 #include "bolero-clk-rsc.h"
 #include "asoc/bolero-slave-internal.h"
+#include <linux/qti-regmap-debugfs.h>
 
 #define DRV_NAME "bolero_codec"
 
@@ -236,8 +237,9 @@ static int bolero_cdc_update_wcd_event(void *handle, u16 event, u32 data)
 				BOLERO_MACRO_EVT_BCS_CLK_OFF, data);
 		break;
 	case SLV_BOLERO_EVT_RX_PA_GAIN_UPDATE:
-		/* Update PA Gain only for bolero version 2.1 */
-		if (priv->version == BOLERO_VERSION_2_1)
+		/* Update PA Gain for bolero version 2.1 and 2.2*/
+		if ((priv->version == BOLERO_VERSION_2_1) ||
+		    (priv->version == BOLERO_VERSION_2_2))
 			if (priv->macro_params[RX_MACRO].event_handler)
 				priv->macro_params[RX_MACRO].event_handler(
 					priv->component,
@@ -698,7 +700,8 @@ int bolero_register_macro(struct device *dev, u16 macro_id,
 	if (macro_id == TX_MACRO || macro_id == VA_MACRO)
 		priv->macro_params[macro_id].clk_div_get = ops->clk_div_get;
 
-	if (priv->version == BOLERO_VERSION_2_1) {
+	if ((priv->version == BOLERO_VERSION_2_1) ||
+	    (priv->version == BOLERO_VERSION_2_2)) {
 		if (macro_id == VA_MACRO)
 			priv->macro_params[macro_id].reg_wake_irq =
 						ops->reg_wake_irq;
@@ -781,6 +784,34 @@ void bolero_unregister_macro(struct device *dev, u16 macro_id)
 }
 EXPORT_SYMBOL(bolero_unregister_macro);
 
+/**
+ * bolero_rx_pa_on - Send PA on event from RX macro to slave.
+ *
+ * @dev: macro device ptr.
+ */
+void bolero_rx_pa_on(struct device *dev)
+{
+	struct bolero_priv *priv;
+
+	if (!dev) {
+		pr_err("%s: dev is null\n", __func__);
+		return;
+	}
+	if (!bolero_is_valid_child_dev(dev)) {
+		dev_err(dev, "%s: not a valid child dev\n",
+			__func__);
+		return;
+	}
+	priv = dev_get_drvdata(dev->parent);
+	if (!priv) {
+		dev_err(dev, "%s: priv is null\n", __func__);
+		return;
+	}
+
+	bolero_cdc_notifier_call(priv, BOLERO_SLV_EVT_RX_MACRO_PA_ON);
+}
+EXPORT_SYMBOL_GPL(bolero_rx_pa_on);
+
 void bolero_wsa_pa_on(struct device *dev, bool adie_lb)
 {
 	struct bolero_priv *priv;
@@ -1055,7 +1086,8 @@ int bolero_register_wake_irq(struct snd_soc_component *component,
 		return -EINVAL;
 	}
 
-	if (priv->version == BOLERO_VERSION_2_1) {
+	if ((priv->version == BOLERO_VERSION_2_1) ||
+	    (priv->version == BOLERO_VERSION_2_2)) {
 		if (priv->macro_params[VA_MACRO].reg_wake_irq)
 			priv->macro_params[VA_MACRO].reg_wake_irq(
 					component, ipc_wakeup);
@@ -1176,7 +1208,7 @@ static int bolero_soc_codec_probe(struct snd_soc_component *component)
 {
 	struct bolero_priv *priv = dev_get_drvdata(component->dev);
 	int macro_idx, ret = 0;
-	u8 core_id_0 = 0, core_id_1 = 0;
+	u8 core_id_0 = 0, core_id_1 = 0, core_id_2 = 0;
 
 	snd_soc_component_init_regmap(component, priv->regmap);
 
@@ -1201,10 +1233,16 @@ static int bolero_soc_codec_probe(struct snd_soc_component *component)
 					BOLERO_CDC_VA_TOP_CSR_CORE_ID_0);
 	core_id_1 = snd_soc_component_read(component,
 					BOLERO_CDC_VA_TOP_CSR_CORE_ID_1);
+	core_id_2 = snd_soc_component_read(component,
+					BOLERO_CDC_VA_TOP_CSR_CORE_ID_2);
 	if ((core_id_0 == 0x01) && (core_id_1 == 0x0F))
 		priv->version = BOLERO_VERSION_2_0;
-	if ((core_id_0 == 0x02) && (core_id_1 == 0x0E))
-		priv->version = BOLERO_VERSION_2_1;
+	if ((core_id_0 == 0x02) && (core_id_1 == 0x0E)) {
+		if (core_id_2 == 0x20)
+			priv->version = BOLERO_VERSION_2_2;
+		else
+			priv->version = BOLERO_VERSION_2_1;
+	}
 
 	/* call init for supported macros */
 	for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) {
@@ -1368,7 +1406,8 @@ static int bolero_probe(struct platform_device *pdev)
 			__func__);
 		ret = 0;
 	}
-	if (priv->version == BOLERO_VERSION_2_1) {
+	if ((priv->version == BOLERO_VERSION_2_1) ||
+	    (priv->version == BOLERO_VERSION_2_2)) {
 		bolero_reg_access[TX_MACRO] = bolero_tx_reg_access_v2;
 		bolero_reg_access[VA_MACRO] = bolero_va_reg_access_v2;
 	} else if (priv->version == BOLERO_VERSION_2_0) {
@@ -1385,6 +1424,9 @@ static int bolero_probe(struct platform_device *pdev)
 		dev_err(&pdev->dev, "%s:regmap init failed\n", __func__);
 		return -EINVAL;
 	}
+
+	devm_regmap_qti_debugfs_register(priv->dev, priv->regmap);
+
 	priv->read_dev = __bolero_reg_read;
 	priv->write_dev = __bolero_reg_write;
 

+ 9 - 0
asoc/codecs/bolero/bolero-cdc.h

@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef BOLERO_CDC_H
@@ -13,6 +14,7 @@
 #define BOLERO_VERSION_1_2 0x0003
 #define BOLERO_VERSION_2_0 0x0004
 #define BOLERO_VERSION_2_1 0x0005
+#define BOLERO_VERSION_2_2 0x0006
 
 enum {
 	START_MACRO,
@@ -115,6 +117,7 @@ int bolero_tx_mclk_enable(struct snd_soc_component *c, bool enable);
 int bolero_get_version(struct device *dev);
 int bolero_dmic_clk_enable(struct snd_soc_component *component,
 			   u32 dmic, u32 tx_mode, bool enable);
+void bolero_rx_pa_on(struct device *dev);
 #else
 static inline int bolero_register_res_clk(struct device *dev, rsc_clk_cb_t cb)
 {
@@ -215,5 +218,11 @@ static int bolero_tx_mclk_enable(struct snd_soc_component *c, bool enable)
 {
 	return 0;
 }
+
+static inline void bolero_rx_pa_on(struct device *dev)
+{
+	return 0;
+}
+
 #endif /* CONFIG_SND_SOC_BOLERO */
 #endif /* BOLERO_CDC_H */

+ 16 - 2
asoc/codecs/bolero/rx-macro.c

@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/module.h>
@@ -462,6 +463,7 @@ struct rx_macro_priv {
 	u16 default_clk_id;
 	int8_t rx0_gain_val;
 	int8_t rx1_gain_val;
+	u32 rx_macro_wsa_slv;
 };
 
 static struct snd_soc_dai_driver rx_macro_dai[];
@@ -1249,7 +1251,11 @@ static int rx_macro_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
 			}
 		}
 	}
-		break;
+
+	if (rx_priv->rx_macro_wsa_slv)
+		bolero_rx_pa_on(rx_dev);
+	break;
+
 	default:
 		break;
 	}
@@ -4112,7 +4118,7 @@ static int rx_macro_probe(struct platform_device *pdev)
 	struct rx_macro_priv *rx_priv = NULL;
 	u32 rx_base_addr = 0, muxsel = 0;
 	char __iomem *rx_io_base = NULL, *muxsel_io = NULL;
-	int ret = 0;
+	int ret = 0, val = 0;
 	u8 bcl_pmic_params[3];
 	u32 default_clk_id = 0;
 	u32 is_used_rx_swr_gpio = 1;
@@ -4144,6 +4150,14 @@ static int rx_macro_probe(struct platform_device *pdev)
 			__func__, "reg");
 		return ret;
 	}
+
+	ret = of_property_read_u32(pdev->dev.of_node, "qcom,rx-wsa-enable", &val);
+	if (ret == 0) {
+		rx_priv->rx_macro_wsa_slv = (val == 1) ? 1 : 0;
+		dev_info(&pdev->dev, "RX macro wsa slave is %s\n",
+			(val == 1) ? "connected" : "not connected");
+	}
+
 	ret = of_property_read_u32(pdev->dev.of_node, "qcom,default-clk-id",
 				   &default_clk_id);
 	if (ret) {

+ 235 - 15
asoc/codecs/bolero/tx-macro.c

@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/module.h>
@@ -690,6 +691,92 @@ static int tx_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
 	return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
 }
 
+static int tx_macro_put_dec_enum_v2(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget =
+		snd_soc_dapm_kcontrol_widget(kcontrol);
+	struct snd_soc_component *component =
+				snd_soc_dapm_to_component(widget->dapm);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int val = 0;
+	u16 mic_sel_reg = 0;
+	struct device *tx_dev = NULL;
+	struct tx_macro_priv *tx_priv = NULL;
+
+	if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__))
+		return -EINVAL;
+
+	val = ucontrol->value.enumerated.item[0];
+	if (val > e->items - 1)
+		return -EINVAL;
+
+	dev_dbg(component->dev, "%s: wname: %s, val: 0x%x\n", __func__,
+		widget->name, val);
+
+	switch (e->reg) {
+	case BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0:
+		mic_sel_reg = BOLERO_CDC_TX0_TX_PATH_CFG0;
+		break;
+	case BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG0:
+		mic_sel_reg = BOLERO_CDC_TX1_TX_PATH_CFG0;
+		break;
+	case BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG0:
+		mic_sel_reg = BOLERO_CDC_TX2_TX_PATH_CFG0;
+		break;
+	case BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG0:
+		mic_sel_reg = BOLERO_CDC_TX3_TX_PATH_CFG0;
+		break;
+	default:
+		dev_err(component->dev, "%s: e->reg: 0x%x not expected\n",
+			__func__, e->reg);
+		return -EINVAL;
+	}
+
+	if (strnstr(widget->name, "SMIC", strlen(widget->name))) {
+		if (val != 0) {
+			snd_soc_component_update_bits(component,
+					mic_sel_reg,
+					1 << 7, 0x0 << 7);
+		}
+	} else {
+		/* DMIC selected */
+		if (val != 0)
+			snd_soc_component_update_bits(component, mic_sel_reg,
+							1 << 7, 1 << 7);
+	}
+
+	return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+}
+
+static int tx_macro_put_pcm_in_enum(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget =
+		snd_soc_dapm_kcontrol_widget(kcontrol);
+	struct snd_soc_component *component =
+				snd_soc_dapm_to_component(widget->dapm);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int val = 0;
+	struct device *tx_dev = NULL;
+	struct tx_macro_priv *tx_priv = NULL;
+
+	if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__))
+		return -EINVAL;
+
+	val = ucontrol->value.enumerated.item[0];
+	if (val > e->items - 1)
+		return -EINVAL;
+
+	dev_dbg(component->dev, "%s: wname: %s\n", __func__, widget->name);
+
+	snd_soc_component_update_bits(component,
+					BOLERO_CDC_TX_TOP_CSR_I2S_CLK,
+					0x1, val);
+
+	return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+}
+
 static int tx_macro_tx_mixer_get(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
@@ -947,7 +1034,8 @@ static int tx_macro_get_bcs_ch_sel(struct snd_kcontrol *kcontrol,
 	if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__))
 		return -EINVAL;
 
-	if (tx_priv->version == BOLERO_VERSION_2_1)
+	if ((tx_priv->version == BOLERO_VERSION_2_1) ||
+	    (tx_priv->version == BOLERO_VERSION_2_2))
 		value = (snd_soc_component_read(component,
 			BOLERO_CDC_VA_TOP_CSR_SWR_CTRL)) & 0x0F;
 	else if (tx_priv->version == BOLERO_VERSION_2_0)
@@ -975,7 +1063,8 @@ static int tx_macro_put_bcs_ch_sel(struct snd_kcontrol *kcontrol,
 		return -EINVAL;
 
 	value = ucontrol->value.integer.value[0];
-	if (tx_priv->version == BOLERO_VERSION_2_1)
+	if ((tx_priv->version == BOLERO_VERSION_2_1) ||
+	    (tx_priv->version == BOLERO_VERSION_2_2))
 		snd_soc_component_update_bits(component,
 			BOLERO_CDC_VA_TOP_CSR_SWR_CTRL, 0x0F, value);
 	else if (tx_priv->version == BOLERO_VERSION_2_0)
@@ -1128,7 +1217,8 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
 			      snd_soc_component_read(component,
 					tx_gain_ctl_reg));
 		if (tx_priv->bcs_enable) {
-			if (tx_priv->version == BOLERO_VERSION_2_1)
+			if ((tx_priv->version == BOLERO_VERSION_2_1) ||
+			    (tx_priv->version == BOLERO_VERSION_2_2))
 				snd_soc_component_update_bits(component,
 					BOLERO_CDC_VA_TOP_CSR_SWR_CTRL, 0x0F,
 					tx_priv->bcs_ch);
@@ -1219,6 +1309,10 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
 						0x20, 0x00);
 		snd_soc_component_update_bits(component,
 			dec_cfg_reg, 0x06, 0x00);
+		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
+			0x40, 0x40);
+		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
+			0x40, 0x00);
 		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
 						0x10, 0x00);
 		if (tx_priv->bcs_enable) {
@@ -1227,7 +1321,8 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
 			snd_soc_component_update_bits(component,
 				BOLERO_CDC_TX0_TX_PATH_SEC7, 0x40, 0x00);
 			tx_priv->bcs_clk_en = false;
-			if (tx_priv->version == BOLERO_VERSION_2_1)
+			if ((tx_priv->version == BOLERO_VERSION_2_1) ||
+			    (tx_priv->version == BOLERO_VERSION_2_2))
 				snd_soc_component_update_bits(component,
 					BOLERO_CDC_VA_TOP_CSR_SWR_CTRL, 0x0F,
 					0x00);
@@ -1559,6 +1654,38 @@ TX_MACRO_DAPM_ENUM_EXT(tx_smic7_v3, BOLERO_CDC_TX_INP_MUX_ADC_MUX7_CFG0,
 			0, smic_mux_text_v2, snd_soc_dapm_get_enum_double,
 			tx_macro_put_dec_enum);
 
+TX_MACRO_DAPM_ENUM_EXT(tx_smic0_v4, BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0,
+			0, smic_mux_text_v2, snd_soc_dapm_get_enum_double,
+			tx_macro_put_dec_enum_v2);
+
+TX_MACRO_DAPM_ENUM_EXT(tx_smic1_v4, BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG0,
+			0, smic_mux_text_v2, snd_soc_dapm_get_enum_double,
+			tx_macro_put_dec_enum_v2);
+
+TX_MACRO_DAPM_ENUM_EXT(tx_smic2_v4, BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG0,
+			0, smic_mux_text_v2, snd_soc_dapm_get_enum_double,
+			tx_macro_put_dec_enum_v2);
+
+TX_MACRO_DAPM_ENUM_EXT(tx_smic3_v4, BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG0,
+			0, smic_mux_text_v2, snd_soc_dapm_get_enum_double,
+			tx_macro_put_dec_enum_v2);
+
+static const char * const pcm_in0_mux_text[] = {
+	"SWR_MIC", "RX_SWR_TX_PCM_IN0",
+};
+
+static const char * const pcm_in1_mux_text[] = {
+	"SWR_MIC", "RX_SWR_TX_PCM_IN1",
+};
+
+TX_MACRO_DAPM_ENUM_EXT(rx_swr_tx_pcm_in0, SND_SOC_NOPM,
+			0, pcm_in0_mux_text, snd_soc_dapm_get_enum_double,
+			tx_macro_put_pcm_in_enum);
+
+TX_MACRO_DAPM_ENUM_EXT(rx_swr_tx_pcm_in1, SND_SOC_NOPM,
+			0, pcm_in1_mux_text, snd_soc_dapm_get_enum_double,
+			tx_macro_put_pcm_in_enum);
+
 static const char * const dec_mode_mux_text[] = {
 	"ADC_DEFAULT", "ADC_LOW_PWR", "ADC_HIGH_PERF",
 };
@@ -1681,11 +1808,6 @@ static const struct snd_soc_dapm_widget tx_macro_dapm_widgets_common[] = {
 	TX_MACRO_DAPM_MUX("TX DMIC MUX2", 0, tx_dmic2),
 	TX_MACRO_DAPM_MUX("TX DMIC MUX3", 0, tx_dmic3),
 
-	TX_MACRO_DAPM_MUX("TX SMIC MUX0", 0, tx_smic0_v2),
-	TX_MACRO_DAPM_MUX("TX SMIC MUX1", 0, tx_smic1_v2),
-	TX_MACRO_DAPM_MUX("TX SMIC MUX2", 0, tx_smic2_v2),
-	TX_MACRO_DAPM_MUX("TX SMIC MUX3", 0, tx_smic3_v2),
-
 	SND_SOC_DAPM_SUPPLY("TX MIC BIAS1", SND_SOC_NOPM, 0, 0,
 		tx_macro_enable_micbias,
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
@@ -1768,6 +1890,12 @@ static const struct snd_soc_dapm_widget tx_macro_dapm_widgets_v2[] = {
 	SND_SOC_DAPM_MIXER("TX_AIF3_CAP Mixer", SND_SOC_NOPM,
 		TX_MACRO_AIF3_CAP, 0,
 		tx_aif3_cap_mixer_v2, ARRAY_SIZE(tx_aif3_cap_mixer_v2)),
+
+	TX_MACRO_DAPM_MUX("TX SMIC MUX0", 0, tx_smic0_v2),
+	TX_MACRO_DAPM_MUX("TX SMIC MUX1", 0, tx_smic1_v2),
+	TX_MACRO_DAPM_MUX("TX SMIC MUX2", 0, tx_smic2_v2),
+	TX_MACRO_DAPM_MUX("TX SMIC MUX3", 0, tx_smic3_v2),
+
 };
 
 static const struct snd_soc_dapm_widget tx_macro_dapm_widgets_v3[] = {
@@ -1788,6 +1916,10 @@ static const struct snd_soc_dapm_widget tx_macro_dapm_widgets_v3[] = {
 	TX_MACRO_DAPM_MUX("TX DMIC MUX6", 0, tx_dmic6),
 	TX_MACRO_DAPM_MUX("TX DMIC MUX7", 0, tx_dmic7),
 
+	TX_MACRO_DAPM_MUX("TX SMIC MUX0", 0, tx_smic0_v2),
+	TX_MACRO_DAPM_MUX("TX SMIC MUX1", 0, tx_smic1_v2),
+	TX_MACRO_DAPM_MUX("TX SMIC MUX2", 0, tx_smic2_v2),
+	TX_MACRO_DAPM_MUX("TX SMIC MUX3", 0, tx_smic3_v2),
 	TX_MACRO_DAPM_MUX("TX SMIC MUX4", 0, tx_smic4_v3),
 	TX_MACRO_DAPM_MUX("TX SMIC MUX5", 0, tx_smic5_v3),
 	TX_MACRO_DAPM_MUX("TX SMIC MUX6", 0, tx_smic6_v3),
@@ -1826,6 +1958,31 @@ static const struct snd_soc_dapm_widget tx_macro_dapm_widgets_v3[] = {
 			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 };
 
+static const struct snd_soc_dapm_widget tx_macro_dapm_widgets_v4[] = {
+	SND_SOC_DAPM_MIXER("TX_AIF1_CAP Mixer", SND_SOC_NOPM,
+		TX_MACRO_AIF1_CAP, 0,
+		tx_aif1_cap_mixer_v2, ARRAY_SIZE(tx_aif1_cap_mixer_v2)),
+
+	SND_SOC_DAPM_MIXER("TX_AIF2_CAP Mixer", SND_SOC_NOPM,
+		TX_MACRO_AIF2_CAP, 0,
+		tx_aif2_cap_mixer_v2, ARRAY_SIZE(tx_aif2_cap_mixer_v2)),
+
+	SND_SOC_DAPM_MIXER("TX_AIF3_CAP Mixer", SND_SOC_NOPM,
+		TX_MACRO_AIF3_CAP, 0,
+		tx_aif3_cap_mixer_v2, ARRAY_SIZE(tx_aif3_cap_mixer_v2)),
+
+	TX_MACRO_DAPM_MUX("TX SMIC MUX0", 0, tx_smic0_v4),
+	TX_MACRO_DAPM_MUX("TX SMIC MUX1", 0, tx_smic1_v4),
+	TX_MACRO_DAPM_MUX("TX SMIC MUX2", 0, tx_smic2_v4),
+	TX_MACRO_DAPM_MUX("TX SMIC MUX3", 0, tx_smic3_v4),
+
+	TX_MACRO_DAPM_MUX("RX SWR TX MUX0", 0, rx_swr_tx_pcm_in0),
+	TX_MACRO_DAPM_MUX("RX SWR TX MUX1", 0, rx_swr_tx_pcm_in1),
+
+	SND_SOC_DAPM_INPUT("RX_SWR_TX_PCM_IN0"),
+	SND_SOC_DAPM_INPUT("RX_SWR_TX_PCM_IN1"),
+};
+
 static const struct snd_soc_dapm_widget tx_macro_dapm_widgets[] = {
 	SND_SOC_DAPM_AIF_OUT("TX_AIF1 CAP", "TX_AIF1 Capture", 0,
 		SND_SOC_NOPM, TX_MACRO_AIF1_CAP, 0),
@@ -2022,8 +2179,6 @@ static const struct snd_soc_dapm_route tx_audio_map_common[] = {
 	{"TX SMIC MUX0", "SWR_MIC7", "TX SWR_INPUT"},
 	{"TX SMIC MUX0", "SWR_MIC8", "TX SWR_INPUT"},
 	{"TX SMIC MUX0", "SWR_MIC9", "TX SWR_INPUT"},
-	{"TX SMIC MUX0", "SWR_MIC10", "TX SWR_INPUT"},
-	{"TX SMIC MUX0", "SWR_MIC11", "TX SWR_INPUT"},
 
 	{"TX DEC1 MUX", "MSM_DMIC", "TX DMIC MUX1"},
 	{"TX DMIC MUX1", "DMIC0", "TX DMIC0"},
@@ -2046,8 +2201,6 @@ static const struct snd_soc_dapm_route tx_audio_map_common[] = {
 	{"TX SMIC MUX1", "SWR_MIC7", "TX SWR_INPUT"},
 	{"TX SMIC MUX1", "SWR_MIC8", "TX SWR_INPUT"},
 	{"TX SMIC MUX1", "SWR_MIC9", "TX SWR_INPUT"},
-	{"TX SMIC MUX1", "SWR_MIC10", "TX SWR_INPUT"},
-	{"TX SMIC MUX1", "SWR_MIC11", "TX SWR_INPUT"},
 
 	{"TX DEC2 MUX", "MSM_DMIC", "TX DMIC MUX2"},
 	{"TX DMIC MUX2", "DMIC0", "TX DMIC0"},
@@ -2070,8 +2223,6 @@ static const struct snd_soc_dapm_route tx_audio_map_common[] = {
 	{"TX SMIC MUX2", "SWR_MIC7", "TX SWR_INPUT"},
 	{"TX SMIC MUX2", "SWR_MIC8", "TX SWR_INPUT"},
 	{"TX SMIC MUX2", "SWR_MIC9", "TX SWR_INPUT"},
-	{"TX SMIC MUX2", "SWR_MIC10", "TX SWR_INPUT"},
-	{"TX SMIC MUX2", "SWR_MIC11", "TX SWR_INPUT"},
 
 	{"TX DEC3 MUX", "MSM_DMIC", "TX DMIC MUX3"},
 	{"TX DMIC MUX3", "DMIC0", "TX DMIC0"},
@@ -2094,11 +2245,35 @@ static const struct snd_soc_dapm_route tx_audio_map_common[] = {
 	{"TX SMIC MUX3", "SWR_MIC7", "TX SWR_INPUT"},
 	{"TX SMIC MUX3", "SWR_MIC8", "TX SWR_INPUT"},
 	{"TX SMIC MUX3", "SWR_MIC9", "TX SWR_INPUT"},
+};
+
+static const struct snd_soc_dapm_route tx_audio_map_v2[] = {
+	{"TX SMIC MUX0", "SWR_MIC10", "TX SWR_INPUT"},
+	{"TX SMIC MUX0", "SWR_MIC11", "TX SWR_INPUT"},
+
+	{"TX SMIC MUX1", "SWR_MIC10", "TX SWR_INPUT"},
+	{"TX SMIC MUX1", "SWR_MIC11", "TX SWR_INPUT"},
+
+	{"TX SMIC MUX2", "SWR_MIC10", "TX SWR_INPUT"},
+	{"TX SMIC MUX2", "SWR_MIC11", "TX SWR_INPUT"},
+
 	{"TX SMIC MUX3", "SWR_MIC10", "TX SWR_INPUT"},
 	{"TX SMIC MUX3", "SWR_MIC11", "TX SWR_INPUT"},
 };
 
 static const struct snd_soc_dapm_route tx_audio_map_v3[] = {
+	{"TX SMIC MUX0", "SWR_MIC10", "TX SWR_INPUT"},
+	{"TX SMIC MUX0", "SWR_MIC11", "TX SWR_INPUT"},
+
+	{"TX SMIC MUX1", "SWR_MIC10", "TX SWR_INPUT"},
+	{"TX SMIC MUX1", "SWR_MIC11", "TX SWR_INPUT"},
+
+	{"TX SMIC MUX2", "SWR_MIC10", "TX SWR_INPUT"},
+	{"TX SMIC MUX2", "SWR_MIC11", "TX SWR_INPUT"},
+
+	{"TX SMIC MUX3", "SWR_MIC10", "TX SWR_INPUT"},
+	{"TX SMIC MUX3", "SWR_MIC11", "TX SWR_INPUT"},
+
 	{"TX_AIF1_CAP Mixer", "DEC4", "TX DEC4 MUX"},
 	{"TX_AIF1_CAP Mixer", "DEC5", "TX DEC5 MUX"},
 	{"TX_AIF1_CAP Mixer", "DEC6", "TX DEC6 MUX"},
@@ -2238,6 +2413,39 @@ static const struct snd_soc_dapm_route tx_audio_map_v3[] = {
 	{"TX SWR_INPUT", NULL, "TX_SWR_PWR"},
 };
 
+static const struct snd_soc_dapm_route tx_audio_map_v4[] = {
+	{"TX SMIC MUX0", "SWR_MIC10", "RX SWR TX MUX0"},
+	{"RX SWR TX MUX0", "SWR_MIC", "TX SWR_INPUT"},
+	{"RX SWR TX MUX0", "RX_SWR_TX_PCM_IN0", "RX_SWR_TX_PCM_IN0"},
+	{"TX SMIC MUX0", "SWR_MIC11", "RX SWR TX MUX1"},
+	{"RX SWR TX MUX1", "SWR_MIC", "TX SWR_INPUT"},
+	{"RX SWR TX MUX1", "RX_SWR_TX_PCM_IN1", "RX_SWR_TX_PCM_IN1"},
+
+	{"TX SMIC MUX1", "SWR_MIC10", "RX SWR TX MUX0"},
+	{"RX SWR TX MUX0", "SWR_MIC", "TX SWR_INPUT"},
+	{"RX SWR TX MUX0", "RX_SWR_TX_PCM_IN0", "RX_SWR_TX_PCM_IN0"},
+	{"TX SMIC MUX1", "SWR_MIC11", "RX SWR TX MUX1"},
+	{"RX SWR TX MUX1", "SWR_MIC", "TX SWR_INPUT"},
+	{"RX SWR TX MUX1", "RX_SWR_TX_PCM_IN1", "RX_SWR_TX_PCM_IN1"},
+
+	{"TX SMIC MUX2", "SWR_MIC10", "RX SWR TX MUX0"},
+	{"RX SWR TX MUX0", "SWR_MIC", "TX SWR_INPUT"},
+	{"RX SWR TX MUX0", "RX_SWR_TX_PCM_IN0", "RX_SWR_TX_PCM_IN0"},
+	{"TX SMIC MUX2", "SWR_MIC11", "RX SWR TX MUX1"},
+	{"RX SWR TX MUX1", "SWR_MIC", "TX SWR_INPUT"},
+	{"RX SWR TX MUX1", "RX_SWR_TX_PCM_IN1", "RX_SWR_TX_PCM_IN1"},
+
+	{"TX SMIC MUX3", "SWR_MIC10", "RX SWR TX MUX0"},
+	{"RX SWR TX MUX0", "SWR_MIC", "TX SWR_INPUT"},
+	{"RX SWR TX MUX0", "RX_SWR_TX_PCM_IN0", "RX_SWR_TX_PCM_IN0"},
+	{"TX SMIC MUX3", "SWR_MIC11", "RX SWR TX MUX1"},
+	{"RX SWR TX MUX1", "SWR_MIC", "TX SWR_INPUT"},
+	{"RX SWR TX MUX1", "RX_SWR_TX_PCM_IN1", "RX_SWR_TX_PCM_IN1"},
+
+	{"RX SWR TX MUX0", NULL, "TX_MCLK"},
+	{"RX SWR TX MUX1", NULL, "TX_MCLK"},
+};
+
 static const struct snd_soc_dapm_route tx_audio_map[] = {
 	{"TX_AIF1 CAP", NULL, "TX_MCLK"},
 	{"TX_AIF2 CAP", NULL, "TX_MCLK"},
@@ -3125,6 +3333,10 @@ static int tx_macro_init(struct snd_soc_component *component)
 			ret = snd_soc_dapm_new_controls(dapm,
 				tx_macro_dapm_widgets_v3,
 				ARRAY_SIZE(tx_macro_dapm_widgets_v3));
+		else if (tx_priv->version == BOLERO_VERSION_2_2)
+			ret = snd_soc_dapm_new_controls(dapm,
+				tx_macro_dapm_widgets_v4,
+				ARRAY_SIZE(tx_macro_dapm_widgets_v4));
 		if (ret < 0) {
 			dev_err(tx_dev, "%s: Failed to add controls\n",
 				__func__);
@@ -3149,10 +3361,18 @@ static int tx_macro_init(struct snd_soc_component *component)
 				__func__);
 			return ret;
 		}
+		if (tx_priv->version == BOLERO_VERSION_2_1)
+			ret = snd_soc_dapm_add_routes(dapm,
+					tx_audio_map_v2,
+					ARRAY_SIZE(tx_audio_map_v2));
 		if (tx_priv->version == BOLERO_VERSION_2_0)
 			ret = snd_soc_dapm_add_routes(dapm,
 					tx_audio_map_v3,
 					ARRAY_SIZE(tx_audio_map_v3));
+		if (tx_priv->version == BOLERO_VERSION_2_2)
+			ret = snd_soc_dapm_add_routes(dapm,
+					tx_audio_map_v4,
+					ARRAY_SIZE(tx_audio_map_v4));
 		if (ret < 0) {
 			dev_err(tx_dev, "%s: Failed to add routes\n",
 				__func__);

+ 27 - 15
asoc/codecs/bolero/va-macro.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/module.h>
@@ -180,6 +180,7 @@ struct va_macro_priv {
 	int dec_mode[VA_MACRO_NUM_DECIMATORS];
 	u16 current_clk_id;
 	int pcm_rate[VA_MACRO_NUM_DECIMATORS];
+	bool dev_up;
 };
 
 static bool va_macro_get_data(struct snd_soc_component *component,
@@ -325,6 +326,7 @@ static int va_macro_event_handler(struct snd_soc_component *component,
 		trace_printk("%s, enter SSR up\n", __func__);
 		/* reset swr after ssr/pdr */
 		va_priv->reset_swr = true;
+		va_priv->dev_up = true;
 		if (va_priv->swr_ctrl_data)
 			swrm_wcd_notify(
 				va_priv->swr_ctrl_data[0].va_swr_pdev,
@@ -334,6 +336,7 @@ static int va_macro_event_handler(struct snd_soc_component *component,
 		bolero_rsc_clk_reset(va_dev, VA_CORE_CLK);
 		break;
 	case BOLERO_MACRO_EVT_SSR_DOWN:
+		va_priv->dev_up = false;
 		if (va_priv->swr_ctrl_data) {
 			swrm_wcd_notify(
 				va_priv->swr_ctrl_data[0].va_swr_pdev,
@@ -437,31 +440,31 @@ static int va_macro_swr_pwr_event_v2(struct snd_soc_dapm_widget *w,
 		}
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		if (va_priv->current_clk_id == VA_CORE_CLK &&
-			va_priv->va_swr_clk_cnt != 0 &&
-			va_priv->tx_clk_status) {
+		if (va_priv->current_clk_id == VA_CORE_CLK) {
 			ret = bolero_clk_rsc_request_clock(va_priv->dev,
 					va_priv->default_clk_id,
 					TX_CORE_CLK,
 					true);
 			if (ret) {
-				dev_dbg(component->dev,
-					"%s: request clock TX_CLK disable failed\n",
+				dev_err(component->dev,
+					"%s: request clock TX_CLK enable failed\n",
 					__func__);
-				break;
+				if (va_priv->dev_up)
+					break;
 			}
 			ret = bolero_clk_rsc_request_clock(va_priv->dev,
 					va_priv->default_clk_id,
 					VA_CORE_CLK,
 					false);
 			if (ret) {
-				dev_dbg(component->dev,
+				dev_err(component->dev,
 					"%s: request clock VA_CLK disable failed\n",
 					__func__);
-				bolero_clk_rsc_request_clock(va_priv->dev,
-					TX_CORE_CLK,
-					TX_CORE_CLK,
-					false);
+				if (va_priv->dev_up)
+					bolero_clk_rsc_request_clock(va_priv->dev,
+						TX_CORE_CLK,
+						TX_CORE_CLK,
+						false);
 				break;
 			}
 			va_priv->current_clk_id = TX_CORE_CLK;
@@ -1338,6 +1341,10 @@ static int va_macro_enable_dec(struct snd_soc_dapm_widget *w,
 		/* Disable TX CLK */
 		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
 					0x20, 0x00);
+		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
+			0x40, 0x40);
+		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
+			0x40, 0x00);
 		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
 					0x10, 0x00);
 		break;
@@ -2750,7 +2757,8 @@ static int va_macro_init(struct snd_soc_component *component)
 				__func__);
 			return ret;
 		}
-		if (va_priv->version == BOLERO_VERSION_2_1)
+		if ((va_priv->version == BOLERO_VERSION_2_1) ||
+		    (va_priv->version == BOLERO_VERSION_2_2))
 			ret = snd_soc_dapm_new_controls(dapm,
 				va_macro_dapm_widgets_v2,
 				ARRAY_SIZE(va_macro_dapm_widgets_v2));
@@ -2792,7 +2800,8 @@ static int va_macro_init(struct snd_soc_component *component)
 				return ret;
 			}
 		}
-		if (va_priv->version == BOLERO_VERSION_2_1) {
+		if ((va_priv->version == BOLERO_VERSION_2_1) ||
+		    (va_priv->version == BOLERO_VERSION_2_2)) {
 			ret = snd_soc_dapm_add_routes(dapm,
 					va_audio_map_v2,
 					ARRAY_SIZE(va_audio_map_v2));
@@ -2867,6 +2876,8 @@ static int va_macro_init(struct snd_soc_component *component)
 	}
 	snd_soc_dapm_sync(dapm);
 
+	va_priv->dev_up = true;
+
 	for (i = 0; i < VA_MACRO_NUM_DECIMATORS; i++) {
 		va_priv->va_hpf_work[i].va_priv = va_priv;
 		va_priv->va_hpf_work[i].decimator = i;
@@ -2882,7 +2893,8 @@ static int va_macro_init(struct snd_soc_component *component)
 	}
 	va_priv->component = component;
 
-	if (va_priv->version == BOLERO_VERSION_2_1) {
+	if ((va_priv->version == BOLERO_VERSION_2_1) ||
+	    (va_priv->version == BOLERO_VERSION_2_2)) {
 		snd_soc_component_update_bits(component,
 			BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL0, 0xEE, 0xCC);
 		snd_soc_component_update_bits(component,

+ 3 - 0
asoc/codecs/wcd937x/internal.h

@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _WCD937X_INTERNAL_H
@@ -60,6 +61,7 @@ struct wcd937x_priv {
 	u32 hph_mode;
 	bool comp1_enable;
 	bool comp2_enable;
+	bool bcs_dis;
 
 	struct irq_domain *virq;
 	struct wcd_irq_info irq_info;
@@ -93,6 +95,7 @@ struct wcd937x_priv {
 	struct snd_info_entry *variant_entry;
 	int ear_rx_path;
 	int ana_clk_count;
+	int adc_count;
 	struct mutex ana_tx_clk_lock;
 	u8 tx_master_ch_map[WCD937X_MAX_SLAVE_CH_TYPES];
 	bool usbc_hs_status;

+ 109 - 16
asoc/codecs/wcd937x/wcd937x.c

@@ -142,11 +142,6 @@ static int wcd937x_handle_post_irq(void *data)
 	struct wcd937x_priv *wcd937x = data;
 	u32 status1 = 0, status2 = 0, status3 = 0;
 
-	/* Clear the ACK registers. Temporary workaround.*/
-	regmap_write(wcd937x->regmap, WCD937X_DIGITAL_INTR_CLEAR_0, 0x0);
-	regmap_write(wcd937x->regmap, WCD937X_DIGITAL_INTR_CLEAR_1, 0x0);
-	regmap_write(wcd937x->regmap, WCD937X_DIGITAL_INTR_CLEAR_2, 0x0);
-
 	regmap_read(wcd937x->regmap, WCD937X_DIGITAL_INTR_STATUS_0, &status1);
 	regmap_read(wcd937x->regmap, WCD937X_DIGITAL_INTR_STATUS_1, &status2);
 	regmap_read(wcd937x->regmap, WCD937X_DIGITAL_INTR_STATUS_2, &status3);
@@ -159,8 +154,20 @@ static int wcd937x_handle_post_irq(void *data)
 
 static int wcd937x_init_reg(struct snd_soc_component *component)
 {
-	snd_soc_component_update_bits(component, WCD937X_SLEEP_CTL,
+	u32 val = 0;
+
+	val = snd_soc_component_read(component, WCD937X_DIGITAL_EFUSE_REG_29)
+	     & 0x0F;
+
+	if (snd_soc_component_read(component, WCD937X_DIGITAL_EFUSE_REG_16)
+	    == 0x02 || snd_soc_component_read(component,
+	    WCD937X_DIGITAL_EFUSE_REG_17) > 0x09) {
+		snd_soc_component_update_bits(component, WCD937X_SLEEP_CTL,
+				0x0E, val);
+	} else {
+		snd_soc_component_update_bits(component, WCD937X_SLEEP_CTL,
 				0x0E, 0x0E);
+	}
 	snd_soc_component_update_bits(component, WCD937X_SLEEP_CTL,
 				0x80, 0x80);
 	usleep_range(1000, 1010);
@@ -187,6 +194,28 @@ static int wcd937x_init_reg(struct snd_soc_component *component)
 				0xFF, 0xFA);
 	snd_soc_component_update_bits(component, WCD937X_MICB3_TEST_CTL_1,
 				0xFF, 0xFA);
+	snd_soc_component_update_bits(component, WCD937X_MICB1_TEST_CTL_2,
+				      0x38, 0x00);
+	snd_soc_component_update_bits(component, WCD937X_MICB2_TEST_CTL_2,
+				      0x38, 0x00);
+	snd_soc_component_update_bits(component, WCD937X_MICB3_TEST_CTL_2,
+				      0x38, 0x00);
+	/* Set Bandgap Fine Adjustment to +5mV for Tanggu SMIC part */
+	if (snd_soc_component_read(component, WCD937X_DIGITAL_EFUSE_REG_16)
+	    == 0x01) {
+		snd_soc_component_update_bits(component,
+				WCD937X_BIAS_VBG_FINE_ADJ, 0xF0, 0xB0);
+	} else if (snd_soc_component_read(component,
+		WCD937X_DIGITAL_EFUSE_REG_16) == 0x02) {
+		snd_soc_component_update_bits(component,
+				WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x1F, 0x04);
+		snd_soc_component_update_bits(component,
+				WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x1F, 0x04);
+		snd_soc_component_update_bits(component,
+				WCD937X_BIAS_VBG_FINE_ADJ, 0xF0, 0xB0);
+		snd_soc_component_update_bits(component,
+				WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL, 0xF0, 0x50);
+	}
 	return 0;
 }
 
@@ -551,6 +580,12 @@ static int wcd937x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
 		set_bit(HPH_COMP_DELAY, &wcd937x->status_mask);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
+		if ((snd_soc_component_read(component,
+		   WCD937X_DIGITAL_EFUSE_REG_16) == 0x02) &&
+		   ((snd_soc_component_read(component,
+			WCD937X_ANA_HPH) & 0x0C) == 0x0C))
+			snd_soc_component_update_bits(component,
+			WCD937X_RX_BIAS_HPH_LOWPOWER, 0xF0, 0x90);
 		if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI)
 			snd_soc_component_update_bits(component,
 				WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
@@ -592,6 +627,12 @@ static int wcd937x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
 				WCD937X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x00);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
+		if ((snd_soc_component_read(component,
+		   WCD937X_DIGITAL_EFUSE_REG_16) == 0x02) &&
+		   ((snd_soc_component_read(component,
+			WCD937X_ANA_HPH) & 0x0C) == 0x0C))
+			snd_soc_component_update_bits(component,
+			WCD937X_RX_BIAS_HPH_LOWPOWER, 0xF0, 0x80);
 		snd_soc_component_update_bits(component,
 			WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
 			0x0F, 0x01);
@@ -625,6 +666,12 @@ static int wcd937x_codec_hphr_dac_event(struct snd_soc_dapm_widget *w,
 		set_bit(HPH_COMP_DELAY, &wcd937x->status_mask);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
+		if ((snd_soc_component_read(component,
+		   WCD937X_DIGITAL_EFUSE_REG_16) == 0x02) &&
+		   ((snd_soc_component_read(component,
+			WCD937X_ANA_HPH) & 0x0C) == 0x0C))
+			snd_soc_component_update_bits(component,
+			WCD937X_RX_BIAS_HPH_LOWPOWER, 0xF0, 0x90);
 		if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI)
 			snd_soc_component_update_bits(component,
 				WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R,
@@ -666,6 +713,12 @@ static int wcd937x_codec_hphr_dac_event(struct snd_soc_dapm_widget *w,
 				WCD937X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x00);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
+		if ((snd_soc_component_read(component,
+		   WCD937X_DIGITAL_EFUSE_REG_16) == 0x02) &&
+		   ((snd_soc_component_read(component,
+			WCD937X_ANA_HPH) & 0x0C) == 0x0C))
+			snd_soc_component_update_bits(component,
+			WCD937X_RX_BIAS_HPH_LOWPOWER, 0xF0, 0x80);
 		snd_soc_component_update_bits(component,
 			WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R,
 			0x0F, 0x01);
@@ -1413,8 +1466,12 @@ static int wcd937x_tx_swr_ctrl(struct snd_soc_dapm_widget *w,
 			/* Enable BCS for Headset mic */
 			if (w->shift == 1 && !(snd_soc_component_read(component,
 				WCD937X_TX_NEW_TX_CH2_SEL) & 0x80)) {
-				wcd937x_tx_connect_port(component, MBHC, true);
-				set_bit(AMIC2_BCS_ENABLE, &wcd937x->status_mask);
+				if (!wcd937x->bcs_dis) {
+					wcd937x_tx_connect_port(
+							component, MBHC, true);
+					set_bit(AMIC2_BCS_ENABLE,
+							&wcd937x->status_mask);
+				}
 			}
 			wcd937x_tx_connect_port(component, ADC1 + (w->shift), true);
 		} else {
@@ -1449,6 +1506,7 @@ static int wcd937x_codec_enable_adc(struct snd_soc_dapm_widget *w,
 		mutex_lock(&wcd937x->ana_tx_clk_lock);
 		wcd937x->ana_clk_count++;
 		mutex_unlock(&wcd937x->ana_tx_clk_lock);
+		wcd937x->adc_count++;
 		snd_soc_component_update_bits(component,
 				WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x80, 0x80);
 		snd_soc_component_update_bits(component,
@@ -1466,8 +1524,13 @@ static int wcd937x_codec_enable_adc(struct snd_soc_dapm_widget *w,
 			wcd937x_tx_connect_port(component, MBHC, false);
 			clear_bit(AMIC2_BCS_ENABLE, &wcd937x->status_mask);
 		}
-		snd_soc_component_update_bits(component,
-				WCD937X_DIGITAL_CDC_ANA_CLK_CTL, 0x08, 0x00);
+
+		wcd937x->adc_count--;
+		if (wcd937x->adc_count <= 0) {
+			snd_soc_component_update_bits(component,
+					WCD937X_DIGITAL_CDC_ANA_CLK_CTL, 0x08, 0x00);
+			wcd937x->adc_count = 0;
+		}
 		break;
 	};
 
@@ -1507,14 +1570,19 @@ static int wcd937x_enable_req(struct snd_soc_dapm_widget *w,
 				WCD937X_ANA_TX_CH3, 0x80, 0x80);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_component_update_bits(component,
+		if (wcd937x->adc_count == 0) {
+			snd_soc_component_update_bits(component,
 				WCD937X_ANA_TX_CH1, 0x80, 0x00);
-		snd_soc_component_update_bits(component,
+			snd_soc_component_update_bits(component,
 				WCD937X_ANA_TX_CH2, 0x80, 0x00);
-		snd_soc_component_update_bits(component,
+			snd_soc_component_update_bits(component,
 				WCD937X_ANA_TX_CH3, 0x80, 0x00);
-		snd_soc_component_update_bits(component,
+			snd_soc_component_update_bits(component,
 				WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x10, 0x00);
+			snd_soc_component_update_bits(component,
+				WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x80, 0x00);
+		}
+
 		mutex_lock(&wcd937x->ana_tx_clk_lock);
 		wcd937x->ana_clk_count--;
 		if (wcd937x->ana_clk_count <= 0) {
@@ -1524,8 +1592,6 @@ static int wcd937x_enable_req(struct snd_soc_dapm_widget *w,
 		}
 
 		mutex_unlock(&wcd937x->ana_tx_clk_lock);
-		snd_soc_component_update_bits(component,
-				WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x80, 0x00);
 		break;
 	};
 	return 0;
@@ -2185,6 +2251,29 @@ static int wcd937x_tx_master_ch_put(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
+static int wcd937x_bcs_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+				snd_soc_kcontrol_component(kcontrol);
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = wcd937x->bcs_dis;
+	return 0;
+}
+
+static int wcd937x_bcs_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_kcontrol_component(kcontrol);
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+	wcd937x->bcs_dis = ucontrol->value.integer.value[0];
+	dev_dbg(component->dev, "%s: BCS Disable %d\n", __func__, wcd937x->bcs_dis);
+	return 0;
+}
+
 static const char * const wcd937x_tx_ch_pwr_level_text[] = {
 	"L0", "L1", "L2", "L3",
 };
@@ -2216,6 +2305,8 @@ static const struct snd_kcontrol_new wcd937x_snd_controls[] = {
 		wcd937x_get_compander, wcd937x_set_compander),
 	SOC_SINGLE_EXT("HPHR_COMP Switch", SND_SOC_NOPM, 1, 1, 0,
 		wcd937x_get_compander, wcd937x_set_compander),
+	SOC_SINGLE_EXT("ADC2_BCS Disable", SND_SOC_NOPM, 0, 1, 0,
+		wcd937x_bcs_get, wcd937x_bcs_put),
 
 	SOC_SINGLE_TLV("HPHL Volume", WCD937X_HPH_L_EN, 0, 20, 1, line_gain),
 	SOC_SINGLE_TLV("HPHR Volume", WCD937X_HPH_R_EN, 0, 20, 1, line_gain),
@@ -2846,6 +2937,8 @@ static int wcd937x_soc_codec_probe(struct snd_soc_component *component)
 			component, WCD937X_DIGITAL_EFUSE_REG_0) & 0x1E) >> 1;
 	wcd937x->variant = variant;
 
+	wcd937x->adc_count = 0;
+
 	wcd937x->fw_data = devm_kzalloc(component->dev,
 					sizeof(*(wcd937x->fw_data)),
 					GFP_KERNEL);

+ 2 - 2
asoc/codecs/wsa881x-analog.c

@@ -1233,12 +1233,12 @@ static const struct snd_soc_component_driver soc_codec_dev_wsa881x = {
 
 static struct snd_soc_dai_driver wsa_dai[] = {
 	{
-		.name = "",
+		.name = "wsa_rx0",
 		.playback = {
 			.stream_name = "",
 			.rates = WSA881X_RATES | WSA881X_FRAC_RATES,
 			.formats = WSA881X_FORMATS,
-			.rate_max = 192000,
+			.rate_max = 384000,
 			.rate_min = 8000,
 			.channels_min = 1,
 			.channels_max = 2,

+ 9 - 0
asoc/holi.c

@@ -1774,7 +1774,16 @@ err:
 static int msm_asoc_machine_remove(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct msm_asoc_mach_data *pdata = NULL;
+	struct msm_common_pdata *common_pdata = NULL;
+
+	if (card)
+		pdata = snd_soc_card_get_drvdata(card);
+
+	if (pdata)
+		common_pdata = pdata->common_pdata;
 
+	msm_common_snd_deinit(common_pdata);
 	snd_event_master_deregister(&pdev->dev);
 	snd_soc_unregister_card(card);
 

+ 2 - 0
include/asoc/bolero-slave-internal.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 /* from Slave to bolero events */
@@ -24,4 +25,5 @@ enum {
 	BOLERO_SLV_EVT_PA_ON_POST_FSCLK,
 	BOLERO_SLV_EVT_PA_ON_POST_FSCLK_ADIE_LB,
 	BOLERO_SLV_EVT_CLK_NOTIFY,
+	BOLERO_SLV_EVT_RX_MACRO_PA_ON,
 };