1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright 2011 Broadcom Corporation. All rights reserved. */
4 #include <sound/core.h>
5 #include <sound/control.h>
7 #include <sound/asoundef.h>
11 /* volume maximum and minimum in terms of 0.01dB */
12 #define CTRL_VOL_MAX 400
13 #define CTRL_VOL_MIN -10239 /* originally -10240 */
15 static int bcm2835_audio_set_chip_ctls(struct bcm2835_chip *chip)
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]);
30 static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
31 struct snd_ctl_elem_info *uinfo)
33 if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
34 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
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;
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;
46 uinfo->value.integer.min = 0;
47 uinfo->value.integer.max = AUDIO_DEST_MAX - 1;
52 static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
53 struct snd_ctl_elem_value *ucontrol)
55 struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
57 mutex_lock(&chip->audio_mutex);
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;
66 mutex_unlock(&chip->audio_mutex);
70 static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
71 struct snd_ctl_elem_value *ucontrol)
73 struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
77 if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
79 else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
81 else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
86 val = ucontrol->value.integer.value[0];
87 mutex_lock(&chip->audio_mutex);
91 if (bcm2835_audio_set_chip_ctls(chip))
92 dev_err(chip->card->dev, "Failed to set ALSA controls..\n");
94 mutex_unlock(&chip->audio_mutex);
98 static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
100 static const struct snd_kcontrol_new snd_bcm2835_ctl[] = {
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}
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,
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,
131 static int snd_bcm2835_spdif_default_info(struct snd_kcontrol *kcontrol,
132 struct snd_ctl_elem_info *uinfo)
134 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
139 static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol,
140 struct snd_ctl_elem_value *ucontrol)
142 struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
145 mutex_lock(&chip->audio_mutex);
147 for (i = 0; i < 4; i++)
148 ucontrol->value.iec958.status[i] =
149 (chip->spdif_status >> (i * 8)) & 0xff;
151 mutex_unlock(&chip->audio_mutex);
155 static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol,
156 struct snd_ctl_elem_value *ucontrol)
158 struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
159 unsigned int val = 0;
162 mutex_lock(&chip->audio_mutex);
164 for (i = 0; i < 4; i++)
165 val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
167 change = val != chip->spdif_status;
168 chip->spdif_status = val;
170 mutex_unlock(&chip->audio_mutex);
174 static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol,
175 struct snd_ctl_elem_info *uinfo)
177 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
182 static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol,
183 struct snd_ctl_elem_value *ucontrol)
186 * bcm2835 supports only consumer mode and sets all other format flags
187 * automatically. So the only thing left is signalling non-audio content
189 ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO;
193 static const struct snd_kcontrol_new snd_bcm2835_spdif[] = {
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
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,
210 static int create_ctls(struct bcm2835_chip *chip, size_t size,
211 const struct snd_kcontrol_new *kctls)
215 for (i = 0; i < size; i++) {
216 err = snd_ctl_add(chip->card, snd_ctl_new1(&kctls[i], chip));
223 int snd_bcm2835_new_ctl(struct bcm2835_chip *chip)
227 strscpy(chip->card->mixername, "Broadcom Mixer", sizeof(chip->card->mixername));
228 err = create_ctls(chip, ARRAY_SIZE(snd_bcm2835_ctl), snd_bcm2835_ctl);
231 return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_spdif),
235 static const struct snd_kcontrol_new snd_bcm2835_headphones_ctl[] = {
237 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
238 .name = "Headphone Playback Volume",
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,
247 .tlv = {.p = snd_bcm2835_db_scale}
250 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
251 .name = "Headphone Playback Switch",
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,
262 int snd_bcm2835_new_headphones_ctl(struct bcm2835_chip *chip)
264 strscpy(chip->card->mixername, "Broadcom Mixer", sizeof(chip->card->mixername));
265 return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_headphones_ctl),
266 snd_bcm2835_headphones_ctl);
269 static const struct snd_kcontrol_new snd_bcm2835_hdmi[] = {
271 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
272 .name = "HDMI Playback Volume",
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,
281 .tlv = {.p = snd_bcm2835_db_scale}
284 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
285 .name = "HDMI Playback Switch",
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,
296 int snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip *chip)
298 strscpy(chip->card->mixername, "Broadcom Mixer", sizeof(chip->card->mixername));
299 return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_hdmi),