Files
linux/sound/soc/intel/avs/control.c
Amadeusz Sławiński be2b81b519 ASoC: Intel: avs: Parse control tuples
Add callback to handle loading of kcontrol and linking it to active
widget. In order to link kcontrol to specific modules add additional
field to module data, as well as specify control id in kcontrol data.

Co-authored-by: Cezary Rojewski <cezary.rojewski@intel.com>
Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Link: https://lore.kernel.org/r/20221214185500.3896902-4-amadeuszx.slawinski@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2022-12-25 23:33:03 +00:00

106 lines
3.0 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
//
// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
//
// Authors: Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
// Cezary Rojewski <cezary.rojewski@intel.com>
//
#include <sound/soc.h>
#include "avs.h"
#include "control.h"
#include "messages.h"
#include "path.h"
static struct avs_dev *avs_get_kcontrol_adev(struct snd_kcontrol *kcontrol)
{
struct snd_soc_dapm_widget *w;
w = snd_soc_dapm_kcontrol_widget(kcontrol);
return to_avs_dev(w->dapm->component->dev);
}
static struct avs_path_module *avs_get_kcontrol_module(struct avs_dev *adev, u32 id)
{
struct avs_path *path;
struct avs_path_pipeline *ppl;
struct avs_path_module *mod;
list_for_each_entry(path, &adev->path_list, node)
list_for_each_entry(ppl, &path->ppl_list, node)
list_for_each_entry(mod, &ppl->mod_list, node)
if (mod->template->ctl_id && mod->template->ctl_id == id)
return mod;
return NULL;
}
int avs_control_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
struct avs_control_data *ctl_data = (struct avs_control_data *)mc->dobj.private;
struct avs_dev *adev = avs_get_kcontrol_adev(kcontrol);
struct avs_volume_cfg *dspvols = NULL;
struct avs_path_module *active_module;
size_t num_dspvols;
int ret = 0;
/* prevent access to modules while path is being constructed */
mutex_lock(&adev->path_mutex);
active_module = avs_get_kcontrol_module(adev, ctl_data->id);
if (active_module) {
ret = avs_ipc_peakvol_get_volume(adev, active_module->module_id,
active_module->instance_id, &dspvols,
&num_dspvols);
if (!ret)
ucontrol->value.integer.value[0] = dspvols[0].target_volume;
ret = AVS_IPC_RET(ret);
kfree(dspvols);
} else {
ucontrol->value.integer.value[0] = ctl_data->volume;
}
mutex_unlock(&adev->path_mutex);
return ret;
}
int avs_control_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
struct avs_control_data *ctl_data = (struct avs_control_data *)mc->dobj.private;
struct avs_dev *adev = avs_get_kcontrol_adev(kcontrol);
long *volume = &ctl_data->volume;
struct avs_path_module *active_module;
struct avs_volume_cfg dspvol = {0};
long ctlvol = ucontrol->value.integer.value[0];
int ret = 0, changed = 0;
if (ctlvol < 0 || ctlvol > mc->max)
return -EINVAL;
/* prevent access to modules while path is being constructed */
mutex_lock(&adev->path_mutex);
if (*volume != ctlvol) {
*volume = ctlvol;
changed = 1;
}
active_module = avs_get_kcontrol_module(adev, ctl_data->id);
if (active_module) {
dspvol.channel_id = AVS_ALL_CHANNELS_MASK;
dspvol.target_volume = *volume;
ret = avs_ipc_peakvol_set_volume(adev, active_module->module_id,
active_module->instance_id, &dspvol);
ret = AVS_IPC_RET(ret);
}
mutex_unlock(&adev->path_mutex);
return ret ? ret : changed;
}