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(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(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(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(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(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(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(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(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(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(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(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(scomp->dev);
200	err = pm_runtime_put_autosuspend(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(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