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>
This commit is contained in:
Charles Keepax 2026-02-04 12:59:43 +00:00 committed by Mark Brown
parent 02d851b46b
commit 812ff1baa7
2 changed files with 37 additions and 2 deletions

View File

@ -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;

View File

@ -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;