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