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 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 18 int 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 33 int 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 48 int 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 70 int 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 85 int 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 100 int 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 115 int 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 130 int 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 145 int 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 160 int 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 180 int 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 207 int 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.