audio: volume: support switch control

Implement function to support SOF_IPC4_SWITCH_CONTROL_PARAM_ID in
set_configuration callback. Linux side could use this switch control
to mute/unmute a gain widget.

Signed-off-by: Brent Lu <brent.lu@intel.com>
This commit is contained in:
Brent Lu 2024-01-19 04:47:25 +08:00 committed by Liam Girdwood
parent a25c70e183
commit f9bcf61b9a
1 changed files with 70 additions and 13 deletions

View File

@ -54,10 +54,6 @@ static int set_volume_ipc4(struct vol_data *cd, uint32_t const channel,
cd->tvolume[channel] = target_volume; cd->tvolume[channel] = target_volume;
/* init ramp start volume*/ /* init ramp start volume*/
cd->rvolume[channel] = 0; cd->rvolume[channel] = 0;
/* init muted volume */
cd->mvolume[channel] = 0;
/* set muted as false*/
cd->muted[channel] = false;
/* ATM there is support for the same ramp for all channels */ /* ATM there is support for the same ramp for all channels */
cd->ramp_type = ipc4_curve_type_convert((enum ipc4_curve_type)curve_type); cd->ramp_type = ipc4_curve_type_convert((enum ipc4_curve_type)curve_type);
@ -164,6 +160,9 @@ int volume_init(struct processing_module *mod)
target_volume[channel_cfg], target_volume[channel_cfg],
vol->config[channel_cfg].curve_type, vol->config[channel_cfg].curve_type,
vol->config[channel_cfg].curve_duration); vol->config[channel_cfg].curve_duration);
/* set muted as false*/
cd->muted[channel] = false;
} }
init_ramp(cd, vol->config[0].curve_duration, target_volume[0]); init_ramp(cd, vol->config[0].curve_duration, target_volume[0]);
@ -224,21 +223,30 @@ static int volume_set_volume(struct processing_module *mod, const uint8_t *data,
if (cdata.channel_id == IPC4_ALL_CHANNELS_MASK) { if (cdata.channel_id == IPC4_ALL_CHANNELS_MASK) {
for (i = 0; i < channels_count; i++) { for (i = 0; i < channels_count; i++) {
set_volume_ipc4(cd, i, cdata.target_volume, if (cd->muted[i]) {
cdata.curve_type, cd->mvolume[i] = cdata.target_volume;
cdata.curve_duration); } else {
set_volume_ipc4(cd, i, cdata.target_volume,
cdata.curve_type,
cdata.curve_duration);
volume_set_chan(mod, i, cd->tvolume[i], true); volume_set_chan(mod, i, cd->tvolume[i], true);
}
if (cd->volume[i] != cd->tvolume[i]) if (cd->volume[i] != cd->tvolume[i])
cd->ramp_finished = false; cd->ramp_finished = false;
} }
} else { } else {
set_volume_ipc4(cd, cdata.channel_id, cdata.target_volume, if (cd->muted[cdata.channel_id]) {
cdata.curve_type, cd->mvolume[cdata.channel_id] = cdata.target_volume;
cdata.curve_duration); } else {
set_volume_ipc4(cd, cdata.channel_id,
cdata.target_volume,
cdata.curve_type,
cdata.curve_duration);
volume_set_chan(mod, cdata.channel_id, cd->tvolume[cdata.channel_id], volume_set_chan(mod, cdata.channel_id,
true); cd->tvolume[cdata.channel_id], true);
}
if (cd->volume[cdata.channel_id] != cd->tvolume[cdata.channel_id]) if (cd->volume[cdata.channel_id] != cd->tvolume[cdata.channel_id])
cd->ramp_finished = false; cd->ramp_finished = false;
} }
@ -297,6 +305,53 @@ static int volume_set_attenuation(struct processing_module *mod, const uint8_t *
return 0; return 0;
} }
static int volume_set_switch(struct processing_module *mod, const uint8_t *data,
int data_size)
{
struct vol_data *cd = module_get_private_data(mod);
struct comp_dev *dev = mod->dev;
struct sof_ipc4_control_msg_payload *ctl;
unsigned int channels_count, num_elems;
unsigned int i, val;
if (data_size < sizeof(struct sof_ipc4_control_msg_payload)) {
comp_err(dev, "error: data_size %d should be bigger than %d", data_size,
sizeof(struct sof_ipc4_control_msg_payload));
return -EINVAL;
}
ctl = (struct sof_ipc4_control_msg_payload *)data;
cd->ramp_finished = true;
channels_count = mod->priv.cfg.base_cfg.audio_fmt.channels_count;
if (channels_count > SOF_IPC_MAX_CHANNELS) {
comp_err(dev, "Invalid channels count %u", channels_count);
return -EINVAL;
}
num_elems = ctl->num_elems;
if (num_elems > channels_count) {
comp_warn(dev, "limit num_elems %d to %d", num_elems, channels_count);
num_elems = channels_count;
}
for (i = 0; i < num_elems; i++) {
val = ctl->chanv[i].value;
comp_dbg(dev, "channel %i, value %u", i, val);
if (val)
volume_set_chan_unmute(mod, i);
else
volume_set_chan_mute(mod, i);
if (cd->volume[i] != cd->tvolume[i])
cd->ramp_finished = false;
}
return 0;
}
int volume_set_config(struct processing_module *mod, uint32_t config_id, int volume_set_config(struct processing_module *mod, uint32_t config_id,
enum module_cfg_fragment_position pos, uint32_t data_offset_size, enum module_cfg_fragment_position pos, uint32_t data_offset_size,
const uint8_t *fragment, size_t fragment_size, uint8_t *response, const uint8_t *fragment, size_t fragment_size, uint8_t *response,
@ -321,6 +376,8 @@ int volume_set_config(struct processing_module *mod, uint32_t config_id,
return volume_set_volume(mod, fragment, fragment_size); return volume_set_volume(mod, fragment, fragment_size);
case IPC4_SET_ATTENUATION: case IPC4_SET_ATTENUATION:
return volume_set_attenuation(mod, fragment, fragment_size); return volume_set_attenuation(mod, fragment, fragment_size);
case SOF_IPC4_SWITCH_CONTROL_PARAM_ID:
return volume_set_switch(mod, fragment, fragment_size);
default: default:
comp_err(dev, "unsupported param %d", config_id); comp_err(dev, "unsupported param %d", config_id);
return -EINVAL; return -EINVAL;