[PATCH v1 2/3] ASoC: tas2781: add capture profile control and capture dapm event

Shenghao Ding <[email protected]> Sat, 1 Aug 2026 10:08:20 +0800
Newsgroups org.kernel.vger.linux-sound
Message-ID <[email protected]>
Expose a new mixer control "Speaker Capture Profile Id" to user space,
so that applications can configure which profile ID should be used
for capture paths.

Add a dedicated DAPM event handler tasdevice_capture_dapm_event() that
calls tasdevice_tuning_switch() with is_cap=true, and attach it to the
ASI Capture widget. This completes the end-to-end support for PDM
microphone recording and IV data capture tuning on SmartAMP devices.

Signed-off-by: Shenghao Ding <[email protected]>
---
 sound/soc/codecs/tas2781-i2c.c | 82 +++++++++++++++++++++++++++++++++-
 1 file changed, 80 insertions(+), 2 deletions(-)

diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c
index 01442fd57d7e..307af0d4807c 100644
--- a/sound/soc/codecs/tas2781-i2c.c
+++ b/sound/soc/codecs/tas2781-i2c.c
@@ -1000,6 +1000,23 @@ static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
 	return ret;
 }
 
+static int tasdevice_set_capture_profile_id(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+	struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+	int ret = 0;
+
+	if (tas_priv->rcabin.capture_profile_id !=
+		ucontrol->value.integer.value[0]) {
+		tas_priv->rcabin.capture_profile_id =
+			ucontrol->value.integer.value[0];
+		ret = 1;
+	}
+
+	return ret;
+}
+
 static int tasdevice_info_active_num(struct snd_kcontrol *kcontrol,
 			struct snd_ctl_elem_info *uinfo)
 {
@@ -1080,6 +1097,17 @@ static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
+static int tasdevice_get_capture_profile_id(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+	struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = tas_priv->rcabin.capture_profile_id;
+
+	return 0;
+}
+
 static int tasdevice_get_chip_id(struct snd_kcontrol *kcontrol,
 			struct snd_ctl_elem_value *ucontrol)
 {
@@ -1122,6 +1150,41 @@ static int tasdevice_create_control(struct tasdevice_priv *tas_priv)
 	ret = snd_soc_add_component_controls(tas_priv->codec,
 		prof_ctrls, nr_controls < mix_index ? nr_controls : mix_index);
 
+	mix_index = 0;
+	switch (tas_priv->chip_id) {
+	case TAS2563:
+	case TAS2568:
+	case TAS2570:
+	case TAS2572:
+	case TAS2573:
+	case TAS2574:
+	case TAS2781:
+	prof_ctrls = devm_kcalloc(tas_priv->dev, nr_controls,
+		sizeof(prof_ctrls[0]), GFP_KERNEL);
+	if (!prof_ctrls) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/* Create a mixer item for selecting the capture profile */
+	name = devm_kstrdup(tas_priv->dev, "Speaker Capture Profile Id",
+		GFP_KERNEL);
+	if (!name) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	prof_ctrls[mix_index].name = name;
+	prof_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	prof_ctrls[mix_index].info = tasdevice_info_profile;
+	prof_ctrls[mix_index].get = tasdevice_get_capture_profile_id;
+	prof_ctrls[mix_index].put = tasdevice_set_capture_profile_id;
+	mix_index++;
+
+	ret = snd_soc_add_component_controls(tas_priv->codec,
+		prof_ctrls, nr_controls < mix_index ? nr_controls : mix_index);
+		break;
+	}
+
 out:
 	return ret;
 }
@@ -1773,7 +1836,22 @@ static int tasdevice_dapm_event(struct snd_soc_dapm_widget *w,
 	guard(mutex)(&tas_priv->codec_lock);
 	if (event == SND_SOC_DAPM_PRE_PMD)
 		state = 1;
-	tasdevice_tuning_switch(tas_priv, state);
+	tasdevice_tuning_switch(tas_priv, state, false);
+
+	return 0;
+}
+
+static int tasdevice_capture_dapm_event(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
+	struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+	int state = 0;
+
+	guard(mutex)(&tas_priv->codec_lock);
+	if (event == SND_SOC_DAPM_PRE_PMD)
+		state = 1;
+	tasdevice_tuning_switch(tas_priv, state, true);
 
 	return 0;
 }
@@ -1781,7 +1859,7 @@ static int tasdevice_dapm_event(struct snd_soc_dapm_widget *w,
 static const struct snd_soc_dapm_widget tasdevice_dapm_widgets[] = {
 	SND_SOC_DAPM_AIF_IN("ASI", "ASI Playback", 0, SND_SOC_NOPM, 0, 0),
 	SND_SOC_DAPM_AIF_OUT_E("ASI OUT", "ASI Capture", 0, SND_SOC_NOPM,
-		0, 0, tasdevice_dapm_event,
+		0, 0, tasdevice_capture_dapm_event,
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 	SND_SOC_DAPM_SPK("SPK", tasdevice_dapm_event),
 	SND_SOC_DAPM_OUTPUT("OUT"),
-- 
2.43.0