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