Skip to content

Commit e979a6a

Browse files
ujfalusigregkh
authored andcommitted
ASoC: SOF: ipc4-control: Add support for ALSA enum control
commit 07a866a upstream. Enum controls use generic param_id and a generic struct where the data is passed to the firmware. Signed-off-by: Peter Ujfalusi <[email protected]> Reviewed-by: Bard Liao <[email protected]> Reviewed-by: Pierre-Louis Bossart <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 3facc04 commit e979a6a

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

sound/soc/sof/ipc4-control.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,63 @@ static int sof_ipc4_switch_get(struct snd_sof_control *scontrol,
297297
return 0;
298298
}
299299

300+
static bool sof_ipc4_enum_put(struct snd_sof_control *scontrol,
301+
struct snd_ctl_elem_value *ucontrol)
302+
{
303+
struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
304+
struct snd_soc_component *scomp = scontrol->scomp;
305+
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
306+
struct snd_sof_widget *swidget;
307+
bool widget_found = false;
308+
bool change = false;
309+
unsigned int i;
310+
u32 value;
311+
int ret;
312+
313+
/* update each channel */
314+
for (i = 0; i < scontrol->num_channels; i++) {
315+
value = ucontrol->value.enumerated.item[i];
316+
change = change || (value != cdata->chanv[i].value);
317+
cdata->chanv[i].channel = i;
318+
cdata->chanv[i].value = value;
319+
}
320+
321+
if (!pm_runtime_active(scomp->dev))
322+
return change;
323+
324+
/* find widget associated with the control */
325+
list_for_each_entry(swidget, &sdev->widget_list, list) {
326+
if (swidget->comp_id == scontrol->comp_id) {
327+
widget_found = true;
328+
break;
329+
}
330+
}
331+
332+
if (!widget_found) {
333+
dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
334+
return false;
335+
}
336+
337+
ret = sof_ipc4_set_generic_control_data(sdev, swidget, scontrol, true);
338+
if (ret < 0)
339+
return false;
340+
341+
return change;
342+
}
343+
344+
static int sof_ipc4_enum_get(struct snd_sof_control *scontrol,
345+
struct snd_ctl_elem_value *ucontrol)
346+
{
347+
struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
348+
unsigned int i;
349+
350+
/* read back each channel */
351+
for (i = 0; i < scontrol->num_channels; i++)
352+
ucontrol->value.enumerated.item[i] = cdata->chanv[i].value;
353+
354+
return 0;
355+
}
356+
300357
static int sof_ipc4_set_get_bytes_data(struct snd_sof_dev *sdev,
301358
struct snd_sof_control *scontrol,
302359
bool set, bool lock)
@@ -562,6 +619,11 @@ static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_s
562619
ret = sof_ipc4_set_get_bytes_data(sdev, scontrol,
563620
true, false);
564621
break;
622+
case SND_SOC_TPLG_CTL_ENUM:
623+
case SND_SOC_TPLG_CTL_ENUM_VALUE:
624+
ret = sof_ipc4_set_generic_control_data(sdev, swidget,
625+
scontrol, false);
626+
break;
565627
default:
566628
break;
567629
}
@@ -605,6 +667,8 @@ const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = {
605667
.volume_get = sof_ipc4_volume_get,
606668
.switch_put = sof_ipc4_switch_put,
607669
.switch_get = sof_ipc4_switch_get,
670+
.enum_put = sof_ipc4_enum_put,
671+
.enum_get = sof_ipc4_enum_get,
608672
.bytes_put = sof_ipc4_bytes_put,
609673
.bytes_get = sof_ipc4_bytes_get,
610674
.bytes_ext_put = sof_ipc4_bytes_ext_put,

sound/soc/sof/ipc4-topology.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2148,6 +2148,36 @@ static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof
21482148
return 0;
21492149
}
21502150

2151+
static int sof_ipc4_control_load_enum(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
2152+
{
2153+
struct sof_ipc4_control_data *control_data;
2154+
struct sof_ipc4_msg *msg;
2155+
int i;
2156+
2157+
scontrol->size = struct_size(control_data, chanv, scontrol->num_channels);
2158+
2159+
/* scontrol->ipc_control_data will be freed in sof_control_unload */
2160+
scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
2161+
if (!scontrol->ipc_control_data)
2162+
return -ENOMEM;
2163+
2164+
control_data = scontrol->ipc_control_data;
2165+
control_data->index = scontrol->index;
2166+
2167+
msg = &control_data->msg;
2168+
msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
2169+
msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
2170+
msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
2171+
2172+
msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_ENUM_CONTROL_PARAM_ID);
2173+
2174+
/* Default, initial value for enums: first enum entry is selected (0) */
2175+
for (i = 0; i < scontrol->num_channels; i++)
2176+
control_data->chanv[i].channel = i;
2177+
2178+
return 0;
2179+
}
2180+
21512181
static int sof_ipc4_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
21522182
{
21532183
struct sof_ipc4_control_data *control_data;
@@ -2222,6 +2252,9 @@ static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_contr
22222252
return sof_ipc4_control_load_volume(sdev, scontrol);
22232253
case SND_SOC_TPLG_CTL_BYTES:
22242254
return sof_ipc4_control_load_bytes(sdev, scontrol);
2255+
case SND_SOC_TPLG_CTL_ENUM:
2256+
case SND_SOC_TPLG_CTL_ENUM_VALUE:
2257+
return sof_ipc4_control_load_enum(sdev, scontrol);
22252258
default:
22262259
break;
22272260
}

0 commit comments

Comments
 (0)