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 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
snd_bcm2835_spdif_default_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)122 static int snd_bcm2835_spdif_default_info(struct snd_kcontrol *kcontrol,
123 struct snd_ctl_elem_info *uinfo)
124 {
125 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
126 uinfo->count = 1;
127 return 0;
128 }
129
snd_bcm2835_spdif_default_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)130 static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol,
131 struct snd_ctl_elem_value *ucontrol)
132 {
133 struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
134 int i;
135
136 mutex_lock(&chip->audio_mutex);
137
138 for (i = 0; i < 4; i++)
139 ucontrol->value.iec958.status[i] =
140 (chip->spdif_status >> (i * 8)) & 0xff;
141
142 mutex_unlock(&chip->audio_mutex);
143 return 0;
144 }
145
snd_bcm2835_spdif_default_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)146 static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol,
147 struct snd_ctl_elem_value *ucontrol)
148 {
149 struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
150 unsigned int val = 0;
151 int i, change;
152
153 mutex_lock(&chip->audio_mutex);
154
155 for (i = 0; i < 4; i++)
156 val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
157
158 change = val != chip->spdif_status;
159 chip->spdif_status = val;
160
161 mutex_unlock(&chip->audio_mutex);
162 return change;
163 }
164
snd_bcm2835_spdif_mask_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)165 static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol,
166 struct snd_ctl_elem_info *uinfo)
167 {
168 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
169 uinfo->count = 1;
170 return 0;
171 }
172
snd_bcm2835_spdif_mask_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)173 static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol,
174 struct snd_ctl_elem_value *ucontrol)
175 {
176 /*
177 * bcm2835 supports only consumer mode and sets all other format flags
178 * automatically. So the only thing left is signalling non-audio content
179 */
180 ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO;
181 return 0;
182 }
183
184 static const struct snd_kcontrol_new snd_bcm2835_spdif[] = {
185 {
186 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
187 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
188 .info = snd_bcm2835_spdif_default_info,
189 .get = snd_bcm2835_spdif_default_get,
190 .put = snd_bcm2835_spdif_default_put
191 },
192 {
193 .access = SNDRV_CTL_ELEM_ACCESS_READ,
194 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
195 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
196 .info = snd_bcm2835_spdif_mask_info,
197 .get = snd_bcm2835_spdif_mask_get,
198 },
199 };
200
create_ctls(struct bcm2835_chip * chip,size_t size,const struct snd_kcontrol_new * kctls)201 static int create_ctls(struct bcm2835_chip *chip, size_t size,
202 const struct snd_kcontrol_new *kctls)
203 {
204 int i, err;
205
206 for (i = 0; i < size; i++) {
207 err = snd_ctl_add(chip->card, snd_ctl_new1(&kctls[i], chip));
208 if (err < 0)
209 return err;
210 }
211 return 0;
212 }
213
snd_bcm2835_new_headphones_ctl(struct bcm2835_chip * chip)214 int snd_bcm2835_new_headphones_ctl(struct bcm2835_chip *chip)
215 {
216 strscpy(chip->card->mixername, "Broadcom Mixer", sizeof(chip->card->mixername));
217 return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_ctl),
218 snd_bcm2835_ctl);
219 }
220
snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip * chip)221 int snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip *chip)
222 {
223 int err;
224
225 strscpy(chip->card->mixername, "Broadcom Mixer", sizeof(chip->card->mixername));
226 err = create_ctls(chip, ARRAY_SIZE(snd_bcm2835_ctl), snd_bcm2835_ctl);
227 if (err < 0)
228 return err;
229 return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_spdif),
230 snd_bcm2835_spdif);
231 }
232
233