control.c (7539B)
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 = sdev->ipc->ops->tplg; 26 27 if (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 = sdev->ipc->ops->tplg; 41 42 if (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 = sdev->ipc->ops->tplg; 78 79 if (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 = sdev->ipc->ops->tplg; 93 94 if (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 = sdev->ipc->ops->tplg; 108 109 if (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 = sdev->ipc->ops->tplg; 123 124 if (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 = sdev->ipc->ops->tplg; 138 139 if (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 = sdev->ipc->ops->tplg; 153 154 if (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 = sdev->ipc->ops->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->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 = sdev->ipc->ops->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->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 = sdev->ipc->ops->tplg; 216 217 if (tplg_ops->control->bytes_ext_get) 218 return tplg_ops->control->bytes_ext_get(scontrol, binary_data, size); 219 220 return 0; 221}