LCOV - code coverage report
Current view: top level - drivers/staging/vc04_services/bcm2835-audio - bcm2835-ctl.c (source / functions) Hit Total Coverage
Test: Real Lines: 48 94 51.1 %
Date: 2020-10-17 15:46:16 Functions: 0 13 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       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                 :          3 : 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                 :          3 :         for (i = 0; i < MAX_SUBSTREAMS; i++) {
      21                 :          3 :                 if (chip->alsa_stream[i]) {
      22                 :          0 :                         err = bcm2835_audio_set_ctls(chip->alsa_stream[i]);
      23                 :          0 :                         if (err < 0)
      24                 :            :                                 break;
      25                 :            :                 }
      26                 :            :         }
      27                 :          3 :         return err;
      28                 :            : }
      29                 :            : 
      30                 :          3 : static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
      31                 :            :                                 struct snd_ctl_elem_info *uinfo)
      32                 :            : {
      33                 :          3 :         if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
      34                 :          3 :                 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
      35                 :          3 :                 uinfo->count = 1;
      36                 :          3 :                 uinfo->value.integer.min = CTRL_VOL_MIN;
      37                 :          3 :                 uinfo->value.integer.max = CTRL_VOL_MAX; /* 2303 */
      38                 :          3 :         } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
      39                 :          3 :                 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
      40                 :          3 :                 uinfo->count = 1;
      41                 :          3 :                 uinfo->value.integer.min = 0;
      42                 :          3 :                 uinfo->value.integer.max = 1;
      43                 :          0 :         } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
      44                 :          0 :                 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
      45                 :          0 :                 uinfo->count = 1;
      46                 :          0 :                 uinfo->value.integer.min = 0;
      47                 :          0 :                 uinfo->value.integer.max = AUDIO_DEST_MAX - 1;
      48                 :            :         }
      49                 :          3 :         return 0;
      50                 :            : }
      51                 :            : 
      52                 :          3 : static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
      53                 :            :                                struct snd_ctl_elem_value *ucontrol)
      54                 :            : {
      55                 :          3 :         struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
      56                 :            : 
      57                 :          3 :         mutex_lock(&chip->audio_mutex);
      58                 :            : 
      59                 :          3 :         if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
      60                 :          3 :                 ucontrol->value.integer.value[0] = chip->volume;
      61                 :          3 :         else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
      62                 :          3 :                 ucontrol->value.integer.value[0] = chip->mute;
      63                 :          0 :         else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
      64                 :          0 :                 ucontrol->value.integer.value[0] = chip->dest;
      65                 :            : 
      66                 :          3 :         mutex_unlock(&chip->audio_mutex);
      67                 :          3 :         return 0;
      68                 :            : }
      69                 :            : 
      70                 :          3 : static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
      71                 :            :                                struct snd_ctl_elem_value *ucontrol)
      72                 :            : {
      73                 :          3 :         struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
      74                 :            :         int val, *valp;
      75                 :            :         int changed = 0;
      76                 :            : 
      77                 :          3 :         if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
      78                 :          3 :                 valp = &chip->volume;
      79                 :          3 :         else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
      80                 :          3 :                 valp = &chip->mute;
      81                 :          0 :         else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
      82                 :          0 :                 valp = &chip->dest;
      83                 :            :         else
      84                 :            :                 return -EINVAL;
      85                 :            : 
      86                 :          3 :         val = ucontrol->value.integer.value[0];
      87                 :          3 :         mutex_lock(&chip->audio_mutex);
      88                 :          3 :         if (val != *valp) {
      89                 :          3 :                 *valp = val;
      90                 :            :                 changed = 1;
      91                 :          3 :                 if (bcm2835_audio_set_chip_ctls(chip))
      92                 :          0 :                         dev_err(chip->card->dev, "Failed to set ALSA controls..\n");
      93                 :            :         }
      94                 :          3 :         mutex_unlock(&chip->audio_mutex);
      95                 :          3 :         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                 :          0 : static int snd_bcm2835_spdif_default_info(struct snd_kcontrol *kcontrol,
     132                 :            :                                           struct snd_ctl_elem_info *uinfo)
     133                 :            : {
     134                 :          0 :         uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
     135                 :          0 :         uinfo->count = 1;
     136                 :          0 :         return 0;
     137                 :            : }
     138                 :            : 
     139                 :          0 : static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol,
     140                 :            :                                          struct snd_ctl_elem_value *ucontrol)
     141                 :            : {
     142                 :          0 :         struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
     143                 :            :         int i;
     144                 :            : 
     145                 :          0 :         mutex_lock(&chip->audio_mutex);
     146                 :            : 
     147                 :          0 :         for (i = 0; i < 4; i++)
     148                 :          0 :                 ucontrol->value.iec958.status[i] =
     149                 :          0 :                         (chip->spdif_status >> (i * 8)) & 0xff;
     150                 :            : 
     151                 :          0 :         mutex_unlock(&chip->audio_mutex);
     152                 :          0 :         return 0;
     153                 :            : }
     154                 :            : 
     155                 :          0 : static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol,
     156                 :            :                                          struct snd_ctl_elem_value *ucontrol)
     157                 :            : {
     158                 :          0 :         struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
     159                 :            :         unsigned int val = 0;
     160                 :            :         int i, change;
     161                 :            : 
     162                 :          0 :         mutex_lock(&chip->audio_mutex);
     163                 :            : 
     164                 :          0 :         for (i = 0; i < 4; i++)
     165                 :          0 :                 val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
     166                 :            : 
     167                 :          0 :         change = val != chip->spdif_status;
     168                 :          0 :         chip->spdif_status = val;
     169                 :            : 
     170                 :          0 :         mutex_unlock(&chip->audio_mutex);
     171                 :          0 :         return change;
     172                 :            : }
     173                 :            : 
     174                 :          0 : static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol,
     175                 :            :                                        struct snd_ctl_elem_info *uinfo)
     176                 :            : {
     177                 :          0 :         uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
     178                 :          0 :         uinfo->count = 1;
     179                 :          0 :         return 0;
     180                 :            : }
     181                 :            : 
     182                 :          0 : 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                 :          0 :         ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO;
     190                 :          0 :         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                 :          3 : 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                 :          3 :         for (i = 0; i < size; i++) {
     216                 :          3 :                 err = snd_ctl_add(chip->card, snd_ctl_new1(&kctls[i], chip));
     217                 :          3 :                 if (err < 0)
     218                 :          0 :                         return err;
     219                 :            :         }
     220                 :            :         return 0;
     221                 :            : }
     222                 :            : 
     223                 :          0 : int snd_bcm2835_new_ctl(struct bcm2835_chip *chip)
     224                 :            : {
     225                 :            :         int err;
     226                 :            : 
     227                 :          0 :         strcpy(chip->card->mixername, "Broadcom Mixer");
     228                 :          0 :         err = create_ctls(chip, ARRAY_SIZE(snd_bcm2835_ctl), snd_bcm2835_ctl);
     229                 :          0 :         if (err < 0)
     230                 :            :                 return err;
     231                 :          0 :         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                 :          3 : int snd_bcm2835_new_headphones_ctl(struct bcm2835_chip *chip)
     263                 :            : {
     264                 :          3 :         strcpy(chip->card->mixername, "Broadcom Mixer");
     265                 :          3 :         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                 :          3 : int snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip *chip)
     297                 :            : {
     298                 :          3 :         strcpy(chip->card->mixername, "Broadcom Mixer");
     299                 :          3 :         return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_hdmi),
     300                 :            :                            snd_bcm2835_hdmi);
     301                 :            : }
     302                 :            : 
    

Generated by: LCOV version 1.14