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
avs_get_kcontrol_adev(struct snd_kcontrol * kcontrol)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
avs_get_volume_module(struct avs_dev * adev,u32 id)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
avs_control_volume_get(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * uctl)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
avs_control_volume_put(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * uctl)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
avs_control_volume_info(struct snd_kcontrol * kctl,struct snd_ctl_elem_info * uinfo)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
avs_control_mute_get(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * uctl)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
avs_control_mute_put(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * uctl)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
avs_control_mute_info(struct snd_kcontrol * kctl,struct snd_ctl_elem_info * uinfo)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