Selaa lähdekoodia

Merge commit 'e3de149b42b456220dc761bd9a23e30302c78355' into audio-kernel.lnx.6.0.r1-rel

V S Ganga VaraPrasad (VARA) Adabala 1 vuosi sitten
vanhempi
sitoutus
1cae8a08d6

+ 2 - 0
Android.mk

@@ -391,6 +391,7 @@ LOCAL_MODULE_DEBUG_ENABLE := true
 LOCAL_MODULE_PATH         := $(KERNEL_MODULES_OUT)
 include $(DLKM_DIR)/Build_external_kernelmodule.mk
 ###########################################################
+ifeq ($(AUDIO_DLKM_ENABLE), true)
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES           := $(AUDIO_SRC_FILES)
 LOCAL_MODULE              := hdmi_dlkm.ko
@@ -402,6 +403,7 @@ LOCAL_REQUIRED_MODULES    := msm-ext-disp-module-symvers
 LOCAL_ADDITIONAL_DEPENDENCIES := $(call intermediates-dir-for,DLKM,msm-ext-disp-module-symvers)/Module.symvers
 include $(DLKM_DIR)/Build_external_kernelmodule.mk
 endif
+endif
 
 ifeq ($(call is-board-platform-in-list, bengal holi blair),true)
 ###########################################################

+ 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,

+ 2 - 0
asoc/codecs/lpass-cdc/lpass-cdc-tx-macro.c

@@ -1072,6 +1072,8 @@ static int lpass_cdc_tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
 			dec_cfg_reg, 0x06, 0x00);
 		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
 						0x10, 0x00);
+		snd_soc_component_update_bits(component, tx_fs_reg,
+						0x0F, 0x04);
 		if (tx_priv->bcs_enable) {
 			snd_soc_component_update_bits(component, dec_cfg_reg,
 					0x01, 0x00);

+ 2 - 0
asoc/codecs/lpass-cdc/lpass-cdc-va-macro.c

@@ -1392,6 +1392,8 @@ static int lpass_cdc_va_macro_enable_dec(struct snd_soc_dapm_widget *w,
 					0x40, 0x00);
 		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
 					0x10, 0x00);
+		snd_soc_component_update_bits(component, tx_fs_reg,
+					0x0F, 0x04);
 		break;
 	}
 	return 0;

+ 11 - 3
asoc/codecs/wcd-mbhc-v2.c

@@ -963,10 +963,15 @@ static bool wcd_mbhc_moisture_detect(struct wcd_mbhc *mbhc, bool detection_type)
 	return ret;
 }
 
-static void wcd_mbhc_set_hsj_connect(struct snd_soc_component *component, bool connect)
+static void wcd_mbhc_set_hsj_connect(struct wcd_mbhc *mbhc, bool connect)
 {
+
 #if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C)
+	struct snd_soc_component *component = mbhc->component;
 	if (connect) {
+		if (mbhc->mbhc_cb && mbhc->mbhc_cb->zdet_leakage_resistance)
+			mbhc->mbhc_cb->zdet_leakage_resistance(mbhc, false); /* enable 1M pull-up */
+
 		if (of_find_property(component->card->dev->of_node,
 					"qcom,usbss-hsj-connect-enabled", NULL))
 			wcd_usbss_switch_update(WCD_USBSS_HSJ_CONNECT, WCD_USBSS_CABLE_CONNECT);
@@ -974,6 +979,9 @@ static void wcd_mbhc_set_hsj_connect(struct snd_soc_component *component, bool c
 		if (of_find_property(component->card->dev->of_node,
 					"qcom,usbss-hsj-connect-enabled", NULL))
 			wcd_usbss_switch_update(WCD_USBSS_HSJ_CONNECT, WCD_USBSS_CABLE_DISCONNECT);
+
+		if (mbhc->mbhc_cb && mbhc->mbhc_cb->zdet_leakage_resistance)
+			mbhc->mbhc_cb->zdet_leakage_resistance(mbhc, true); /* disable 1M pull-up */
 	}
 #endif
 }
@@ -1019,7 +1027,7 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc)
 	if ((mbhc->current_plug == MBHC_PLUG_TYPE_NONE) &&
 	    detection_type) {
 
-		wcd_mbhc_set_hsj_connect(component, 1);
+		wcd_mbhc_set_hsj_connect(mbhc, 1);
 		/* If moisture is present, then enable polling, disable
 		 * moisture detection and wait for interrupt
 		 */
@@ -1135,7 +1143,7 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc)
 				mbhc->mbhc_cb->mbhc_moisture_detect_en(mbhc,
 									false);
 		}
-		wcd_mbhc_set_hsj_connect(component, 0);
+		wcd_mbhc_set_hsj_connect(mbhc, 0);
 
 	} else if (!detection_type) {
 		/* Disable external voltage source to micbias if present */

+ 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);

+ 352 - 0
asoc/codecs/wcd939x/wcd939x-mbhc.c

@@ -20,6 +20,8 @@
 #include <sound/soc-dapm.h>
 #include <asoc/wcdcal-hwdep.h>
 #include <asoc/wcd-mbhc-v2-api.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
 #include "wcd939x-registers.h"
 #include "internal.h"
 #if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C)
@@ -57,6 +59,13 @@
 #define MAX_TAP 1023
 #define RDOWN_TIMER_PERIOD_MSEC 100
 
+#define WCD_USBSS_WRITE true
+#define WCD_USBSS_READ false
+#define WCD_USBSS_EXT_LIN_EN 0x3D
+#define WCD_USBSS_EXT_SW_CTRL_1 0x43
+#define WCD_USBSS_MG1_BIAS 0x25
+#define WCD_USBSS_MG2_BIAS 0x29
+
 static struct wcd_mbhc_register
 	wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = {
 	WCD_MBHC_REGISTER("WCD_MBHC_L_DET_EN",
@@ -952,6 +961,310 @@ err_data:
 	*gnd_tap = 0;
 }
 
+struct usbcss_hs_attr {
+	struct wcd939x_priv *priv;
+	struct kobj_attribute attr;
+	int index;
+};
+
+static char *usbcss_sysfs_files[] = {
+	"rdson",
+	"r2",
+	"r3",
+	"r4",
+	"r5",
+	"r6",
+	"r7",
+	"lin-k-aud",
+	"lin-k-gnd",
+	"xtalk_config",
+};
+
+static ssize_t usbcss_sysfs_store(struct kobject *kobj,
+		struct kobj_attribute *attr, const char *buf,
+		size_t count)
+{
+	struct usbcss_hs_attr *usbc_attr;
+	struct wcd939x_priv *wcd939x;
+	struct wcd939x_pdata *pdata;
+	struct wcd939x_usbcss_hs_params *usbcss_hs;
+	long val;
+	int rc;
+	u32 aud_tap = 0, gnd_tap = 0;
+	bool update_xtalk = false, update_linearizer = false;
+
+	usbc_attr = container_of(attr, struct usbcss_hs_attr, attr);
+	wcd939x = usbc_attr->priv;
+	pdata = dev_get_platdata(wcd939x->dev);
+
+	if (!wcd939x || !pdata)
+		return -EINVAL;
+
+	usbcss_hs = &pdata->usbcss_hs;
+
+	rc = kstrtol(buf, 0, &val);
+	if (rc)
+		return rc;
+
+	if (strcmp(attr->attr.name, "rdson") == 0) {
+		if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) {
+			dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n",
+			__func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS);
+			return count;
+		}
+		usbcss_hs->r_gnd_ext_fet_customer_mohms = val;
+		update_linearizer = usbcss_hs->xtalk_config == XTALK_ANALOG;
+	} else if (strcmp(attr->attr.name, "r2") == 0) {
+		if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) {
+			dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n",
+			__func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS);
+			return count;
+		}
+		usbcss_hs->r_conn_par_load_pos_mohms = val;
+	} else if (strcmp(attr->attr.name, "r3") == 0) {
+		if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) {
+			dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n",
+			__func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS);
+			return count;
+		}
+		usbcss_hs->r3 = val;
+		update_linearizer = true;
+	} else if (strcmp(attr->attr.name, "r4") == 0) {
+		if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) {
+			dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n",
+			__func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS);
+			return count;
+		}
+		usbcss_hs->r4 = val;
+		update_xtalk = true;
+		update_linearizer = true;
+
+		switch (usbcss_hs->xtalk_config) {
+		case XTALK_DIGITAL:
+			usbcss_hs->r_gnd_par_route2_mohms = usbcss_hs->r6 + val;
+			break;
+		case XTALK_ANALOG:
+			usbcss_hs->r_gnd_par_route1_mohms = usbcss_hs->r5 + val;
+			break;
+		case XTALK_NONE:
+			fallthrough;
+		default:
+			return count;
+		}
+	} else if (strcmp(attr->attr.name, "r5") == 0) {
+		if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) {
+			dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n",
+			__func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS);
+			return count;
+		}
+		usbcss_hs->r5 = val;
+
+		switch (usbcss_hs->xtalk_config) {
+		case XTALK_ANALOG:
+			update_xtalk = true;
+			update_linearizer = true;
+			usbcss_hs->r_gnd_par_route1_mohms = val + usbcss_hs->r4;
+			break;
+		case XTALK_DIGITAL:
+			fallthrough;
+		case XTALK_NONE:
+			fallthrough;
+		default:
+			return count;
+		}
+	} else if (strcmp(attr->attr.name, "r6") == 0) {
+		if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) {
+			dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n",
+			__func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS);
+			return count;
+		}
+		usbcss_hs->r6 = val;
+
+		switch (usbcss_hs->xtalk_config) {
+		case XTALK_DIGITAL:
+			update_xtalk = true;
+			update_linearizer = true;
+			usbcss_hs->r_gnd_par_route2_mohms = val + usbcss_hs->r4;
+			break;
+		case XTALK_ANALOG:
+			fallthrough;
+		case XTALK_NONE:
+			fallthrough;
+		default:
+			return count;
+		}
+	} else if (strcmp(attr->attr.name, "r7") == 0) {
+		if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) {
+			dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n",
+			__func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS);
+			return count;
+		}
+		usbcss_hs->r7 = val;
+
+		switch (usbcss_hs->xtalk_config) {
+		case XTALK_DIGITAL:
+			update_xtalk = true;
+			update_linearizer = true;
+			usbcss_hs->r_gnd_par_route1_mohms = val;
+			break;
+		case XTALK_ANALOG:
+			fallthrough;
+		case XTALK_NONE:
+			fallthrough;
+		default:
+			return count;
+		}
+	} else if (strcmp(attr->attr.name, "lin-k-aud") == 0) {
+		if (val < MIN_K_TIMES_100 || val > MAX_K_TIMES_100) {
+			dev_err(wcd939x->dev, "%s: Value %d out of bounds. Min: %d, Max: %d\n",
+			__func__, val, MIN_K_TIMES_100, MAX_K_TIMES_100);
+			return count;
+		}
+		usbcss_hs->k_aud_times_100 = val;
+		update_linearizer = true;
+	} else if (strcmp(attr->attr.name, "lin-k-gnd") == 0) {
+		if (val < MIN_K_TIMES_100 || val > MAX_K_TIMES_100) {
+			dev_err(wcd939x->dev, "%s: Value %d out of bounds. Min: %d, Max: %d\n",
+			__func__, val, MIN_K_TIMES_100, MAX_K_TIMES_100);
+			return count;
+		}
+		usbcss_hs->k_gnd_times_100 = val;
+		update_linearizer = true;
+	} else if (strcmp(attr->attr.name, "xtalk_config") == 0) {
+		pdata->usbcss_hs.xtalk_config = val;
+		update_xtalk = true;
+
+		switch (val) {
+		case XTALK_NONE:
+			usbcss_hs->scale_l = MAX_XTALK_SCALE;
+			usbcss_hs->scale_r = MAX_XTALK_SCALE;
+			usbcss_hs->alpha_l = MIN_XTALK_ALPHA;
+			usbcss_hs->alpha_r = MIN_XTALK_ALPHA;
+			break;
+		case XTALK_DIGITAL:
+			usbcss_hs->r_gnd_par_route2_mohms = usbcss_hs->r6 + usbcss_hs->r4;
+			usbcss_hs->r_gnd_par_route1_mohms = usbcss_hs->r7;
+			update_linearizer = true;
+			break;
+		case XTALK_ANALOG:
+			usbcss_hs->r_gnd_par_route1_mohms = usbcss_hs->r5 + usbcss_hs->r4;
+			usbcss_hs->r_gnd_par_route2_mohms = 1;
+			update_linearizer = true;
+			break;
+		default:
+			return count;
+		}
+	}
+
+	if (update_xtalk) {
+		update_xtalk_scale_and_alpha(pdata, wcd939x->regmap);
+		regmap_update_bits(wcd939x->regmap, WCD939X_HPHL_RX_PATH_SEC0,
+				0x1F, pdata->usbcss_hs.scale_l);
+		regmap_update_bits(wcd939x->regmap, WCD939X_HPHL_RX_PATH_SEC1,
+				0xFF, pdata->usbcss_hs.alpha_l);
+		regmap_update_bits(wcd939x->regmap, WCD939X_HPHL_RX_PATH_SEC0 + 1,
+				0x1F, pdata->usbcss_hs.scale_r);
+		regmap_update_bits(wcd939x->regmap, WCD939X_HPHL_RX_PATH_SEC1 + 1,
+				0xFF, pdata->usbcss_hs.alpha_r);
+		dev_err(wcd939x->dev, "%s: Updated xtalk thru sysfs\n",
+			__func__);
+	}
+
+	if (update_linearizer) {
+		get_linearizer_taps(pdata, &aud_tap, &gnd_tap);
+		wcd_usbss_set_linearizer_sw_tap(aud_tap, gnd_tap);
+		dev_err(wcd939x->dev, "%s: Updated linearizer thru sysfs\n",
+			__func__);
+	}
+
+	return count;
+}
+
+static ssize_t usbcss_sysfs_show(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	struct usbcss_hs_attr *usbc_attr;
+	struct wcd939x_priv *wcd939x;
+	struct wcd939x_pdata *pdata;
+
+	usbc_attr = container_of(attr, struct usbcss_hs_attr, attr);
+	wcd939x = usbc_attr->priv;
+	pdata = dev_get_platdata(wcd939x->dev);
+
+	if (strcmp(attr->attr.name, "rdson") == 0)
+		return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.r_gnd_ext_fet_customer_mohms);
+	else if (strcmp(attr->attr.name, "r2") == 0)
+		return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.r_conn_par_load_pos_mohms);
+	else if (strcmp(attr->attr.name, "r3") == 0)
+		return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.r3);
+	else if (strcmp(attr->attr.name, "r4") == 0)
+		return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.r4);
+	else if (strcmp(attr->attr.name, "r5") == 0)
+		return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.r5);
+	else if (strcmp(attr->attr.name, "r6") == 0)
+		return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.r6);
+	else if (strcmp(attr->attr.name, "r7") == 0)
+		return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.r7);
+	else if (strcmp(attr->attr.name, "lin-k-aud") == 0)
+		return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.k_aud_times_100);
+	else if (strcmp(attr->attr.name, "lin-k-gnd") == 0)
+		return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.k_gnd_times_100);
+	else if (strcmp(attr->attr.name, "xtalk_config") == 0)
+		return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.xtalk_config);
+
+	return 0;
+}
+
+static int create_sysfs_entry_file(struct wcd939x_priv *wcd939x, char *name, int mode,
+		int index, struct kobject *parent)
+{
+	struct usbcss_hs_attr *usbc_attr;
+	char *name_copy;
+
+	usbc_attr = devm_kmalloc(wcd939x->dev, sizeof(*usbc_attr), GFP_KERNEL);
+	if (!usbc_attr)
+		return -ENOMEM;
+
+	name_copy = devm_kstrdup(wcd939x->dev, name, GFP_KERNEL);
+	if (!name_copy)
+		return -ENOMEM;
+
+	usbc_attr->priv = wcd939x;
+	usbc_attr->index = index;
+	usbc_attr->attr.attr.name = name_copy;
+	usbc_attr->attr.attr.mode = mode;
+	usbc_attr->attr.show = usbcss_sysfs_show;
+	usbc_attr->attr.store = usbcss_sysfs_store;
+	sysfs_attr_init(&usbc_attr->attr.attr);
+
+	return sysfs_create_file(parent, &usbc_attr->attr.attr);
+}
+
+static int usbcss_hs_sysfs_init(struct wcd939x_priv *wcd939x)
+{
+	int rc = 0;
+	int i = 0;
+	struct kobject *kobj = NULL;
+
+	if (!wcd939x || !wcd939x->dev) {
+		pr_err("%s: Invalid wcd939x private data.\n", __func__);
+		return -EINVAL;
+	}
+
+	kobj = kobject_create_and_add("usbcss_hs", kernel_kobj);
+	if (!kobj) {
+		dev_err(wcd939x->dev, "%s: Could not create the USBC-SS HS kobj.\n", __func__);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(usbcss_sysfs_files); i++) {
+		rc = create_sysfs_entry_file(wcd939x, usbcss_sysfs_files[i],
+				0644, i, kobj);
+	}
+
+	return 0;
+}
+
 static void wcd939x_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, uint32_t *zr)
 {
 	struct snd_soc_component *component = mbhc->component;
@@ -967,6 +1280,11 @@ static void wcd939x_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
 	struct wcd939x_mbhc_zdet_param zdet_param = {4, 0, 6, 0x18, 0x60, 0x78};
 	struct wcd939x_mbhc_zdet_param *zdet_param_ptr = &zdet_param;
 	s16 d1[] = {0, 30, 30, 6};
+	uint32_t cached_regs[4][2] = {{WCD_USBSS_EXT_LIN_EN, 0}, {WCD_USBSS_EXT_SW_CTRL_1, 0},
+				      {WCD_USBSS_MG1_BIAS, 0}, {WCD_USBSS_MG2_BIAS, 0}};
+	uint32_t l_3_6V_regs[4][2] = {{WCD_USBSS_EXT_LIN_EN, 0x00}, {WCD_USBSS_EXT_SW_CTRL_1, 0x00},
+				      {WCD_USBSS_MG1_BIAS, 0x0E}, {WCD_USBSS_MG2_BIAS, 0x0E}};
+	uint32_t diff_regs[2][2] = {{WCD_USBSS_EXT_LIN_EN, 0x00}, {WCD_USBSS_EXT_SW_CTRL_1, 0xE8}};
 
 	WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
 
@@ -988,6 +1306,11 @@ static void wcd939x_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
 		usleep_range(500, 510);
 	}
 
+#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C)
+	/* Cache relevant USB-SS registers */
+	wcd_usbss_register_update(cached_regs, WCD_USBSS_READ, ARRAY_SIZE(cached_regs));
+#endif
+
 	/* Store register values */
 	reg0 = snd_soc_component_read(component, WCD939X_MBHC_BTN5);
 	reg1 = snd_soc_component_read(component, WCD939X_MBHC_BTN6);
@@ -1028,6 +1351,9 @@ static void wcd939x_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
 #endif
 
 	/* L-channel impedance */
+#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C)
+	wcd_usbss_register_update(l_3_6V_regs, WCD_USBSS_WRITE, ARRAY_SIZE(l_3_6V_regs));
+#endif
 	wcd939x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1);
 	if ((z1L == WCD939X_ZDET_FLOATING_IMPEDANCE) || (z1L > WCD939X_ZDET_VAL_100K)) {
 		*zl = WCD939X_ZDET_FLOATING_IMPEDANCE;
@@ -1063,6 +1389,7 @@ diff_impedance:
 #if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C)
 	/* Disable AGND switch */
 	wcd_usbss_set_switch_settings_enable(AGND_SWITCHES, USBSS_SWITCH_DISABLE);
+	wcd_usbss_register_update(diff_regs, WCD_USBSS_WRITE, ARRAY_SIZE(diff_regs));
 #endif
 	/* Enable HPHR NCLAMP */
 	regmap_update_bits(wcd939x->regmap, WCD939X_HPHLR_SURGE_MISC1, 0x08, 0x08);
@@ -1192,6 +1519,10 @@ zdet_complete:
 		regmap_update_bits(wcd939x->regmap,
 				   WCD939X_MBHC_ELECT, 0x80, 0x80);
 
+#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C)
+	wcd_usbss_register_update(cached_regs, WCD_USBSS_WRITE, ARRAY_SIZE(cached_regs));
+#endif
+
 	/* Turn off RX supplies */
 	if (wcd939x->version == WCD939X_VERSION_2_0) {
 		/* Set VPOS to be controlled by RX */
@@ -1344,6 +1675,17 @@ static void wcd939x_surge_reset_routine(struct wcd_mbhc *mbhc)
 	regcache_sync(wcd939x->regmap);
 }
 
+static void wcd939x_mbhc_zdet_leakage_resistance(struct wcd_mbhc *mbhc,
+							bool enable)
+{
+	if (enable)
+		snd_soc_component_update_bits(mbhc->component, WCD939X_ZDET_BIAS_CTL,
+				0x80, 0x80); /* disable 1M pull-up */
+	else
+		snd_soc_component_update_bits(mbhc->component, WCD939X_ZDET_BIAS_CTL,
+				0x80, 0x00); /* enable 1M pull-up */
+}
+
 static const struct wcd_mbhc_cb mbhc_cb = {
 	.request_irq = wcd939x_mbhc_request_irq,
 	.irq_control = wcd939x_mbhc_irq_control,
@@ -1370,6 +1712,7 @@ static const struct wcd_mbhc_cb mbhc_cb = {
 	.mbhc_moisture_detect_en = wcd939x_mbhc_moisture_detect_en,
 	.bcs_enable = wcd939x_mbhc_bcs_enable,
 	.surge_reset_routine = wcd939x_surge_reset_routine,
+	.zdet_leakage_resistance = wcd939x_mbhc_zdet_leakage_resistance,
 };
 
 static int wcd939x_get_hph_type(struct snd_kcontrol *kcontrol,
@@ -1595,6 +1938,7 @@ int wcd939x_mbhc_init(struct wcd939x_mbhc **mbhc,
 	struct wcd_mbhc *wcd_mbhc = NULL;
 	int ret = 0;
 	struct wcd939x_pdata *pdata;
+	struct wcd939x_priv *wcd939x;
 
 	if (!component) {
 		pr_err("%s: component is NULL\n", __func__);
@@ -1647,6 +1991,14 @@ int wcd939x_mbhc_init(struct wcd939x_mbhc **mbhc,
 	snd_soc_add_component_controls(component, hph_type_detect_controls,
 				   ARRAY_SIZE(hph_type_detect_controls));
 
+	wcd939x = dev_get_drvdata(component->dev);
+	if (!wcd939x) {
+		dev_err(component->dev, "%s: wcd939x pointer is NULL\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+	usbcss_hs_sysfs_init(wcd939x);
+
 	return 0;
 err:
 	if (wcd939x_mbhc)

+ 5 - 0
asoc/codecs/wcd939x/wcd939x.c

@@ -443,6 +443,11 @@ static int wcd939x_init_reg(struct snd_soc_component *component)
 	if (wcd939x->version != WCD939X_VERSION_2_0)
 		snd_soc_component_write(component, WCD939X_CFG0, 0x05);
 
+	/*
+	 * Disable 1M pull-up by default during boot by writing 0b1 to bit[7].
+	 * This gets re-enabled when headset is inserted.
+	 */
+	snd_soc_component_update_bits(component, WCD939X_ZDET_BIAS_CTL, 0x80, 0x80);
 	return 0;
 }
 

+ 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,
 };

+ 1 - 0
include/asoc/wcd-mbhc-v2.h

@@ -531,6 +531,7 @@ struct wcd_mbhc_cb {
 	void (*mbhc_moisture_polling_ctrl)(struct wcd_mbhc *mbhc, bool enable);
 	void (*mbhc_moisture_detect_en)(struct wcd_mbhc *mbhc, bool enable);
 	void (*surge_reset_routine)(struct wcd_mbhc *mbhc);
+	void (*zdet_leakage_resistance)(struct wcd_mbhc *mbhc, bool enable);
 };
 
 struct wcd_mbhc_fn {

+ 10 - 0
include/bindings/audio-codec-port-types.h

@@ -96,4 +96,14 @@
 #define SWRM_TX_PCM_IN 58
 #define HIFI_PCM_L 59
 #define HIFI_PCM_R 60
+
+// BT SWR PORT defines
+#define BT_AUDIO_RX1 101
+#define BT_AUDIO_TX1 102
+#define BT_AUDIO_RX2 103
+#define BT_AUDIO_TX2 104
+#define BT_AUDIO_RX3 105
+#define BT_AUDIO_TX3 106
+#define FM_AUDIO_TX1 107
+
 #endif /* __AUDIO_CODEC_PORT_TYPES_H */