1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright(c) 2021-2022 Intel Corporation 4 // 5 // Authors: Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> 6 // Cezary Rojewski <cezary.rojewski@intel.com> 7 // 8 9 #include <linux/cleanup.h> 10 #include <sound/soc.h> 11 #include "avs.h" 12 #include "control.h" 13 #include "messages.h" 14 #include "path.h" 15 16 static struct avs_dev *avs_get_kcontrol_adev(struct snd_kcontrol *kcontrol) 17 { 18 struct snd_soc_dapm_widget *w; 19 20 w = snd_soc_dapm_kcontrol_widget(kcontrol); 21 22 return to_avs_dev(w->dapm->component->dev); 23 } 24 25 static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 id) 26 { 27 struct avs_path *path; 28 struct avs_path_pipeline *ppl; 29 struct avs_path_module *mod; 30 31 spin_lock(&adev->path_list_lock); 32 list_for_each_entry(path, &adev->path_list, node) { 33 list_for_each_entry(ppl, &path->ppl_list, node) { 34 list_for_each_entry(mod, &ppl->mod_list, node) { 35 guid_t *type = &mod->template->cfg_ext->type; 36 37 if ((guid_equal(type, &AVS_PEAKVOL_MOD_UUID) || 38 guid_equal(type, &AVS_GAIN_MOD_UUID)) && 39 mod->template->ctl_id == id) { 40 spin_unlock(&adev->path_list_lock); 41 return mod; 42 } 43 } 44 } 45 } 46 spin_unlock(&adev->path_list_lock); 47 48 return NULL; 49 } 50 51 int avs_control_volume_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl) 52 { 53 struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; 54 struct avs_control_data *ctl_data = mc->dobj.private; 55 struct avs_path_module *active_module; 56 struct avs_volume_cfg *dspvols; 57 struct avs_dev *adev; 58 size_t num_dspvols; 59 int ret, i; 60 61 adev = avs_get_kcontrol_adev(kctl); 62 63 /* Prevent access to modules while path is being constructed. */ 64 guard(mutex)(&adev->path_mutex); 65 66 active_module = avs_get_volume_module(adev, ctl_data->id); 67 if (active_module) { 68 ret = avs_ipc_peakvol_get_volume(adev, active_module->module_id, 69 active_module->instance_id, &dspvols, 70 &num_dspvols); 71 if (ret) 72 return AVS_IPC_RET(ret); 73 74 /* Do not copy more than the control can store. */ 75 num_dspvols = min_t(u32, num_dspvols, SND_SOC_TPLG_MAX_CHAN); 76 for (i = 0; i < num_dspvols; i++) 77 ctl_data->values[i] = dspvols[i].target_volume; 78 kfree(dspvols); 79 } 80 81 memcpy(uctl->value.integer.value, ctl_data->values, sizeof(ctl_data->values)); 82 return 0; 83 } 84 85 int avs_control_volume_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl) 86 { 87 struct avs_path_module *active_module; 88 struct avs_control_data *ctl_data; 89 struct soc_mixer_control *mc; 90 struct avs_dev *adev; 91 long *input; 92 int ret, i; 93 94 mc = (struct soc_mixer_control *)kctl->private_value; 95 ctl_data = mc->dobj.private; 96 adev = avs_get_kcontrol_adev(kctl); 97 input = uctl->value.integer.value; 98 i = 0; 99 100 /* mc->num_channels can be 0. */ 101 do { 102 if (input[i] < mc->min || input[i] > mc->max) 103 return -EINVAL; 104 } while (++i < mc->num_channels); 105 106 if (!memcmp(ctl_data->values, input, sizeof(ctl_data->values))) 107 return 0; 108 109 /* Prevent access to modules while path is being constructed. */ 110 guard(mutex)(&adev->path_mutex); 111 112 active_module = avs_get_volume_module(adev, ctl_data->id); 113 if (active_module) { 114 ret = avs_peakvol_set_volume(adev, active_module, mc, input); 115 if (ret) 116 return ret; 117 } 118 119 memcpy(ctl_data->values, input, sizeof(ctl_data->values)); 120 return 1; 121 } 122 123 int avs_control_volume_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) 124 { 125 struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; 126 127 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 128 uinfo->count = max_t(u32, 1, mc->num_channels); 129 uinfo->value.integer.min = 0; 130 uinfo->value.integer.max = mc->max; 131 return 0; 132 } 133 134 int avs_control_mute_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl) 135 { 136 struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; 137 struct avs_control_data *ctl_data = mc->dobj.private; 138 struct avs_path_module *active_module; 139 struct avs_mute_cfg *dspmutes; 140 struct avs_dev *adev; 141 size_t num_dspmutes; 142 int ret, i; 143 144 adev = avs_get_kcontrol_adev(kctl); 145 146 /* Prevent access to modules while path is being constructed. */ 147 guard(mutex)(&adev->path_mutex); 148 149 active_module = avs_get_volume_module(adev, ctl_data->id); 150 if (active_module) { 151 ret = avs_ipc_peakvol_get_mute(adev, active_module->module_id, 152 active_module->instance_id, &dspmutes, 153 &num_dspmutes); 154 if (ret) 155 return AVS_IPC_RET(ret); 156 157 /* Do not copy more than the control can store. */ 158 num_dspmutes = min_t(u32, num_dspmutes, SND_SOC_TPLG_MAX_CHAN); 159 for (i = 0; i < num_dspmutes; i++) 160 ctl_data->values[i] = !dspmutes[i].mute; 161 kfree(dspmutes); 162 } 163 164 memcpy(uctl->value.integer.value, ctl_data->values, sizeof(ctl_data->values)); 165 return 0; 166 } 167 168 int avs_control_mute_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl) 169 { 170 struct avs_path_module *active_module; 171 struct avs_control_data *ctl_data; 172 struct soc_mixer_control *mc; 173 struct avs_dev *adev; 174 long *input; 175 int ret, i; 176 177 mc = (struct soc_mixer_control *)kctl->private_value; 178 ctl_data = mc->dobj.private; 179 adev = avs_get_kcontrol_adev(kctl); 180 input = uctl->value.integer.value; 181 i = 0; 182 183 /* mc->num_channels can be 0. */ 184 do { 185 if (input[i] < mc->min || input[i] > mc->max) 186 return -EINVAL; 187 } while (++i < mc->num_channels); 188 189 if (!memcmp(ctl_data->values, input, sizeof(ctl_data->values))) 190 return 0; 191 192 /* Prevent access to modules while path is being constructed. */ 193 guard(mutex)(&adev->path_mutex); 194 195 active_module = avs_get_volume_module(adev, ctl_data->id); 196 if (active_module) { 197 ret = avs_peakvol_set_mute(adev, active_module, mc, input); 198 if (ret) 199 return ret; 200 } 201 202 memcpy(ctl_data->values, input, sizeof(ctl_data->values)); 203 return 1; 204 } 205 206 int avs_control_mute_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) 207 { 208 struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; 209 210 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 211 uinfo->count = max_t(u32, 1, mc->num_channels); 212 uinfo->value.integer.min = 0; 213 uinfo->value.integer.max = mc->max; 214 return 0; 215 } 216