| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 |
|
| 11 |
|
| 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 |
|
| 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 |
|
| 191 | if (!tplg_ops || !tplg_ops->control ||
|
| 192 | !tplg_ops->control->bytes_ext_volatile_get)
|
| 193 | return 0;
|
| 194 |
|
| 195 | ret = pm_runtime_resume_and_get(scomp->dev);
|
| 196 | if (ret < 0 && ret != -EACCES) {
|
| 197 | dev_err_ratelimited(scomp->dev, "%s: failed to resume %d\n", __func__, ret);
|
| 198 | return ret;
|
| 199 | }
|
| 200 |
|
| 201 |
|
| 202 | ret = snd_sof_boot_dsp_firmware(sdev);
|
| 203 | if (!ret)
|
| 204 | ret = tplg_ops->control->bytes_ext_volatile_get(scontrol,
|
| 205 | binary_data,
|
| 206 | size);
|
| 207 |
|
| 208 | err = pm_runtime_put_autosuspend(scomp->dev);
|
| 209 | if (err < 0)
|
| 210 | dev_err_ratelimited(scomp->dev, "%s: failed to idle %d\n", __func__, err);
|
| 211 |
|
| 212 | return ret;
|
| 213 | }
|
| 214 |
|
| 215 | int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
|
| 216 | unsigned int __user *binary_data,
|
| 217 | unsigned int size)
|
| 218 | {
|
| 219 | struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
|
| 220 | struct snd_sof_control *scontrol = be->dobj.private;
|
| 221 | struct snd_soc_component *scomp = scontrol->scomp;
|
| 222 | struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
|
| 223 | const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
|
| 224 |
|
| 225 | if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_ext_get)
|
| 226 | return tplg_ops->control->bytes_ext_get(scontrol, binary_data, size);
|
| 227 |
|
| 228 | return 0;
|
| 229 | }
|