root/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bcm2835_audio_set_chip_ctls
  2. snd_bcm2835_ctl_info
  3. snd_bcm2835_ctl_get
  4. snd_bcm2835_ctl_put
  5. snd_bcm2835_spdif_default_info
  6. snd_bcm2835_spdif_default_get
  7. snd_bcm2835_spdif_default_put
  8. snd_bcm2835_spdif_mask_info
  9. snd_bcm2835_spdif_mask_get
  10. create_ctls
  11. snd_bcm2835_new_ctl
  12. snd_bcm2835_new_headphones_ctl
  13. snd_bcm2835_new_hdmi_ctl

   1 // SPDX-License-Identifier: GPL-2.0
   2 /* Copyright 2011 Broadcom Corporation.  All rights reserved. */
   3 
   4 #include <sound/core.h>
   5 #include <sound/control.h>
   6 #include <sound/tlv.h>
   7 #include <sound/asoundef.h>
   8 
   9 #include "bcm2835.h"
  10 
  11 /* volume maximum and minimum in terms of 0.01dB */
  12 #define CTRL_VOL_MAX 400
  13 #define CTRL_VOL_MIN -10239 /* originally -10240 */
  14 
  15 static int bcm2835_audio_set_chip_ctls(struct bcm2835_chip *chip)
  16 {
  17         int i, err = 0;
  18 
  19         /* change ctls for all substreams */
  20         for (i = 0; i < MAX_SUBSTREAMS; i++) {
  21                 if (chip->alsa_stream[i]) {
  22                         err = bcm2835_audio_set_ctls(chip->alsa_stream[i]);
  23                         if (err < 0)
  24                                 break;
  25                 }
  26         }
  27         return err;
  28 }
  29 
  30 static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
  31                                 struct snd_ctl_elem_info *uinfo)
  32 {
  33         if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
  34                 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  35                 uinfo->count = 1;
  36                 uinfo->value.integer.min = CTRL_VOL_MIN;
  37                 uinfo->value.integer.max = CTRL_VOL_MAX; /* 2303 */
  38         } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
  39                 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
  40                 uinfo->count = 1;
  41                 uinfo->value.integer.min = 0;
  42                 uinfo->value.integer.max = 1;
  43         } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
  44                 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  45                 uinfo->count = 1;
  46                 uinfo->value.integer.min = 0;
  47                 uinfo->value.integer.max = AUDIO_DEST_MAX - 1;
  48         }
  49         return 0;
  50 }
  51 
  52 static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
  53                                struct snd_ctl_elem_value *ucontrol)
  54 {
  55         struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
  56 
  57         mutex_lock(&chip->audio_mutex);
  58 
  59         if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
  60                 ucontrol->value.integer.value[0] = chip->volume;
  61         else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
  62                 ucontrol->value.integer.value[0] = chip->mute;
  63         else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
  64                 ucontrol->value.integer.value[0] = chip->dest;
  65 
  66         mutex_unlock(&chip->audio_mutex);
  67         return 0;
  68 }
  69 
  70 static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
  71                                struct snd_ctl_elem_value *ucontrol)
  72 {
  73         struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
  74         int val, *valp;
  75         int changed = 0;
  76 
  77         if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
  78                 valp = &chip->volume;
  79         else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
  80                 valp = &chip->mute;
  81         else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
  82                 valp = &chip->dest;
  83         else
  84                 return -EINVAL;
  85 
  86         val = ucontrol->value.integer.value[0];
  87         mutex_lock(&chip->audio_mutex);
  88         if (val != *valp) {
  89                 *valp = val;
  90                 changed = 1;
  91                 if (bcm2835_audio_set_chip_ctls(chip))
  92                         dev_err(chip->card->dev, "Failed to set ALSA controls..\n");
  93         }
  94         mutex_unlock(&chip->audio_mutex);
  95         return changed;
  96 }
  97 
  98 static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
  99 
 100 static const struct snd_kcontrol_new snd_bcm2835_ctl[] = {
 101         {
 102                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 103                 .name = "PCM Playback Volume",
 104                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
 105                 .private_value = PCM_PLAYBACK_VOLUME,
 106                 .info = snd_bcm2835_ctl_info,
 107                 .get = snd_bcm2835_ctl_get,
 108                 .put = snd_bcm2835_ctl_put,
 109                 .tlv = {.p = snd_bcm2835_db_scale}
 110         },
 111         {
 112                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 113                 .name = "PCM Playback Switch",
 114                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 115                 .private_value = PCM_PLAYBACK_MUTE,
 116                 .info = snd_bcm2835_ctl_info,
 117                 .get = snd_bcm2835_ctl_get,
 118                 .put = snd_bcm2835_ctl_put,
 119         },
 120         {
 121                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 122                 .name = "PCM Playback Route",
 123                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 124                 .private_value = PCM_PLAYBACK_DEVICE,
 125                 .info = snd_bcm2835_ctl_info,
 126                 .get = snd_bcm2835_ctl_get,
 127                 .put = snd_bcm2835_ctl_put,
 128         },
 129 };
 130 
 131 static int snd_bcm2835_spdif_default_info(struct snd_kcontrol *kcontrol,
 132                                           struct snd_ctl_elem_info *uinfo)
 133 {
 134         uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
 135         uinfo->count = 1;
 136         return 0;
 137 }
 138 
 139 static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol,
 140                                          struct snd_ctl_elem_value *ucontrol)
 141 {
 142         struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
 143         int i;
 144 
 145         mutex_lock(&chip->audio_mutex);
 146 
 147         for (i = 0; i < 4; i++)
 148                 ucontrol->value.iec958.status[i] =
 149                         (chip->spdif_status >> (i * 8)) & 0xff;
 150 
 151         mutex_unlock(&chip->audio_mutex);
 152         return 0;
 153 }
 154 
 155 static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol,
 156                                          struct snd_ctl_elem_value *ucontrol)
 157 {
 158         struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
 159         unsigned int val = 0;
 160         int i, change;
 161 
 162         mutex_lock(&chip->audio_mutex);
 163 
 164         for (i = 0; i < 4; i++)
 165                 val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
 166 
 167         change = val != chip->spdif_status;
 168         chip->spdif_status = val;
 169 
 170         mutex_unlock(&chip->audio_mutex);
 171         return change;
 172 }
 173 
 174 static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol,
 175                                        struct snd_ctl_elem_info *uinfo)
 176 {
 177         uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
 178         uinfo->count = 1;
 179         return 0;
 180 }
 181 
 182 static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol,
 183                                       struct snd_ctl_elem_value *ucontrol)
 184 {
 185         /*
 186          * bcm2835 supports only consumer mode and sets all other format flags
 187          * automatically. So the only thing left is signalling non-audio content
 188          */
 189         ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO;
 190         return 0;
 191 }
 192 
 193 static const struct snd_kcontrol_new snd_bcm2835_spdif[] = {
 194         {
 195                 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
 196                 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
 197                 .info = snd_bcm2835_spdif_default_info,
 198                 .get = snd_bcm2835_spdif_default_get,
 199                 .put = snd_bcm2835_spdif_default_put
 200         },
 201         {
 202                 .access = SNDRV_CTL_ELEM_ACCESS_READ,
 203                 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
 204                 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
 205                 .info = snd_bcm2835_spdif_mask_info,
 206                 .get = snd_bcm2835_spdif_mask_get,
 207         },
 208 };
 209 
 210 static int create_ctls(struct bcm2835_chip *chip, size_t size,
 211                        const struct snd_kcontrol_new *kctls)
 212 {
 213         int i, err;
 214 
 215         for (i = 0; i < size; i++) {
 216                 err = snd_ctl_add(chip->card, snd_ctl_new1(&kctls[i], chip));
 217                 if (err < 0)
 218                         return err;
 219         }
 220         return 0;
 221 }
 222 
 223 int snd_bcm2835_new_ctl(struct bcm2835_chip *chip)
 224 {
 225         int err;
 226 
 227         strcpy(chip->card->mixername, "Broadcom Mixer");
 228         err = create_ctls(chip, ARRAY_SIZE(snd_bcm2835_ctl), snd_bcm2835_ctl);
 229         if (err < 0)
 230                 return err;
 231         return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_spdif),
 232                            snd_bcm2835_spdif);
 233 }
 234 
 235 static const struct snd_kcontrol_new snd_bcm2835_headphones_ctl[] = {
 236         {
 237                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 238                 .name = "Headphone Playback Volume",
 239                 .index = 0,
 240                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
 241                           SNDRV_CTL_ELEM_ACCESS_TLV_READ,
 242                 .private_value = PCM_PLAYBACK_VOLUME,
 243                 .info = snd_bcm2835_ctl_info,
 244                 .get = snd_bcm2835_ctl_get,
 245                 .put = snd_bcm2835_ctl_put,
 246                 .count = 1,
 247                 .tlv = {.p = snd_bcm2835_db_scale}
 248         },
 249         {
 250                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 251                 .name = "Headphone Playback Switch",
 252                 .index = 0,
 253                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 254                 .private_value = PCM_PLAYBACK_MUTE,
 255                 .info = snd_bcm2835_ctl_info,
 256                 .get = snd_bcm2835_ctl_get,
 257                 .put = snd_bcm2835_ctl_put,
 258                 .count = 1,
 259         }
 260 };
 261 
 262 int snd_bcm2835_new_headphones_ctl(struct bcm2835_chip *chip)
 263 {
 264         strcpy(chip->card->mixername, "Broadcom Mixer");
 265         return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_headphones_ctl),
 266                            snd_bcm2835_headphones_ctl);
 267 }
 268 
 269 static const struct snd_kcontrol_new snd_bcm2835_hdmi[] = {
 270         {
 271                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 272                 .name = "HDMI Playback Volume",
 273                 .index = 0,
 274                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
 275                           SNDRV_CTL_ELEM_ACCESS_TLV_READ,
 276                 .private_value = PCM_PLAYBACK_VOLUME,
 277                 .info = snd_bcm2835_ctl_info,
 278                 .get = snd_bcm2835_ctl_get,
 279                 .put = snd_bcm2835_ctl_put,
 280                 .count = 1,
 281                 .tlv = {.p = snd_bcm2835_db_scale}
 282         },
 283         {
 284                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 285                 .name = "HDMI Playback Switch",
 286                 .index = 0,
 287                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 288                 .private_value = PCM_PLAYBACK_MUTE,
 289                 .info = snd_bcm2835_ctl_info,
 290                 .get = snd_bcm2835_ctl_get,
 291                 .put = snd_bcm2835_ctl_put,
 292                 .count = 1,
 293         }
 294 };
 295 
 296 int snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip *chip)
 297 {
 298         strcpy(chip->card->mixername, "Broadcom Mixer");
 299         return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_hdmi),
 300                            snd_bcm2835_hdmi);
 301 }
 302 

/* [<][>][^][v][top][bottom][index][help] */