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
18int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
19 struct snd_ctl_elem_value *ucontrol)
20{
21 struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
22 struct snd_sof_control *scontrol = sm->dobj.private;
23 struct snd_soc_component *scomp = scontrol->scomp;
24 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(c: scomp);
25 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
26
27 if (tplg_ops && tplg_ops->control && tplg_ops->control->volume_get)
28 return tplg_ops->control->volume_get(scontrol, ucontrol);
29
30 return 0;
31}
32
33int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
34 struct snd_ctl_elem_value *ucontrol)
35{
36 struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
37 struct snd_sof_control *scontrol = sm->dobj.private;
38 struct snd_soc_component *scomp = scontrol->scomp;
39 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(c: scomp);
40 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
41
42 if (tplg_ops && tplg_ops->control && tplg_ops->control->volume_put)
43 return tplg_ops->control->volume_put(scontrol, ucontrol);
44
45 return false;
46}
47
48int snd_sof_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
49{
50 struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
51 struct snd_sof_control *scontrol = sm->dobj.private;
52 unsigned int channels = scontrol->num_channels;
53 int platform_max;
54
55 if (!sm->platform_max)
56 sm->platform_max = sm->max;
57 platform_max = sm->platform_max;
58
59 if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume"))
60 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
61 else
62 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
63
64 uinfo->count = channels;
65 uinfo->value.integer.min = 0;
66 uinfo->value.integer.max = platform_max - sm->min;
67 return 0;
68}
69
70int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
71 struct snd_ctl_elem_value *ucontrol)
72{
73 struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
74 struct snd_sof_control *scontrol = sm->dobj.private;
75 struct snd_soc_component *scomp = scontrol->scomp;
76 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(c: scomp);
77 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
78
79 if (tplg_ops && tplg_ops->control && tplg_ops->control->switch_get)
80 return tplg_ops->control->switch_get(scontrol, ucontrol);
81
82 return 0;
83}
84
85int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
86 struct snd_ctl_elem_value *ucontrol)
87{
88 struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
89 struct snd_sof_control *scontrol = sm->dobj.private;
90 struct snd_soc_component *scomp = scontrol->scomp;
91 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(c: scomp);
92 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
93
94 if (tplg_ops && tplg_ops->control && tplg_ops->control->switch_put)
95 return tplg_ops->control->switch_put(scontrol, ucontrol);
96
97 return false;
98}
99
100int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
101 struct snd_ctl_elem_value *ucontrol)
102{
103 struct soc_enum *se = (struct soc_enum *)kcontrol->private_value;
104 struct snd_sof_control *scontrol = se->dobj.private;
105 struct snd_soc_component *scomp = scontrol->scomp;
106 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(c: scomp);
107 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
108
109 if (tplg_ops && tplg_ops->control && tplg_ops->control->enum_get)
110 return tplg_ops->control->enum_get(scontrol, ucontrol);
111
112 return 0;
113}
114
115int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
116 struct snd_ctl_elem_value *ucontrol)
117{
118 struct soc_enum *se = (struct soc_enum *)kcontrol->private_value;
119 struct snd_sof_control *scontrol = se->dobj.private;
120 struct snd_soc_component *scomp = scontrol->scomp;
121 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(c: scomp);
122 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
123
124 if (tplg_ops && tplg_ops->control && tplg_ops->control->enum_put)
125 return tplg_ops->control->enum_put(scontrol, ucontrol);
126
127 return false;
128}
129
130int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
131 struct snd_ctl_elem_value *ucontrol)
132{
133 struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
134 struct snd_sof_control *scontrol = be->dobj.private;
135 struct snd_soc_component *scomp = scontrol->scomp;
136 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(c: scomp);
137 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
138
139 if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_get)
140 return tplg_ops->control->bytes_get(scontrol, ucontrol);
141
142 return 0;
143}
144
145int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
146 struct snd_ctl_elem_value *ucontrol)
147{
148 struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
149 struct snd_sof_control *scontrol = be->dobj.private;
150 struct snd_soc_component *scomp = scontrol->scomp;
151 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(c: scomp);
152 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
153
154 if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_put)
155 return tplg_ops->control->bytes_put(scontrol, ucontrol);
156
157 return 0;
158}
159
160int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
161 const unsigned int __user *binary_data,
162 unsigned int size)
163{
164 struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
165 struct snd_sof_control *scontrol = be->dobj.private;
166 struct snd_soc_component *scomp = scontrol->scomp;
167 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(c: scomp);
168 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
169
170 /* make sure we have at least a header */
171 if (size < sizeof(struct snd_ctl_tlv))
172 return -EINVAL;
173
174 if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_ext_put)
175 return tplg_ops->control->bytes_ext_put(scontrol, binary_data, size);
176
177 return 0;
178}
179
180int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int __user *binary_data,
181 unsigned int size)
182{
183 struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
184 struct snd_sof_control *scontrol = be->dobj.private;
185 struct snd_soc_component *scomp = scontrol->scomp;
186 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(c: scomp);
187 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
188 int ret, err;
189
190 ret = pm_runtime_resume_and_get(dev: scomp->dev);
191 if (ret < 0 && ret != -EACCES) {
192 dev_err_ratelimited(scomp->dev, "%s: failed to resume %d\n", __func__, ret);
193 return ret;
194 }
195
196 if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_ext_volatile_get)
197 ret = tplg_ops->control->bytes_ext_volatile_get(scontrol, binary_data, size);
198
199 pm_runtime_mark_last_busy(dev: scomp->dev);
200 err = pm_runtime_put_autosuspend(dev: scomp->dev);
201 if (err < 0)
202 dev_err_ratelimited(scomp->dev, "%s: failed to idle %d\n", __func__, err);
203
204 return ret;
205}
206
207int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
208 unsigned int __user *binary_data,
209 unsigned int size)
210{
211 struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
212 struct snd_sof_control *scontrol = be->dobj.private;
213 struct snd_soc_component *scomp = scontrol->scomp;
214 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(c: scomp);
215 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
216
217 if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_ext_get)
218 return tplg_ops->control->bytes_ext_get(scontrol, binary_data, size);
219
220 return 0;
221}
222

source code of linux/sound/soc/sof/control.c