Unverified Commit a4217a03 authored by Amadeusz Sławiński's avatar Amadeusz Sławiński Committed by Mark Brown
Browse files

ASoC: Intel: avs: Add support for mute for PEAKVOL and GAIN



With recent updates to AudioDSP firmware, mute functionality has been
added to PEAKVOL and GAIN modules. The operation occurs over IPC
similarly to how volume is configured. Wire it up to kcontrol
infrastructure present in the avs-driver.

Signed-off-by: default avatarAmadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: default avatarCezary Rojewski <cezary.rojewski@intel.com>
Link: https://patch.msgid.link/20250217102115.3539427-9-cezary.rojewski@intel.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 4c32ebcc
Loading
Loading
Loading
Loading
+83 −0
Original line number Diff line number Diff line
@@ -130,3 +130,86 @@ int avs_control_volume_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info
	uinfo->value.integer.max = mc->max;
	return 0;
}

int avs_control_mute_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl)
{
	struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
	struct avs_control_data *ctl_data = mc->dobj.private;
	struct avs_path_module *active_module;
	struct avs_mute_cfg *dspmutes;
	struct avs_dev *adev;
	size_t num_dspmutes;
	int ret, i;

	adev = avs_get_kcontrol_adev(kctl);

	/* Prevent access to modules while path is being constructed. */
	guard(mutex)(&adev->path_mutex);

	active_module = avs_get_volume_module(adev, ctl_data->id);
	if (active_module) {
		ret = avs_ipc_peakvol_get_mute(adev, active_module->module_id,
					       active_module->instance_id, &dspmutes,
					       &num_dspmutes);
		if (ret)
			return AVS_IPC_RET(ret);

		/* Do not copy more than the control can store. */
		num_dspmutes = min_t(u32, num_dspmutes, SND_SOC_TPLG_MAX_CHAN);
		for (i = 0; i < num_dspmutes; i++)
			ctl_data->values[i] = !dspmutes[i].mute;
		kfree(dspmutes);
	}

	memcpy(uctl->value.integer.value, ctl_data->values, sizeof(ctl_data->values));
	return 0;
}

int avs_control_mute_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl)
{
	struct avs_path_module *active_module;
	struct avs_control_data *ctl_data;
	struct soc_mixer_control *mc;
	struct avs_dev *adev;
	long *input;
	int ret, i;

	mc = (struct soc_mixer_control *)kctl->private_value;
	ctl_data = mc->dobj.private;
	adev = avs_get_kcontrol_adev(kctl);
	input = uctl->value.integer.value;
	i = 0;

	/* mc->num_channels can be 0. */
	do {
		if (input[i] < mc->min || input[i] > mc->max)
			return -EINVAL;
	} while (++i < mc->num_channels);

	if (!memcmp(ctl_data->values, input, sizeof(ctl_data->values)))
		return 0;

	/* Prevent access to modules while path is being constructed. */
	guard(mutex)(&adev->path_mutex);

	active_module = avs_get_volume_module(adev, ctl_data->id);
	if (active_module) {
		ret = avs_peakvol_set_mute(adev, active_module, mc, input);
		if (ret)
			return ret;
	}

	memcpy(ctl_data->values, input, sizeof(ctl_data->values));
	return 1;
}

int avs_control_mute_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
{
	struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;

	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
	uinfo->count = max_t(u32, 1, mc->num_channels);
	uinfo->value.integer.min = 0;
	uinfo->value.integer.max = mc->max;
	return 0;
}
+3 −0
Original line number Diff line number Diff line
@@ -20,5 +20,8 @@ struct avs_control_data {
int avs_control_volume_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl);
int avs_control_volume_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl);
int avs_control_volume_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo);
int avs_control_mute_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl);
int avs_control_mute_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl);
int avs_control_mute_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo);

#endif
+36 −0
Original line number Diff line number Diff line
@@ -359,6 +359,42 @@ int avs_peakvol_set_volume(struct avs_dev *adev, struct avs_path_module *mod,
	return AVS_IPC_RET(ret);
}

int avs_peakvol_set_mute(struct avs_dev *adev, struct avs_path_module *mod,
			 struct soc_mixer_control *mc, long *input)
{
	struct avs_mute_cfg mutes[SND_SOC_TPLG_MAX_CHAN] = {{0}};
	struct avs_control_data *ctl_data;
	struct avs_tplg_module *t;
	int ret, i;

	ctl_data = mc->dobj.private;
	t = mod->template;
	if (!input)
		input = ctl_data->values;

	if (mc->num_channels) {
		for (i = 0; i < mc->num_channels; i++) {
			mutes[i].channel_id = i;
			mutes[i].mute = !input[i];
			mutes[i].curve_type = t->cfg_ext->peakvol.curve_type;
			mutes[i].curve_duration = t->cfg_ext->peakvol.curve_duration;
		}

		ret = avs_ipc_peakvol_set_mutes(adev, mod->module_id, mod->instance_id, mutes,
						mc->num_channels);
		return AVS_IPC_RET(ret);
	}

	/* Target all channels if no individual selected. */
	mutes[0].channel_id = AVS_ALL_CHANNELS_MASK;
	mutes[0].mute = !input[0];
	mutes[0].curve_type = t->cfg_ext->peakvol.curve_type;
	mutes[0].curve_duration = t->cfg_ext->peakvol.curve_duration;

	ret = avs_ipc_peakvol_set_mute(adev, mod->module_id, mod->instance_id, &mutes[0]);
	return AVS_IPC_RET(ret);
}

static int avs_peakvol_create(struct avs_dev *adev, struct avs_path_module *mod)
{
	struct avs_tplg_module *t = mod->template;
+2 −0
Original line number Diff line number Diff line
@@ -71,5 +71,7 @@ int avs_path_run(struct avs_path *path, int trigger);

int avs_peakvol_set_volume(struct avs_dev *adev, struct avs_path_module *mod,
			   struct soc_mixer_control *mc, long *input);
int avs_peakvol_set_mute(struct avs_dev *adev, struct avs_path_module *mod,
			 struct soc_mixer_control *mc, long *input);

#endif
+10 −1
Original line number Diff line number Diff line
@@ -1905,7 +1905,10 @@ static int avs_manifest(struct snd_soc_component *comp, int index,
	return 0;
}

#define AVS_CONTROL_OPS_VOLUME	257
enum {
	AVS_CONTROL_OPS_VOLUME = 257,
	AVS_CONTROL_OPS_MUTE,
};

static const struct snd_soc_tplg_kcontrol_ops avs_control_ops[] = {
	{
@@ -1914,6 +1917,12 @@ static const struct snd_soc_tplg_kcontrol_ops avs_control_ops[] = {
		.put = avs_control_volume_put,
		.info = avs_control_volume_info,
	},
	{
		.id = AVS_CONTROL_OPS_MUTE,
		.get = avs_control_mute_get,
		.put = avs_control_mute_put,
		.info = avs_control_mute_info,
	},
};

static const struct avs_tplg_token_parser control_parsers[] = {