linux/sound/soc/sof/control.c
<<
>>
Prefs
   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
  18static void update_mute_led(struct snd_sof_control *scontrol,
  19                            struct snd_kcontrol *kcontrol,
  20                            struct snd_ctl_elem_value *ucontrol)
  21{
  22        int temp = 0;
  23        int mask;
  24        int i;
  25
  26        mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
  27
  28        for (i = 0; i < scontrol->num_channels; i++) {
  29                if (ucontrol->value.integer.value[i]) {
  30                        temp |= mask;
  31                        break;
  32                }
  33        }
  34
  35        if (temp == scontrol->led_ctl.led_value)
  36                return;
  37
  38        scontrol->led_ctl.led_value = temp;
  39
  40#if IS_REACHABLE(CONFIG_LEDS_TRIGGER_AUDIO)
  41        if (!scontrol->led_ctl.direction)
  42                ledtrig_audio_set(LED_AUDIO_MUTE, temp ? LED_OFF : LED_ON);
  43        else
  44                ledtrig_audio_set(LED_AUDIO_MICMUTE, temp ? LED_OFF : LED_ON);
  45#endif
  46}
  47
  48int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
  49                       struct snd_ctl_elem_value *ucontrol)
  50{
  51        struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
  52        struct snd_sof_control *scontrol = sm->dobj.private;
  53        struct snd_soc_component *scomp = scontrol->scomp;
  54        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
  55        const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
  56
  57        if (tplg_ops->control->volume_get)
  58                return tplg_ops->control->volume_get(scontrol, ucontrol);
  59
  60        return 0;
  61}
  62
  63int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
  64                       struct snd_ctl_elem_value *ucontrol)
  65{
  66        struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
  67        struct snd_sof_control *scontrol = sm->dobj.private;
  68        struct snd_soc_component *scomp = scontrol->scomp;
  69        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
  70        const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
  71
  72        if (tplg_ops->control->volume_put)
  73                return tplg_ops->control->volume_put(scontrol, ucontrol);
  74
  75        return false;
  76}
  77
  78int snd_sof_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
  79{
  80        struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
  81        struct snd_sof_control *scontrol = sm->dobj.private;
  82        unsigned int channels = scontrol->num_channels;
  83        int platform_max;
  84
  85        if (!sm->platform_max)
  86                sm->platform_max = sm->max;
  87        platform_max = sm->platform_max;
  88
  89        if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume"))
  90                uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
  91        else
  92                uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  93
  94        uinfo->count = channels;
  95        uinfo->value.integer.min = 0;
  96        uinfo->value.integer.max = platform_max - sm->min;
  97        return 0;
  98}
  99
 100int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
 101                       struct snd_ctl_elem_value *ucontrol)
 102{
 103        struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
 104        struct snd_sof_control *scontrol = sm->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->switch_get)
 110                return tplg_ops->control->switch_get(scontrol, ucontrol);
 111
 112        return 0;
 113}
 114
 115int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
 116                       struct snd_ctl_elem_value *ucontrol)
 117{
 118        struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
 119        struct snd_sof_control *scontrol = sm->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 (scontrol->led_ctl.use_led)
 125                update_mute_led(scontrol, kcontrol, ucontrol);
 126
 127        if (tplg_ops->control->switch_put)
 128                return tplg_ops->control->switch_put(scontrol, ucontrol);
 129
 130        return false;
 131}
 132
 133int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
 134                     struct snd_ctl_elem_value *ucontrol)
 135{
 136        struct soc_enum *se = (struct soc_enum *)kcontrol->private_value;
 137        struct snd_sof_control *scontrol = se->dobj.private;
 138        struct snd_soc_component *scomp = scontrol->scomp;
 139        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
 140        const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
 141
 142        if (tplg_ops->control->enum_get)
 143                return tplg_ops->control->enum_get(scontrol, ucontrol);
 144
 145        return 0;
 146}
 147
 148int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
 149                     struct snd_ctl_elem_value *ucontrol)
 150{
 151        struct soc_enum *se = (struct soc_enum *)kcontrol->private_value;
 152        struct snd_sof_control *scontrol = se->dobj.private;
 153        struct snd_soc_component *scomp = scontrol->scomp;
 154        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
 155        const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
 156
 157        if (tplg_ops->control->enum_put)
 158                return tplg_ops->control->enum_put(scontrol, ucontrol);
 159
 160        return false;
 161}
 162
 163int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
 164                      struct snd_ctl_elem_value *ucontrol)
 165{
 166        struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
 167        struct snd_sof_control *scontrol = be->dobj.private;
 168        struct snd_soc_component *scomp = scontrol->scomp;
 169        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
 170        const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
 171
 172        if (tplg_ops->control->bytes_get)
 173                return tplg_ops->control->bytes_get(scontrol, ucontrol);
 174
 175        return 0;
 176}
 177
 178int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
 179                      struct snd_ctl_elem_value *ucontrol)
 180{
 181        struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
 182        struct snd_sof_control *scontrol = be->dobj.private;
 183        struct snd_soc_component *scomp = scontrol->scomp;
 184        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
 185        const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
 186
 187        if (tplg_ops->control->bytes_put)
 188                return tplg_ops->control->bytes_put(scontrol, ucontrol);
 189
 190        return 0;
 191}
 192
 193int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
 194                          const unsigned int __user *binary_data,
 195                          unsigned int size)
 196{
 197        struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
 198        struct snd_sof_control *scontrol = be->dobj.private;
 199        struct snd_soc_component *scomp = scontrol->scomp;
 200        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
 201        const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
 202
 203        /* make sure we have at least a header */
 204        if (size < sizeof(struct snd_ctl_tlv))
 205                return -EINVAL;
 206
 207        if (tplg_ops->control->bytes_ext_put)
 208                return tplg_ops->control->bytes_ext_put(scontrol, binary_data, size);
 209
 210        return 0;
 211}
 212
 213int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int __user *binary_data,
 214                                   unsigned int size)
 215{
 216        struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
 217        struct snd_sof_control *scontrol = be->dobj.private;
 218        struct snd_soc_component *scomp = scontrol->scomp;
 219        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
 220        const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
 221        int ret, err;
 222
 223        ret = pm_runtime_get_sync(scomp->dev);
 224        if (ret < 0 && ret != -EACCES) {
 225                dev_err_ratelimited(scomp->dev, "%s: failed to resume %d\n", __func__, ret);
 226                pm_runtime_put_noidle(scomp->dev);
 227                return ret;
 228        }
 229
 230        if (tplg_ops->control->bytes_ext_volatile_get)
 231                ret = tplg_ops->control->bytes_ext_volatile_get(scontrol, binary_data, size);
 232
 233        pm_runtime_mark_last_busy(scomp->dev);
 234        err = pm_runtime_put_autosuspend(scomp->dev);
 235        if (err < 0)
 236                dev_err_ratelimited(scomp->dev, "%s: failed to idle %d\n", __func__, err);
 237
 238        return ret;
 239}
 240
 241int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
 242                          unsigned int __user *binary_data,
 243                          unsigned int size)
 244{
 245        struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
 246        struct snd_sof_control *scontrol = be->dobj.private;
 247        struct snd_soc_component *scomp = scontrol->scomp;
 248        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
 249        const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
 250
 251        if (tplg_ops->control->bytes_ext_get)
 252                return tplg_ops->control->bytes_ext_get(scontrol, binary_data, size);
 253
 254        return 0;
 255}
 256