xref: /openbmc/linux/sound/soc/sof/control.c (revision 7a2f6f61)
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 //
3 // This file is provided under a dual BSD/GPLv2 license.  When using or
4 // redistributing this file, you may do so under either license.
5 //
6 // Copyright(c) 2018 Intel Corporation. All rights reserved.
7 //
8 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9 //
10 
11 /* Mixer Controls */
12 
13 #include <linux/pm_runtime.h>
14 #include <linux/leds.h>
15 #include "sof-priv.h"
16 #include "sof-audio.h"
17 
18 static void update_mute_led(struct snd_sof_control *scontrol,
19 			    struct snd_kcontrol *kcontrol,
20 			    struct snd_ctl_elem_value *ucontrol)
21 {
22 	int temp = 0;
23 	int mask;
24 	int i;
25 
26 	mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
27 
28 	for (i = 0; i < scontrol->num_channels; i++) {
29 		if (ucontrol->value.integer.value[i]) {
30 			temp |= mask;
31 			break;
32 		}
33 	}
34 
35 	if (temp == scontrol->led_ctl.led_value)
36 		return;
37 
38 	scontrol->led_ctl.led_value = temp;
39 
40 #if IS_REACHABLE(CONFIG_LEDS_TRIGGER_AUDIO)
41 	if (!scontrol->led_ctl.direction)
42 		ledtrig_audio_set(LED_AUDIO_MUTE, temp ? LED_OFF : LED_ON);
43 	else
44 		ledtrig_audio_set(LED_AUDIO_MICMUTE, temp ? LED_OFF : LED_ON);
45 #endif
46 }
47 
48 int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
49 		       struct snd_ctl_elem_value *ucontrol)
50 {
51 	struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
52 	struct snd_sof_control *scontrol = sm->dobj.private;
53 	struct snd_soc_component *scomp = scontrol->scomp;
54 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
55 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
56 
57 	if (tplg_ops->control->volume_get)
58 		return tplg_ops->control->volume_get(scontrol, ucontrol);
59 
60 	return 0;
61 }
62 
63 int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
64 		       struct snd_ctl_elem_value *ucontrol)
65 {
66 	struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
67 	struct snd_sof_control *scontrol = sm->dobj.private;
68 	struct snd_soc_component *scomp = scontrol->scomp;
69 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
70 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
71 
72 	if (tplg_ops->control->volume_put)
73 		return tplg_ops->control->volume_put(scontrol, ucontrol);
74 
75 	return false;
76 }
77 
78 int snd_sof_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
79 {
80 	struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
81 	struct snd_sof_control *scontrol = sm->dobj.private;
82 	unsigned int channels = scontrol->num_channels;
83 	int platform_max;
84 
85 	if (!sm->platform_max)
86 		sm->platform_max = sm->max;
87 	platform_max = sm->platform_max;
88 
89 	if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume"))
90 		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
91 	else
92 		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
93 
94 	uinfo->count = channels;
95 	uinfo->value.integer.min = 0;
96 	uinfo->value.integer.max = platform_max - sm->min;
97 	return 0;
98 }
99 
100 int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
101 		       struct snd_ctl_elem_value *ucontrol)
102 {
103 	struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
104 	struct snd_sof_control *scontrol = sm->dobj.private;
105 	struct snd_soc_component *scomp = scontrol->scomp;
106 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
107 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
108 
109 	if (tplg_ops->control->switch_get)
110 		return tplg_ops->control->switch_get(scontrol, ucontrol);
111 
112 	return 0;
113 }
114 
115 int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
116 		       struct snd_ctl_elem_value *ucontrol)
117 {
118 	struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
119 	struct snd_sof_control *scontrol = sm->dobj.private;
120 	struct snd_soc_component *scomp = scontrol->scomp;
121 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
122 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
123 
124 	if (scontrol->led_ctl.use_led)
125 		update_mute_led(scontrol, kcontrol, ucontrol);
126 
127 	if (tplg_ops->control->switch_put)
128 		return tplg_ops->control->switch_put(scontrol, ucontrol);
129 
130 	return false;
131 }
132 
133 int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
134 		     struct snd_ctl_elem_value *ucontrol)
135 {
136 	struct soc_enum *se = (struct soc_enum *)kcontrol->private_value;
137 	struct snd_sof_control *scontrol = se->dobj.private;
138 	struct snd_soc_component *scomp = scontrol->scomp;
139 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
140 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
141 
142 	if (tplg_ops->control->enum_get)
143 		return tplg_ops->control->enum_get(scontrol, ucontrol);
144 
145 	return 0;
146 }
147 
148 int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
149 		     struct snd_ctl_elem_value *ucontrol)
150 {
151 	struct soc_enum *se = (struct soc_enum *)kcontrol->private_value;
152 	struct snd_sof_control *scontrol = se->dobj.private;
153 	struct snd_soc_component *scomp = scontrol->scomp;
154 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
155 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
156 
157 	if (tplg_ops->control->enum_put)
158 		return tplg_ops->control->enum_put(scontrol, ucontrol);
159 
160 	return false;
161 }
162 
163 int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
164 		      struct snd_ctl_elem_value *ucontrol)
165 {
166 	struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
167 	struct snd_sof_control *scontrol = be->dobj.private;
168 	struct snd_soc_component *scomp = scontrol->scomp;
169 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
170 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
171 
172 	if (tplg_ops->control->bytes_get)
173 		return tplg_ops->control->bytes_get(scontrol, ucontrol);
174 
175 	return 0;
176 }
177 
178 int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
179 		      struct snd_ctl_elem_value *ucontrol)
180 {
181 	struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
182 	struct snd_sof_control *scontrol = be->dobj.private;
183 	struct snd_soc_component *scomp = scontrol->scomp;
184 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
185 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
186 
187 	if (tplg_ops->control->bytes_put)
188 		return tplg_ops->control->bytes_put(scontrol, ucontrol);
189 
190 	return 0;
191 }
192 
193 int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
194 			  const unsigned int __user *binary_data,
195 			  unsigned int size)
196 {
197 	struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
198 	struct snd_sof_control *scontrol = be->dobj.private;
199 	struct snd_soc_component *scomp = scontrol->scomp;
200 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
201 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
202 
203 	/* make sure we have at least a header */
204 	if (size < sizeof(struct snd_ctl_tlv))
205 		return -EINVAL;
206 
207 	if (tplg_ops->control->bytes_ext_put)
208 		return tplg_ops->control->bytes_ext_put(scontrol, binary_data, size);
209 
210 	return 0;
211 }
212 
213 int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int __user *binary_data,
214 				   unsigned int size)
215 {
216 	struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
217 	struct snd_sof_control *scontrol = be->dobj.private;
218 	struct snd_soc_component *scomp = scontrol->scomp;
219 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
220 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
221 	int ret, err;
222 
223 	ret = pm_runtime_get_sync(scomp->dev);
224 	if (ret < 0 && ret != -EACCES) {
225 		dev_err_ratelimited(scomp->dev, "%s: failed to resume %d\n", __func__, ret);
226 		pm_runtime_put_noidle(scomp->dev);
227 		return ret;
228 	}
229 
230 	if (tplg_ops->control->bytes_ext_volatile_get)
231 		ret = tplg_ops->control->bytes_ext_volatile_get(scontrol, binary_data, size);
232 
233 	pm_runtime_mark_last_busy(scomp->dev);
234 	err = pm_runtime_put_autosuspend(scomp->dev);
235 	if (err < 0)
236 		dev_err_ratelimited(scomp->dev, "%s: failed to idle %d\n", __func__, err);
237 
238 	return ret;
239 }
240 
241 int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
242 			  unsigned int __user *binary_data,
243 			  unsigned int size)
244 {
245 	struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
246 	struct snd_sof_control *scontrol = be->dobj.private;
247 	struct snd_soc_component *scomp = scontrol->scomp;
248 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
249 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
250 
251 	if (tplg_ops->control->bytes_ext_get)
252 		return tplg_ops->control->bytes_ext_get(scontrol, binary_data, size);
253 
254 	return 0;
255 }
256