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