xref: /openbmc/linux/sound/soc/sof/control.c (revision 67ec2a091630c28ea8d05db2bd7178a05b04b7e6)
1e149ca29SPierre-Louis Bossart // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2c3078f53SLiam Girdwood //
3c3078f53SLiam Girdwood // This file is provided under a dual BSD/GPLv2 license.  When using or
4c3078f53SLiam Girdwood // redistributing this file, you may do so under either license.
5c3078f53SLiam Girdwood //
6c3078f53SLiam Girdwood // Copyright(c) 2018 Intel Corporation. All rights reserved.
7c3078f53SLiam Girdwood //
8c3078f53SLiam Girdwood // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9c3078f53SLiam Girdwood //
10c3078f53SLiam Girdwood 
11c3078f53SLiam Girdwood /* Mixer Controls */
12c3078f53SLiam Girdwood 
13c3078f53SLiam Girdwood #include <linux/pm_runtime.h>
145d43001aSJaska Uimonen #include <linux/leds.h>
15c3078f53SLiam Girdwood #include "sof-priv.h"
16ee1e79b7SRanjani Sridharan #include "sof-audio.h"
17c3078f53SLiam Girdwood 
185d43001aSJaska Uimonen static void update_mute_led(struct snd_sof_control *scontrol,
195d43001aSJaska Uimonen 			    struct snd_kcontrol *kcontrol,
205d43001aSJaska Uimonen 			    struct snd_ctl_elem_value *ucontrol)
215d43001aSJaska Uimonen {
2249c22696SKai-Heng Feng 	int temp = 0;
2349c22696SKai-Heng Feng 	int mask;
245d43001aSJaska Uimonen 	int i;
255d43001aSJaska Uimonen 
265d43001aSJaska Uimonen 	mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
275d43001aSJaska Uimonen 
285d43001aSJaska Uimonen 	for (i = 0; i < scontrol->num_channels; i++) {
295d43001aSJaska Uimonen 		if (ucontrol->value.integer.value[i]) {
305d43001aSJaska Uimonen 			temp |= mask;
315d43001aSJaska Uimonen 			break;
325d43001aSJaska Uimonen 		}
335d43001aSJaska Uimonen 	}
345d43001aSJaska Uimonen 
355d43001aSJaska Uimonen 	if (temp == scontrol->led_ctl.led_value)
365d43001aSJaska Uimonen 		return;
375d43001aSJaska Uimonen 
385d43001aSJaska Uimonen 	scontrol->led_ctl.led_value = temp;
395d43001aSJaska Uimonen 
409899a7a8SYueHaibing #if IS_REACHABLE(CONFIG_LEDS_TRIGGER_AUDIO)
415d43001aSJaska Uimonen 	if (!scontrol->led_ctl.direction)
425d43001aSJaska Uimonen 		ledtrig_audio_set(LED_AUDIO_MUTE, temp ? LED_OFF : LED_ON);
435d43001aSJaska Uimonen 	else
445d43001aSJaska Uimonen 		ledtrig_audio_set(LED_AUDIO_MICMUTE, temp ? LED_OFF : LED_ON);
459899a7a8SYueHaibing #endif
465d43001aSJaska Uimonen }
475d43001aSJaska Uimonen 
48c3078f53SLiam Girdwood int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
49c3078f53SLiam Girdwood 		       struct snd_ctl_elem_value *ucontrol)
50c3078f53SLiam Girdwood {
51838d04f3SRanjani Sridharan 	struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
52c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = sm->dobj.private;
53838d04f3SRanjani Sridharan 	struct snd_soc_component *scomp = scontrol->scomp;
54838d04f3SRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
55838d04f3SRanjani Sridharan 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
56c3078f53SLiam Girdwood 
57838d04f3SRanjani Sridharan 	if (tplg_ops->control->volume_get)
58838d04f3SRanjani Sridharan 		return tplg_ops->control->volume_get(scontrol, ucontrol);
59c3078f53SLiam Girdwood 
60c3078f53SLiam Girdwood 	return 0;
61c3078f53SLiam Girdwood }
62c3078f53SLiam Girdwood 
63c3078f53SLiam Girdwood int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
64c3078f53SLiam Girdwood 		       struct snd_ctl_elem_value *ucontrol)
65c3078f53SLiam Girdwood {
66838d04f3SRanjani Sridharan 	struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
67c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = sm->dobj.private;
68ee1e79b7SRanjani Sridharan 	struct snd_soc_component *scomp = scontrol->scomp;
69838d04f3SRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
70838d04f3SRanjani Sridharan 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
71c3078f53SLiam Girdwood 
72838d04f3SRanjani Sridharan 	if (tplg_ops->control->volume_put)
73838d04f3SRanjani Sridharan 		return tplg_ops->control->volume_put(scontrol, ucontrol);
74c3078f53SLiam Girdwood 
75838d04f3SRanjani Sridharan 	return false;
76c3078f53SLiam Girdwood }
77c3078f53SLiam Girdwood 
78fca18e62SJaska Uimonen int snd_sof_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
79fca18e62SJaska Uimonen {
80fca18e62SJaska Uimonen 	struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
81fca18e62SJaska Uimonen 	struct snd_sof_control *scontrol = sm->dobj.private;
82fca18e62SJaska Uimonen 	unsigned int channels = scontrol->num_channels;
83fca18e62SJaska Uimonen 	int platform_max;
84fca18e62SJaska Uimonen 
85fca18e62SJaska Uimonen 	if (!sm->platform_max)
86fca18e62SJaska Uimonen 		sm->platform_max = sm->max;
87fca18e62SJaska Uimonen 	platform_max = sm->platform_max;
88fca18e62SJaska Uimonen 
89fca18e62SJaska Uimonen 	if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume"))
90fca18e62SJaska Uimonen 		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
91fca18e62SJaska Uimonen 	else
92fca18e62SJaska Uimonen 		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
93fca18e62SJaska Uimonen 
94fca18e62SJaska Uimonen 	uinfo->count = channels;
95fca18e62SJaska Uimonen 	uinfo->value.integer.min = 0;
96fca18e62SJaska Uimonen 	uinfo->value.integer.max = platform_max - sm->min;
97fca18e62SJaska Uimonen 	return 0;
98fca18e62SJaska Uimonen }
99fca18e62SJaska Uimonen 
100c3078f53SLiam Girdwood int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
101c3078f53SLiam Girdwood 		       struct snd_ctl_elem_value *ucontrol)
102c3078f53SLiam Girdwood {
103a6668746SRanjani Sridharan 	struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
104c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = sm->dobj.private;
105a6668746SRanjani Sridharan 	struct snd_soc_component *scomp = scontrol->scomp;
106a6668746SRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
107a6668746SRanjani Sridharan 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
108c3078f53SLiam Girdwood 
109a6668746SRanjani Sridharan 	if (tplg_ops->control->switch_get)
110a6668746SRanjani Sridharan 		return tplg_ops->control->switch_get(scontrol, ucontrol);
111c3078f53SLiam Girdwood 
112c3078f53SLiam Girdwood 	return 0;
113c3078f53SLiam Girdwood }
114c3078f53SLiam Girdwood 
115c3078f53SLiam Girdwood int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
116c3078f53SLiam Girdwood 		       struct snd_ctl_elem_value *ucontrol)
117c3078f53SLiam Girdwood {
118a6668746SRanjani Sridharan 	struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
119c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = sm->dobj.private;
120ee1e79b7SRanjani Sridharan 	struct snd_soc_component *scomp = scontrol->scomp;
121a6668746SRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
122a6668746SRanjani Sridharan 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
123c3078f53SLiam Girdwood 
1245d43001aSJaska Uimonen 	if (scontrol->led_ctl.use_led)
1255d43001aSJaska Uimonen 		update_mute_led(scontrol, kcontrol, ucontrol);
1265d43001aSJaska Uimonen 
127a6668746SRanjani Sridharan 	if (tplg_ops->control->switch_put)
128a6668746SRanjani Sridharan 		return tplg_ops->control->switch_put(scontrol, ucontrol);
129c3078f53SLiam Girdwood 
130a6668746SRanjani Sridharan 	return false;
131c3078f53SLiam Girdwood }
132c3078f53SLiam Girdwood 
133c3078f53SLiam Girdwood int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
134c3078f53SLiam Girdwood 		     struct snd_ctl_elem_value *ucontrol)
135c3078f53SLiam Girdwood {
136049307aaSRanjani Sridharan 	struct soc_enum *se = (struct soc_enum *)kcontrol->private_value;
137c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = se->dobj.private;
138049307aaSRanjani Sridharan 	struct snd_soc_component *scomp = scontrol->scomp;
139049307aaSRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
140049307aaSRanjani Sridharan 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
141c3078f53SLiam Girdwood 
142049307aaSRanjani Sridharan 	if (tplg_ops->control->enum_get)
143049307aaSRanjani Sridharan 		return tplg_ops->control->enum_get(scontrol, ucontrol);
144c3078f53SLiam Girdwood 
145c3078f53SLiam Girdwood 	return 0;
146c3078f53SLiam Girdwood }
147c3078f53SLiam Girdwood 
148c3078f53SLiam Girdwood int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
149c3078f53SLiam Girdwood 		     struct snd_ctl_elem_value *ucontrol)
150c3078f53SLiam Girdwood {
151049307aaSRanjani Sridharan 	struct soc_enum *se = (struct soc_enum *)kcontrol->private_value;
152c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = se->dobj.private;
153ee1e79b7SRanjani Sridharan 	struct snd_soc_component *scomp = scontrol->scomp;
154049307aaSRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
155049307aaSRanjani Sridharan 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
156c3078f53SLiam Girdwood 
157049307aaSRanjani Sridharan 	if (tplg_ops->control->enum_put)
158049307aaSRanjani Sridharan 		return tplg_ops->control->enum_put(scontrol, ucontrol);
159c3078f53SLiam Girdwood 
160049307aaSRanjani Sridharan 	return false;
161c3078f53SLiam Girdwood }
162c3078f53SLiam Girdwood 
163c3078f53SLiam Girdwood int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
164c3078f53SLiam Girdwood 		      struct snd_ctl_elem_value *ucontrol)
165c3078f53SLiam Girdwood {
166544ac885SRanjani Sridharan 	struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
167c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = be->dobj.private;
168ee1e79b7SRanjani Sridharan 	struct snd_soc_component *scomp = scontrol->scomp;
169544ac885SRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
170544ac885SRanjani Sridharan 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
171c3078f53SLiam Girdwood 
172544ac885SRanjani Sridharan 	if (tplg_ops->control->bytes_get)
173544ac885SRanjani Sridharan 		return tplg_ops->control->bytes_get(scontrol, ucontrol);
174c3078f53SLiam Girdwood 
175b9f8e138SGuennadi Liakhovetski 	return 0;
176c3078f53SLiam Girdwood }
177c3078f53SLiam Girdwood 
178c3078f53SLiam Girdwood int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
179c3078f53SLiam Girdwood 		      struct snd_ctl_elem_value *ucontrol)
180c3078f53SLiam Girdwood {
181544ac885SRanjani Sridharan 	struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
182c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = be->dobj.private;
183ee1e79b7SRanjani Sridharan 	struct snd_soc_component *scomp = scontrol->scomp;
184544ac885SRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
185544ac885SRanjani Sridharan 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
186c3078f53SLiam Girdwood 
187544ac885SRanjani Sridharan 	if (tplg_ops->control->bytes_put)
188544ac885SRanjani Sridharan 		return tplg_ops->control->bytes_put(scontrol, ucontrol);
189c3078f53SLiam Girdwood 
1900c888babSBard Liao 	return 0;
191c3078f53SLiam Girdwood }
192c3078f53SLiam Girdwood 
193c3078f53SLiam Girdwood int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
194c3078f53SLiam Girdwood 			  const unsigned int __user *binary_data,
195c3078f53SLiam Girdwood 			  unsigned int size)
196c3078f53SLiam Girdwood {
197*67ec2a09SRanjani Sridharan 	struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
198c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = be->dobj.private;
199ee1e79b7SRanjani Sridharan 	struct snd_soc_component *scomp = scontrol->scomp;
200*67ec2a09SRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
201*67ec2a09SRanjani Sridharan 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
202c3078f53SLiam Girdwood 
2032ca21011SPierre-Louis Bossart 	/* make sure we have at least a header */
2042ca21011SPierre-Louis Bossart 	if (size < sizeof(struct snd_ctl_tlv))
2052ca21011SPierre-Louis Bossart 		return -EINVAL;
2062ca21011SPierre-Louis Bossart 
207*67ec2a09SRanjani Sridharan 	if (tplg_ops->control->bytes_ext_put)
208*67ec2a09SRanjani Sridharan 		return tplg_ops->control->bytes_ext_put(scontrol, binary_data, size);
209c3078f53SLiam Girdwood 
2100c888babSBard Liao 	return 0;
211c3078f53SLiam Girdwood }
212c3078f53SLiam Girdwood 
213783560d0SDharageswari R int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int __user *binary_data,
214783560d0SDharageswari R 				   unsigned int size)
215783560d0SDharageswari R {
216783560d0SDharageswari R 	struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
217783560d0SDharageswari R 	struct snd_sof_control *scontrol = be->dobj.private;
218783560d0SDharageswari R 	struct snd_soc_component *scomp = scontrol->scomp;
219*67ec2a09SRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
220*67ec2a09SRanjani Sridharan 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
221*67ec2a09SRanjani Sridharan 	int ret, err;
222ec5a9762SPierre-Louis Bossart 
223783560d0SDharageswari R 	ret = pm_runtime_get_sync(scomp->dev);
22499ceec5cSPierre-Louis Bossart 	if (ret < 0 && ret != -EACCES) {
225*67ec2a09SRanjani Sridharan 		dev_err_ratelimited(scomp->dev, "%s: failed to resume %d\n", __func__, ret);
226783560d0SDharageswari R 		pm_runtime_put_noidle(scomp->dev);
227783560d0SDharageswari R 		return ret;
228783560d0SDharageswari R 	}
229783560d0SDharageswari R 
230*67ec2a09SRanjani Sridharan 	if (tplg_ops->control->bytes_ext_volatile_get)
231*67ec2a09SRanjani Sridharan 		ret = tplg_ops->control->bytes_ext_volatile_get(scontrol, binary_data, size);
232783560d0SDharageswari R 
233783560d0SDharageswari R 	pm_runtime_mark_last_busy(scomp->dev);
234783560d0SDharageswari R 	err = pm_runtime_put_autosuspend(scomp->dev);
235783560d0SDharageswari R 	if (err < 0)
236*67ec2a09SRanjani Sridharan 		dev_err_ratelimited(scomp->dev, "%s: failed to idle %d\n", __func__, err);
237783560d0SDharageswari R 
238783560d0SDharageswari R 	return ret;
239783560d0SDharageswari R }
240783560d0SDharageswari R 
241c3078f53SLiam Girdwood int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
242c3078f53SLiam Girdwood 			  unsigned int __user *binary_data,
243c3078f53SLiam Girdwood 			  unsigned int size)
244c3078f53SLiam Girdwood {
245*67ec2a09SRanjani Sridharan 	struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
246c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = be->dobj.private;
247ee1e79b7SRanjani Sridharan 	struct snd_soc_component *scomp = scontrol->scomp;
248*67ec2a09SRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
249*67ec2a09SRanjani Sridharan 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
250c3078f53SLiam Girdwood 
251*67ec2a09SRanjani Sridharan 	if (tplg_ops->control->bytes_ext_get)
252*67ec2a09SRanjani Sridharan 		return tplg_ops->control->bytes_ext_get(scontrol, binary_data, size);
253c3078f53SLiam Girdwood 
254b9f8e138SGuennadi Liakhovetski 	return 0;
255c3078f53SLiam Girdwood }
256