[RFC PATCH 15/23] ASoC: qcom: audioreach: add speaker protection mixer controls

From: Srinivas Kandagatla

Date: Fri Oct 23 2026 - 13:24:05 EST


From: Ravi Hothi <ravi.hothi@xxxxxxxxxxxxxxxx>

Add topology mixer controls for the operation mode and the per-speaker
R0/T0 pairs, so userspace can run a calibration and restore its result.

Signed-off-by: Ravi Hothi <ravi.hothi@xxxxxxxxxxxxxxxx>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@xxxxxxxxxxxxxxxx>
---
include/uapi/sound/snd_ar_tokens.h | 2 +
sound/soc/qcom/qdsp6/topology.c | 80 ++++++++++++++++++++++++++++++
2 files changed, 82 insertions(+)

diff --git a/include/uapi/sound/snd_ar_tokens.h b/include/uapi/sound/snd_ar_tokens.h
index 7ab8e11ca5c2..db62dc7f9c8a 100644
--- a/include/uapi/sound/snd_ar_tokens.h
+++ b/include/uapi/sound/snd_ar_tokens.h
@@ -57,6 +57,8 @@ enum ar_event_types {
*/
#define SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX 256
#define SND_SOC_AR_TPLG_VOL_CTL 257
+#define SND_SOC_AR_TPLG_SP_OP_MODE_CTL 258
+#define SND_SOC_AR_TPLG_SP_R0T0_CTL 259

/*
* %AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: Sub Graph Instance Id
diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c
index 5de7e821e5f4..6316d1ab0675 100644
--- a/sound/soc/qcom/qdsp6/topology.c
+++ b/sound/soc/qcom/qdsp6/topology.c
@@ -1463,6 +1463,73 @@ static int audioreach_put_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol,
return 1;
}

+static int audioreach_get_sp_op_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.enumerated.item[0] = audioreach_get_sp_operation_mode();
+
+ return 0;
+}
+
+static int audioreach_put_sp_op_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int mode = ucontrol->value.enumerated.item[0];
+
+ if (mode >= e->items)
+ return -EINVAL;
+
+ if (mode == audioreach_get_sp_operation_mode())
+ return 0;
+
+ audioreach_set_sp_operation_mode(mode);
+
+ return 1;
+}
+
+/* One R0/T0 pair per speaker, written as a whole set */
+#define AR_SP_R0T0_CTL_COUNT (MAX_SP_VI_SPEAKERS * 2)
+
+static int audioreach_info_sp_r0t0(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = AR_SP_R0T0_CTL_COUNT;
+ uinfo->value.integer.min = S32_MIN;
+ uinfo->value.integer.max = S32_MAX;
+
+ return 0;
+}
+
+static int audioreach_get_sp_r0t0(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ audioreach_get_sp_vi_r0t0(ucontrol->value.integer.value,
+ AR_SP_R0T0_CTL_COUNT);
+
+ return 0;
+}
+
+static int audioreach_put_sp_r0t0(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *scomp = snd_kcontrol_chip(kcontrol);
+ long cur[AR_SP_R0T0_CTL_COUNT];
+ int ret;
+
+ audioreach_get_sp_vi_r0t0(cur, AR_SP_R0T0_CTL_COUNT);
+ if (!memcmp(cur, ucontrol->value.integer.value, sizeof(cur)))
+ return 0;
+
+ ret = audioreach_set_sp_vi_r0t0(scomp->dev, ucontrol->value.integer.value,
+ AR_SP_R0T0_CTL_COUNT);
+ if (ret < 0)
+ return ret;
+
+ return 1;
+}
+
static int audioreach_control_load_mix(struct snd_soc_component *scomp,
struct snd_ar_control *scontrol,
struct snd_kcontrol_new *kc,
@@ -1503,6 +1570,7 @@ static int audioreach_control_load(struct snd_soc_component *scomp, int index,
{
struct snd_ar_control *scontrol;
struct soc_mixer_control *sm;
+ struct soc_enum *se;
struct snd_soc_dobj *dobj;
int ret = 0;

@@ -1522,6 +1590,14 @@ static int audioreach_control_load(struct snd_soc_component *scomp, int index,
sm = (struct soc_mixer_control *)kc->private_value;
dobj = &sm->dobj;
break;
+ case SND_SOC_AR_TPLG_SP_R0T0_CTL:
+ sm = (struct soc_mixer_control *)kc->private_value;
+ dobj = &sm->dobj;
+ break;
+ case SND_SOC_AR_TPLG_SP_OP_MODE_CTL:
+ se = (struct soc_enum *)kc->private_value;
+ dobj = &se->dobj;
+ break;
default:
dev_warn(scomp->dev, "control type not supported %d:%d:%d\n",
hdr->ops.get, hdr->ops.put, hdr->ops.info);
@@ -1548,6 +1624,10 @@ static const struct snd_soc_tplg_kcontrol_ops audioreach_io_ops[] = {
audioreach_put_audio_mixer, snd_soc_info_volsw},
{SND_SOC_AR_TPLG_VOL_CTL, audioreach_get_vol_ctrl_audio_mixer,
audioreach_put_vol_ctrl_audio_mixer, snd_soc_info_volsw},
+ {SND_SOC_AR_TPLG_SP_OP_MODE_CTL, audioreach_get_sp_op_mode,
+ audioreach_put_sp_op_mode, snd_soc_info_enum_double},
+ {SND_SOC_AR_TPLG_SP_R0T0_CTL, audioreach_get_sp_r0t0,
+ audioreach_put_sp_r0t0, audioreach_info_sp_r0t0},
};

static const struct snd_soc_tplg_ops audioreach_tplg_ops = {
--
2.47.3