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 18c3078f53SLiam Girdwood int snd_sof_volume_get(struct snd_kcontrol *kcontrol, 19c3078f53SLiam Girdwood struct snd_ctl_elem_value *ucontrol) 20c3078f53SLiam Girdwood { 21838d04f3SRanjani Sridharan struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; 22c3078f53SLiam Girdwood struct snd_sof_control *scontrol = sm->dobj.private; 23838d04f3SRanjani Sridharan struct snd_soc_component *scomp = scontrol->scomp; 24838d04f3SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 25838d04f3SRanjani Sridharan const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; 26c3078f53SLiam Girdwood 27838d04f3SRanjani Sridharan if (tplg_ops->control->volume_get) 28838d04f3SRanjani Sridharan return tplg_ops->control->volume_get(scontrol, ucontrol); 29c3078f53SLiam Girdwood 30c3078f53SLiam Girdwood return 0; 31c3078f53SLiam Girdwood } 32c3078f53SLiam Girdwood 33c3078f53SLiam Girdwood int snd_sof_volume_put(struct snd_kcontrol *kcontrol, 34c3078f53SLiam Girdwood struct snd_ctl_elem_value *ucontrol) 35c3078f53SLiam Girdwood { 36838d04f3SRanjani Sridharan struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; 37c3078f53SLiam Girdwood struct snd_sof_control *scontrol = sm->dobj.private; 38ee1e79b7SRanjani Sridharan struct snd_soc_component *scomp = scontrol->scomp; 39838d04f3SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 40838d04f3SRanjani Sridharan const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; 41c3078f53SLiam Girdwood 42838d04f3SRanjani Sridharan if (tplg_ops->control->volume_put) 43838d04f3SRanjani Sridharan return tplg_ops->control->volume_put(scontrol, ucontrol); 44c3078f53SLiam Girdwood 45838d04f3SRanjani Sridharan return false; 46c3078f53SLiam Girdwood } 47c3078f53SLiam Girdwood 48fca18e62SJaska Uimonen int snd_sof_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 49fca18e62SJaska Uimonen { 50fca18e62SJaska Uimonen struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; 51fca18e62SJaska Uimonen struct snd_sof_control *scontrol = sm->dobj.private; 52fca18e62SJaska Uimonen unsigned int channels = scontrol->num_channels; 53fca18e62SJaska Uimonen int platform_max; 54fca18e62SJaska Uimonen 55fca18e62SJaska Uimonen if (!sm->platform_max) 56fca18e62SJaska Uimonen sm->platform_max = sm->max; 57fca18e62SJaska Uimonen platform_max = sm->platform_max; 58fca18e62SJaska Uimonen 59fca18e62SJaska Uimonen if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume")) 60fca18e62SJaska Uimonen uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 61fca18e62SJaska Uimonen else 62fca18e62SJaska Uimonen uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 63fca18e62SJaska Uimonen 64fca18e62SJaska Uimonen uinfo->count = channels; 65fca18e62SJaska Uimonen uinfo->value.integer.min = 0; 66fca18e62SJaska Uimonen uinfo->value.integer.max = platform_max - sm->min; 67fca18e62SJaska Uimonen return 0; 68fca18e62SJaska Uimonen } 69fca18e62SJaska Uimonen 70c3078f53SLiam Girdwood int snd_sof_switch_get(struct snd_kcontrol *kcontrol, 71c3078f53SLiam Girdwood struct snd_ctl_elem_value *ucontrol) 72c3078f53SLiam Girdwood { 73a6668746SRanjani Sridharan struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; 74c3078f53SLiam Girdwood struct snd_sof_control *scontrol = sm->dobj.private; 75a6668746SRanjani Sridharan struct snd_soc_component *scomp = scontrol->scomp; 76a6668746SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 77a6668746SRanjani Sridharan const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; 78c3078f53SLiam Girdwood 79a6668746SRanjani Sridharan if (tplg_ops->control->switch_get) 80a6668746SRanjani Sridharan return tplg_ops->control->switch_get(scontrol, ucontrol); 81c3078f53SLiam Girdwood 82c3078f53SLiam Girdwood return 0; 83c3078f53SLiam Girdwood } 84c3078f53SLiam Girdwood 85c3078f53SLiam Girdwood int snd_sof_switch_put(struct snd_kcontrol *kcontrol, 86c3078f53SLiam Girdwood struct snd_ctl_elem_value *ucontrol) 87c3078f53SLiam Girdwood { 88a6668746SRanjani Sridharan struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; 89c3078f53SLiam Girdwood struct snd_sof_control *scontrol = sm->dobj.private; 90ee1e79b7SRanjani Sridharan struct snd_soc_component *scomp = scontrol->scomp; 91a6668746SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 92a6668746SRanjani Sridharan const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; 93c3078f53SLiam Girdwood 94a6668746SRanjani Sridharan if (tplg_ops->control->switch_put) 95a6668746SRanjani Sridharan return tplg_ops->control->switch_put(scontrol, ucontrol); 96c3078f53SLiam Girdwood 97a6668746SRanjani Sridharan return false; 98c3078f53SLiam Girdwood } 99c3078f53SLiam Girdwood 100c3078f53SLiam Girdwood int snd_sof_enum_get(struct snd_kcontrol *kcontrol, 101c3078f53SLiam Girdwood struct snd_ctl_elem_value *ucontrol) 102c3078f53SLiam Girdwood { 103049307aaSRanjani Sridharan struct soc_enum *se = (struct soc_enum *)kcontrol->private_value; 104c3078f53SLiam Girdwood struct snd_sof_control *scontrol = se->dobj.private; 105049307aaSRanjani Sridharan struct snd_soc_component *scomp = scontrol->scomp; 106049307aaSRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 107049307aaSRanjani Sridharan const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; 108c3078f53SLiam Girdwood 109049307aaSRanjani Sridharan if (tplg_ops->control->enum_get) 110049307aaSRanjani Sridharan return tplg_ops->control->enum_get(scontrol, ucontrol); 111c3078f53SLiam Girdwood 112c3078f53SLiam Girdwood return 0; 113c3078f53SLiam Girdwood } 114c3078f53SLiam Girdwood 115c3078f53SLiam Girdwood int snd_sof_enum_put(struct snd_kcontrol *kcontrol, 116c3078f53SLiam Girdwood struct snd_ctl_elem_value *ucontrol) 117c3078f53SLiam Girdwood { 118049307aaSRanjani Sridharan struct soc_enum *se = (struct soc_enum *)kcontrol->private_value; 119c3078f53SLiam Girdwood struct snd_sof_control *scontrol = se->dobj.private; 120ee1e79b7SRanjani Sridharan struct snd_soc_component *scomp = scontrol->scomp; 121049307aaSRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 122049307aaSRanjani Sridharan const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; 123c3078f53SLiam Girdwood 124049307aaSRanjani Sridharan if (tplg_ops->control->enum_put) 125049307aaSRanjani Sridharan return tplg_ops->control->enum_put(scontrol, ucontrol); 126c3078f53SLiam Girdwood 127049307aaSRanjani Sridharan return false; 128c3078f53SLiam Girdwood } 129c3078f53SLiam Girdwood 130c3078f53SLiam Girdwood int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, 131c3078f53SLiam Girdwood struct snd_ctl_elem_value *ucontrol) 132c3078f53SLiam Girdwood { 133544ac885SRanjani Sridharan struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; 134c3078f53SLiam Girdwood struct snd_sof_control *scontrol = be->dobj.private; 135ee1e79b7SRanjani Sridharan struct snd_soc_component *scomp = scontrol->scomp; 136544ac885SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 137544ac885SRanjani Sridharan const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; 138c3078f53SLiam Girdwood 139544ac885SRanjani Sridharan if (tplg_ops->control->bytes_get) 140544ac885SRanjani Sridharan return tplg_ops->control->bytes_get(scontrol, ucontrol); 141c3078f53SLiam Girdwood 142b9f8e138SGuennadi Liakhovetski return 0; 143c3078f53SLiam Girdwood } 144c3078f53SLiam Girdwood 145c3078f53SLiam Girdwood int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, 146c3078f53SLiam Girdwood struct snd_ctl_elem_value *ucontrol) 147c3078f53SLiam Girdwood { 148544ac885SRanjani Sridharan struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; 149c3078f53SLiam Girdwood struct snd_sof_control *scontrol = be->dobj.private; 150ee1e79b7SRanjani Sridharan struct snd_soc_component *scomp = scontrol->scomp; 151544ac885SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 152544ac885SRanjani Sridharan const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; 153c3078f53SLiam Girdwood 154544ac885SRanjani Sridharan if (tplg_ops->control->bytes_put) 155544ac885SRanjani Sridharan return tplg_ops->control->bytes_put(scontrol, ucontrol); 156c3078f53SLiam Girdwood 1570c888babSBard Liao return 0; 158c3078f53SLiam Girdwood } 159c3078f53SLiam Girdwood 160c3078f53SLiam Girdwood int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, 161c3078f53SLiam Girdwood const unsigned int __user *binary_data, 162c3078f53SLiam Girdwood unsigned int size) 163c3078f53SLiam Girdwood { 16467ec2a09SRanjani Sridharan struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; 165c3078f53SLiam Girdwood struct snd_sof_control *scontrol = be->dobj.private; 166ee1e79b7SRanjani Sridharan struct snd_soc_component *scomp = scontrol->scomp; 16767ec2a09SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 16867ec2a09SRanjani Sridharan const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; 169c3078f53SLiam Girdwood 1702ca21011SPierre-Louis Bossart /* make sure we have at least a header */ 1712ca21011SPierre-Louis Bossart if (size < sizeof(struct snd_ctl_tlv)) 1722ca21011SPierre-Louis Bossart return -EINVAL; 1732ca21011SPierre-Louis Bossart 17467ec2a09SRanjani Sridharan if (tplg_ops->control->bytes_ext_put) 17567ec2a09SRanjani Sridharan return tplg_ops->control->bytes_ext_put(scontrol, binary_data, size); 176c3078f53SLiam Girdwood 1770c888babSBard Liao return 0; 178c3078f53SLiam Girdwood } 179c3078f53SLiam Girdwood 180783560d0SDharageswari R int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int __user *binary_data, 181783560d0SDharageswari R unsigned int size) 182783560d0SDharageswari R { 183783560d0SDharageswari R struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; 184783560d0SDharageswari R struct snd_sof_control *scontrol = be->dobj.private; 185783560d0SDharageswari R struct snd_soc_component *scomp = scontrol->scomp; 18667ec2a09SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 18767ec2a09SRanjani Sridharan const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; 18867ec2a09SRanjani Sridharan int ret, err; 189ec5a9762SPierre-Louis Bossart 190*bf0736e5SPierre-Louis Bossart ret = pm_runtime_resume_and_get(scomp->dev); 19199ceec5cSPierre-Louis Bossart if (ret < 0 && ret != -EACCES) { 19267ec2a09SRanjani Sridharan dev_err_ratelimited(scomp->dev, "%s: failed to resume %d\n", __func__, ret); 193783560d0SDharageswari R return ret; 194783560d0SDharageswari R } 195783560d0SDharageswari R 19667ec2a09SRanjani Sridharan if (tplg_ops->control->bytes_ext_volatile_get) 19767ec2a09SRanjani Sridharan ret = tplg_ops->control->bytes_ext_volatile_get(scontrol, binary_data, size); 198783560d0SDharageswari R 199783560d0SDharageswari R pm_runtime_mark_last_busy(scomp->dev); 200783560d0SDharageswari R err = pm_runtime_put_autosuspend(scomp->dev); 201783560d0SDharageswari R if (err < 0) 20267ec2a09SRanjani Sridharan dev_err_ratelimited(scomp->dev, "%s: failed to idle %d\n", __func__, err); 203783560d0SDharageswari R 204783560d0SDharageswari R return ret; 205783560d0SDharageswari R } 206783560d0SDharageswari R 207c3078f53SLiam Girdwood int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, 208c3078f53SLiam Girdwood unsigned int __user *binary_data, 209c3078f53SLiam Girdwood unsigned int size) 210c3078f53SLiam Girdwood { 21167ec2a09SRanjani Sridharan struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; 212c3078f53SLiam Girdwood struct snd_sof_control *scontrol = be->dobj.private; 213ee1e79b7SRanjani Sridharan struct snd_soc_component *scomp = scontrol->scomp; 21467ec2a09SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 21567ec2a09SRanjani Sridharan const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; 216c3078f53SLiam Girdwood 21767ec2a09SRanjani Sridharan if (tplg_ops->control->bytes_ext_get) 21867ec2a09SRanjani Sridharan return tplg_ops->control->bytes_ext_get(scontrol, binary_data, size); 219c3078f53SLiam Girdwood 220b9f8e138SGuennadi Liakhovetski return 0; 221c3078f53SLiam Girdwood } 222