Skip to content

Commit 3facc04

Browse files
ujfalusigregkh
authored andcommitted
ASoC: SOF: ipc4-control: Add support for ALSA switch control
commit 4a2fd60 upstream. Volume controls with a max value of 1 are switches. Switch 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 f01d8fc commit 3facc04

File tree

2 files changed

+122
-5
lines changed

2 files changed

+122
-5
lines changed

sound/soc/sof/ipc4-control.c

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,102 @@ static int sof_ipc4_volume_get(struct snd_sof_control *scontrol,
201201
return 0;
202202
}
203203

204+
static int
205+
sof_ipc4_set_generic_control_data(struct snd_sof_dev *sdev,
206+
struct snd_sof_widget *swidget,
207+
struct snd_sof_control *scontrol, bool lock)
208+
{
209+
struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
210+
struct sof_ipc4_control_msg_payload *data;
211+
struct sof_ipc4_msg *msg = &cdata->msg;
212+
size_t data_size;
213+
unsigned int i;
214+
int ret;
215+
216+
data_size = struct_size(data, chanv, scontrol->num_channels);
217+
data = kzalloc(data_size, GFP_KERNEL);
218+
if (!data)
219+
return -ENOMEM;
220+
221+
data->id = cdata->index;
222+
data->num_elems = scontrol->num_channels;
223+
for (i = 0; i < scontrol->num_channels; i++) {
224+
data->chanv[i].channel = cdata->chanv[i].channel;
225+
data->chanv[i].value = cdata->chanv[i].value;
226+
}
227+
228+
msg->data_ptr = data;
229+
msg->data_size = data_size;
230+
231+
ret = sof_ipc4_set_get_kcontrol_data(scontrol, true, lock);
232+
msg->data_ptr = NULL;
233+
msg->data_size = 0;
234+
if (ret < 0)
235+
dev_err(sdev->dev, "Failed to set control update for %s\n",
236+
scontrol->name);
237+
238+
kfree(data);
239+
240+
return ret;
241+
}
242+
243+
static bool sof_ipc4_switch_put(struct snd_sof_control *scontrol,
244+
struct snd_ctl_elem_value *ucontrol)
245+
{
246+
struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
247+
struct snd_soc_component *scomp = scontrol->scomp;
248+
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
249+
struct snd_sof_widget *swidget;
250+
bool widget_found = false;
251+
bool change = false;
252+
unsigned int i;
253+
u32 value;
254+
int ret;
255+
256+
/* update each channel */
257+
for (i = 0; i < scontrol->num_channels; i++) {
258+
value = ucontrol->value.integer.value[i];
259+
change = change || (value != cdata->chanv[i].value);
260+
cdata->chanv[i].channel = i;
261+
cdata->chanv[i].value = value;
262+
}
263+
264+
if (!pm_runtime_active(scomp->dev))
265+
return change;
266+
267+
/* find widget associated with the control */
268+
list_for_each_entry(swidget, &sdev->widget_list, list) {
269+
if (swidget->comp_id == scontrol->comp_id) {
270+
widget_found = true;
271+
break;
272+
}
273+
}
274+
275+
if (!widget_found) {
276+
dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
277+
return false;
278+
}
279+
280+
ret = sof_ipc4_set_generic_control_data(sdev, swidget, scontrol, true);
281+
if (ret < 0)
282+
return false;
283+
284+
return change;
285+
}
286+
287+
static int sof_ipc4_switch_get(struct snd_sof_control *scontrol,
288+
struct snd_ctl_elem_value *ucontrol)
289+
{
290+
struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
291+
unsigned int i;
292+
293+
/* read back each channel */
294+
for (i = 0; i < scontrol->num_channels; i++)
295+
ucontrol->value.integer.value[i] = cdata->chanv[i].value;
296+
297+
return 0;
298+
}
299+
204300
static int sof_ipc4_set_get_bytes_data(struct snd_sof_dev *sdev,
205301
struct snd_sof_control *scontrol,
206302
bool set, bool lock)
@@ -438,6 +534,16 @@ static int sof_ipc4_bytes_ext_volatile_get(struct snd_sof_control *scontrol,
438534
return _sof_ipc4_bytes_ext_get(scontrol, binary_data, size, true);
439535
}
440536

537+
static int
538+
sof_ipc4_volsw_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
539+
struct snd_sof_control *scontrol)
540+
{
541+
if (scontrol->max == 1)
542+
return sof_ipc4_set_generic_control_data(sdev, swidget, scontrol, false);
543+
544+
return sof_ipc4_set_volume_data(sdev, swidget, scontrol, false);
545+
}
546+
441547
/* set up all controls for the widget */
442548
static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
443549
{
@@ -450,8 +556,7 @@ static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_s
450556
case SND_SOC_TPLG_CTL_VOLSW:
451557
case SND_SOC_TPLG_CTL_VOLSW_SX:
452558
case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
453-
ret = sof_ipc4_set_volume_data(sdev, swidget,
454-
scontrol, false);
559+
ret = sof_ipc4_volsw_setup(sdev, swidget, scontrol);
455560
break;
456561
case SND_SOC_TPLG_CTL_BYTES:
457562
ret = sof_ipc4_set_get_bytes_data(sdev, scontrol,
@@ -498,6 +603,8 @@ sof_ipc4_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_I
498603
const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = {
499604
.volume_put = sof_ipc4_volume_put,
500605
.volume_get = sof_ipc4_volume_get,
606+
.switch_put = sof_ipc4_switch_put,
607+
.switch_get = sof_ipc4_switch_get,
501608
.bytes_put = sof_ipc4_bytes_put,
502609
.bytes_get = sof_ipc4_bytes_get,
503610
.bytes_ext_put = sof_ipc4_bytes_ext_put,

sound/soc/sof/ipc4-topology.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2127,12 +2127,22 @@ static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof
21272127
msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
21282128
msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
21292129

2130-
msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID);
2130+
/* volume controls with range 0-1 (off/on) are switch controls */
2131+
if (scontrol->max == 1)
2132+
msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_SWITCH_CONTROL_PARAM_ID);
2133+
else
2134+
msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID);
21312135

2132-
/* set default volume values to 0dB in control */
21332136
for (i = 0; i < scontrol->num_channels; i++) {
21342137
control_data->chanv[i].channel = i;
2135-
control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB;
2138+
/*
2139+
* Default, initial values:
2140+
* - 0dB for volume controls
2141+
* - off (0) for switch controls - value already zero after
2142+
* memory allocation
2143+
*/
2144+
if (scontrol->max > 1)
2145+
control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB;
21362146
}
21372147

21382148
return 0;

0 commit comments

Comments
 (0)