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
bcm2835_audio_set_chip_ctls(struct bcm2835_chip * chip)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
snd_bcm2835_ctl_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)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
snd_bcm2835_ctl_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)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
snd_bcm2835_ctl_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)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 struct snd_ctl_elem_info info;
75 int val, *valp;
76 int changed = 0;
77
78 if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
79 valp = &chip->volume;
80 else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
81 valp = &chip->mute;
82 else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
83 valp = &chip->dest;
84 else
85 return -EINVAL;
86
87 val = ucontrol->value.integer.value[0];
88
89 snd_bcm2835_ctl_info(kcontrol, &info);
90 if (val < info.value.integer.min || val > info.value.integer.max)
91 return -EINVAL;
92
93 mutex_lock(&chip->audio_mutex);
94 if (val != *valp) {
95 *valp = val;
96 changed = 1;
97 if (bcm2835_audio_set_chip_ctls(chip))
98 dev_err(chip->card->dev, "Failed to set ALSA controls..\n");
99 }
100 mutex_unlock(&chip->audio_mutex);
101 return changed;
102 }
103
104 static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
105
106 static const struct snd_kcontrol_new snd_bcm2835_ctl[] = {
107 {
108 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
109 .name = "PCM Playback Volume",
110 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
111 .private_value = PCM_PLAYBACK_VOLUME,
112 .info = snd_bcm2835_ctl_info,
113 .get = snd_bcm2835_ctl_get,
114 .put = snd_bcm2835_ctl_put,
115 .tlv = {.p = snd_bcm2835_db_scale}
116 },
117 {
118 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
119 .name = "PCM Playback Switch",
120 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
121 .private_value = PCM_PLAYBACK_MUTE,
122 .info = snd_bcm2835_ctl_info,
123 .get = snd_bcm2835_ctl_get,
124 .put = snd_bcm2835_ctl_put,
125 },
126 };
127
snd_bcm2835_spdif_default_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)128 static int snd_bcm2835_spdif_default_info(struct snd_kcontrol *kcontrol,
129 struct snd_ctl_elem_info *uinfo)
130 {
131 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
132 uinfo->count = 1;
133 return 0;
134 }
135
snd_bcm2835_spdif_default_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)136 static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol,
137 struct snd_ctl_elem_value *ucontrol)
138 {
139 struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
140 int i;
141
142 mutex_lock(&chip->audio_mutex);
143
144 for (i = 0; i < 4; i++)
145 ucontrol->value.iec958.status[i] =
146 (chip->spdif_status >> (i * 8)) & 0xff;
147
148 mutex_unlock(&chip->audio_mutex);
149 return 0;
150 }
151
snd_bcm2835_spdif_default_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)152 static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol,
153 struct snd_ctl_elem_value *ucontrol)
154 {
155 struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
156 unsigned int val = 0;
157 int i, change;
158
159 mutex_lock(&chip->audio_mutex);
160
161 for (i = 0; i < 4; i++)
162 val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
163
164 change = val != chip->spdif_status;
165 chip->spdif_status = val;
166
167 mutex_unlock(&chip->audio_mutex);
168 return change;
169 }
170
snd_bcm2835_spdif_mask_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)171 static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol,
172 struct snd_ctl_elem_info *uinfo)
173 {
174 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
175 uinfo->count = 1;
176 return 0;
177 }
178
snd_bcm2835_spdif_mask_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)179 static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol,
180 struct snd_ctl_elem_value *ucontrol)
181 {
182 /*
183 * bcm2835 supports only consumer mode and sets all other format flags
184 * automatically. So the only thing left is signalling non-audio content
185 */
186 ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO;
187 return 0;
188 }
189
190 static const struct snd_kcontrol_new snd_bcm2835_spdif[] = {
191 {
192 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
193 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
194 .info = snd_bcm2835_spdif_default_info,
195 .get = snd_bcm2835_spdif_default_get,
196 .put = snd_bcm2835_spdif_default_put
197 },
198 {
199 .access = SNDRV_CTL_ELEM_ACCESS_READ,
200 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
201 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
202 .info = snd_bcm2835_spdif_mask_info,
203 .get = snd_bcm2835_spdif_mask_get,
204 },
205 };
206
create_ctls(struct bcm2835_chip * chip,size_t size,const struct snd_kcontrol_new * kctls)207 static int create_ctls(struct bcm2835_chip *chip, size_t size,
208 const struct snd_kcontrol_new *kctls)
209 {
210 int i, err;
211
212 for (i = 0; i < size; i++) {
213 err = snd_ctl_add(chip->card, snd_ctl_new1(&kctls[i], chip));
214 if (err < 0)
215 return err;
216 }
217 return 0;
218 }
219
snd_bcm2835_new_headphones_ctl(struct bcm2835_chip * chip)220 int snd_bcm2835_new_headphones_ctl(struct bcm2835_chip *chip)
221 {
222 strscpy(chip->card->mixername, "Broadcom Mixer", sizeof(chip->card->mixername));
223 return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_ctl),
224 snd_bcm2835_ctl);
225 }
226
snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip * chip)227 int snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip *chip)
228 {
229 int err;
230
231 strscpy(chip->card->mixername, "Broadcom Mixer", sizeof(chip->card->mixername));
232 err = create_ctls(chip, ARRAY_SIZE(snd_bcm2835_ctl), snd_bcm2835_ctl);
233 if (err < 0)
234 return err;
235 return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_spdif),
236 snd_bcm2835_spdif);
237 }
238
239