1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/pm_runtime.h>
14#include <linux/leds.h>
15#include "sof-priv.h"
16#include "sof-audio.h"
17
18static 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
48int 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
63int 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
78int 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
100int 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
115int 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
133int 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
148int 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
163int 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
178int 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
193int 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
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
213int 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
241int 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