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 | int 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 | |
33 | int 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 | |
48 | int 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 | |
70 | int 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 | |
85 | int 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 | |
100 | int 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 | |
115 | int 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 | |
130 | int 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 | |
145 | int 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 | |
160 | int 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 | |
180 | int 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 | |
207 | int 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 | |