summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorCharles Keepax <ckeepax@opensource.cirrus.com>2026-02-04 12:59:43 +0000
committerMark Brown <broonie@kernel.org>2026-02-04 14:10:51 +0000
commit812ff1baa764080ba37bb0729e0c23c0e869b542 (patch)
tree794a59609f3ce62978d5085afd140641eea8b466 /sound
parent02d851b46b366b69dfe0842ab45313d8a4d6c960 (diff)
ASoC: SDCA: Limit values user can write to Selected Mode
Prevent the user from both updating the Selected Mode control whilst the jack is not present, and from writing values that don't correspond to a valid jack type (Unknown, in progress, etc.). Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com> Link: https://patch.msgid.link/20260204125944.1134011-7-ckeepax@opensource.cirrus.com Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/sdca/sdca_asoc.c37
-rw-r--r--sound/soc/sdca/sdca_jack.c2
2 files changed, 37 insertions, 2 deletions
diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c
index 9685281529e9..bb6e74e80a3e 100644
--- a/sound/soc/sdca/sdca_asoc.c
+++ b/sound/soc/sdca/sdca_asoc.c
@@ -116,6 +116,41 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun
}
EXPORT_SYMBOL_NS(sdca_asoc_count_component, "SND_SOC_SDCA");
+static int ge_put_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+ struct device *dev = component->dev;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int *item = ucontrol->value.enumerated.item;
+ unsigned int reg = e->reg;
+ int ret;
+
+ reg &= ~SDW_SDCA_CTL_CSEL(0x3F);
+ reg |= SDW_SDCA_CTL_CSEL(SDCA_CTL_GE_DETECTED_MODE);
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0) {
+ dev_err(dev, "failed to resume writing %s: %d\n",
+ kcontrol->id.name, ret);
+ return ret;
+ }
+
+ ret = snd_soc_component_read(component, reg);
+ pm_runtime_put(dev);
+ if (ret < 0)
+ return ret;
+ else if (ret <= SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS)
+ return -EBUSY;
+
+ ret = snd_soc_enum_item_to_val(e, item[0]);
+ if (ret <= SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS)
+ return -EINVAL;
+
+ return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+}
+
static int entity_early_parse_ge(struct device *dev,
struct sdca_function_data *function,
struct sdca_entity *entity)
@@ -192,7 +227,7 @@ static int entity_early_parse_ge(struct device *dev,
kctl->name = control_name;
kctl->info = snd_soc_info_enum_double;
kctl->get = snd_soc_dapm_get_enum_double;
- kctl->put = snd_soc_dapm_put_enum_double;
+ kctl->put = ge_put_enum_double;
kctl->private_value = (unsigned long)soc_enum;
entity->ge.kctl = kctl;
diff --git a/sound/soc/sdca/sdca_jack.c b/sound/soc/sdca/sdca_jack.c
index bfa621b744e1..605514f02045 100644
--- a/sound/soc/sdca/sdca_jack.c
+++ b/sound/soc/sdca/sdca_jack.c
@@ -105,7 +105,7 @@ int sdca_jack_process(struct sdca_interrupt *interrupt)
ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(soc_enum, val);
- ret = kctl->put(kctl, ucontrol);
+ ret = snd_soc_dapm_put_enum_double(kctl, ucontrol);
if (ret < 0) {
dev_err(dev, "failed to update selected mode: %d\n", ret);
return ret;