From 0a1b4265364177c7e61247b850ee56dbd65838a5 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Fri, 19 Jan 2024 04:47:25 +0800 Subject: [PATCH 1/4] 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 --- src/audio/volume/volume_ipc4.c | 85 ++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 14 deletions(-) diff --git a/src/audio/volume/volume_ipc4.c b/src/audio/volume/volume_ipc4.c index b47a3f8410b3..d12eed346d77 100644 --- a/src/audio/volume/volume_ipc4.c +++ b/src/audio/volume/volume_ipc4.c @@ -54,10 +54,6 @@ static int set_volume_ipc4(struct vol_data *cd, uint32_t const channel, cd->tvolume[channel] = target_volume; /* init ramp start volume*/ 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 */ 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], vol->config[channel_cfg].curve_type, 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]); @@ -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) { for (i = 0; i < channels_count; i++) { - set_volume_ipc4(cd, i, cdata.target_volume, - cdata.curve_type, - cdata.curve_duration); - - volume_set_chan(mod, i, cd->tvolume[i], true); + if (cd->muted[i]) { + cd->mvolume[i] = cdata.target_volume; + } else { + set_volume_ipc4(cd, i, cdata.target_volume, + cdata.curve_type, + cdata.curve_duration); + + volume_set_chan(mod, i, cd->tvolume[i], true); + } if (cd->volume[i] != cd->tvolume[i]) cd->ramp_finished = false; } } else { - set_volume_ipc4(cd, cdata.channel_id, cdata.target_volume, - cdata.curve_type, - cdata.curve_duration); + if (cd->muted[cdata.channel_id]) { + cd->mvolume[cdata.channel_id] = cdata.target_volume; + } 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], - true); + volume_set_chan(mod, cdata.channel_id, + cd->tvolume[cdata.channel_id], true); + } if (cd->volume[cdata.channel_id] != cd->tvolume[cdata.channel_id]) cd->ramp_finished = false; } @@ -297,6 +305,53 @@ static int volume_set_attenuation(struct processing_module *mod, const uint8_t * 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, enum module_cfg_fragment_position pos, uint32_t data_offset_size, 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); case IPC4_SET_ATTENUATION: return volume_set_attenuation(mod, fragment, fragment_size); + case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: + return volume_set_switch(mod, fragment, fragment_size); default: comp_err(dev, "unsupported param %d", config_id); return -EINVAL; From 662f600bf91af08e53e2b3147890dd669fea5d95 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Fri, 19 Jan 2024 04:53:57 +0800 Subject: [PATCH 2/4] topology2: gain: add mixer switch for mute control Add a switch to gain widget for mute control. It could also be used as MIC/SPK mute LED control purpose. Signed-off-by: Brent Lu --- .../topology2/include/components/gain.conf | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tools/topology/topology2/include/components/gain.conf b/tools/topology/topology2/include/components/gain.conf index 3343365880fd..757bcb24ff72 100644 --- a/tools/topology/topology2/include/components/gain.conf +++ b/tools/topology/topology2/include/components/gain.conf @@ -152,6 +152,41 @@ Class.Widget."gain" { } } } + + # mute switch control + mixer."2" { + Object.Base.channel.1 { + name "flw" + reg 2 + shift 0 + } + Object.Base.channel.2 { + name "fl" + reg 2 + shift 1 + } + Object.Base.channel.3 { + name "fr" + reg 2 + shift 2 + } + Object.Base.channel.4 { + name "frw" + reg 2 + shift 3 + } + + Object.Base.ops.1 { + name "ctl" + info "volsw" + ## get = 259 binds the mixer control to switch get/put handlers + get 259 + put 259 + } + + #max 1 indicates switch type control + max 1 + } } # Default attribute values for gain widget From 5373ce75bc0eb0fadf2638b3c5789c3ef93a0f40 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Fri, 19 Jan 2024 04:56:49 +0800 Subject: [PATCH 3/4] topology2: dmic-generic: add switch for LED control Add a mute switch to gain widget for DMIC. Also register this switch as MIC mute LED mixer control on Linux side. Signed-off-by: Brent Lu --- tools/topology/topology2/platform/intel/dmic-generic.conf | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/topology/topology2/platform/intel/dmic-generic.conf b/tools/topology/topology2/platform/intel/dmic-generic.conf index 5ca0ec27c79b..78cc0aeb169f 100644 --- a/tools/topology/topology2/platform/intel/dmic-generic.conf +++ b/tools/topology/topology2/platform/intel/dmic-generic.conf @@ -142,6 +142,12 @@ IncludeByKey.PASSTHROUGH { Object.Control.mixer.1 { name '$DMIC0_PCM_NAME Capture Volume' } + Object.Control.mixer.2 { + name 'Dmic0 Capture Switch' + + mute_led_use 1 + mute_led_direction 1 + } } Object.Widget.module-copier."2" { From 7c73b9aed97fb3598f222a110e3b13d70a90d940 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Fri, 26 Jan 2024 06:08:10 +0800 Subject: [PATCH 4/4] topology2: dmic-generic: rename volume switch The volume switch of gain widget is renamed as 'Dmic0 Capture Volume' for backward compatibility. Signed-off-by: Brent Lu --- tools/topology/topology2/platform/intel/dmic-generic.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/topology/topology2/platform/intel/dmic-generic.conf b/tools/topology/topology2/platform/intel/dmic-generic.conf index 78cc0aeb169f..11fede22cf63 100644 --- a/tools/topology/topology2/platform/intel/dmic-generic.conf +++ b/tools/topology/topology2/platform/intel/dmic-generic.conf @@ -140,7 +140,7 @@ IncludeByKey.PASSTHROUGH { } ] Object.Control.mixer.1 { - name '$DMIC0_PCM_NAME Capture Volume' + name 'Dmic0 Capture Volume' } Object.Control.mixer.2 { name 'Dmic0 Capture Switch'