]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
staging: bcm2835-audio: Remove redundant spdif stream ctls
[linux.git] / drivers / staging / vc04_services / bcm2835-audio / bcm2835-ctl.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright 2011 Broadcom Corporation.  All rights reserved. */
3
4 #include <linux/platform_device.h>
5 #include <linux/init.h>
6 #include <linux/io.h>
7 #include <linux/jiffies.h>
8 #include <linux/slab.h>
9 #include <linux/time.h>
10 #include <linux/wait.h>
11 #include <linux/delay.h>
12 #include <linux/moduleparam.h>
13 #include <linux/sched.h>
14
15 #include <sound/core.h>
16 #include <sound/control.h>
17 #include <sound/pcm.h>
18 #include <sound/pcm_params.h>
19 #include <sound/rawmidi.h>
20 #include <sound/initval.h>
21 #include <sound/tlv.h>
22 #include <sound/asoundef.h>
23
24 #include "bcm2835.h"
25
26 /* volume maximum and minimum in terms of 0.01dB */
27 #define CTRL_VOL_MAX 400
28 #define CTRL_VOL_MIN -10239 /* originally -10240 */
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 /* toggles mute on or off depending on the value of nmute, and returns
53  * 1 if the mute value was changed, otherwise 0
54  */
55 static int toggle_mute(struct bcm2835_chip *chip, int nmute)
56 {
57         /* if settings are ok, just return 0 */
58         if (chip->mute == nmute)
59                 return 0;
60
61         /* if the sound is muted then we need to unmute */
62         if (chip->mute == CTRL_VOL_MUTE) {
63                 chip->volume = chip->old_volume; /* copy the old volume back */
64                 audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
65         } else /* otherwise we mute */ {
66                 chip->old_volume = chip->volume;
67                 chip->volume = 26214; /* set volume to minimum level AKA mute */
68                 audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
69         }
70
71         chip->mute = nmute;
72         return 1;
73 }
74
75 static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
76                                struct snd_ctl_elem_value *ucontrol)
77 {
78         struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
79
80         mutex_lock(&chip->audio_mutex);
81
82         BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
83
84         if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
85                 ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
86         else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
87                 ucontrol->value.integer.value[0] = chip->mute;
88         else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
89                 ucontrol->value.integer.value[0] = chip->dest;
90
91         mutex_unlock(&chip->audio_mutex);
92         return 0;
93 }
94
95 static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
96                                 struct snd_ctl_elem_value *ucontrol)
97 {
98         struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
99         int changed = 0;
100
101         mutex_lock(&chip->audio_mutex);
102
103         if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
104                 audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
105                 if (chip->mute == CTRL_VOL_MUTE) {
106                         /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
107                         changed = 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
108                         goto unlock;
109                 }
110                 if (changed || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
111                         chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
112                         changed = 1;
113                 }
114
115         } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
116                 /* Now implemented */
117                 audio_info(" Mute attempted\n");
118                 changed = toggle_mute(chip, ucontrol->value.integer.value[0]);
119
120         } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
121                 if (ucontrol->value.integer.value[0] != chip->dest) {
122                         chip->dest = ucontrol->value.integer.value[0];
123                         changed = 1;
124                 }
125         }
126
127         if (changed && bcm2835_audio_set_ctls(chip))
128                 dev_err(chip->card->dev, "Failed to set ALSA controls..\n");
129
130 unlock:
131         mutex_unlock(&chip->audio_mutex);
132         return changed;
133 }
134
135 static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
136
137 static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
138         {
139                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
140                 .name = "PCM Playback Volume",
141                 .index = 0,
142                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
143                 .private_value = PCM_PLAYBACK_VOLUME,
144                 .info = snd_bcm2835_ctl_info,
145                 .get = snd_bcm2835_ctl_get,
146                 .put = snd_bcm2835_ctl_put,
147                 .count = 1,
148                 .tlv = {.p = snd_bcm2835_db_scale}
149         },
150         {
151                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
152                 .name = "PCM Playback Switch",
153                 .index = 0,
154                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
155                 .private_value = PCM_PLAYBACK_MUTE,
156                 .info = snd_bcm2835_ctl_info,
157                 .get = snd_bcm2835_ctl_get,
158                 .put = snd_bcm2835_ctl_put,
159                 .count = 1,
160         },
161         {
162                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
163                 .name = "PCM Playback Route",
164                 .index = 0,
165                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
166                 .private_value = PCM_PLAYBACK_DEVICE,
167                 .info = snd_bcm2835_ctl_info,
168                 .get = snd_bcm2835_ctl_get,
169                 .put = snd_bcm2835_ctl_put,
170                 .count = 1,
171         },
172 };
173
174 static int snd_bcm2835_spdif_default_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_default_get(struct snd_kcontrol *kcontrol,
183         struct snd_ctl_elem_value *ucontrol)
184 {
185         struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
186         int i;
187
188         mutex_lock(&chip->audio_mutex);
189
190         for (i = 0; i < 4; i++)
191                 ucontrol->value.iec958.status[i] =
192                         (chip->spdif_status >> (i * 8)) & 0xff;
193
194         mutex_unlock(&chip->audio_mutex);
195         return 0;
196 }
197
198 static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol,
199         struct snd_ctl_elem_value *ucontrol)
200 {
201         struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
202         unsigned int val = 0;
203         int i, change;
204
205         mutex_lock(&chip->audio_mutex);
206
207         for (i = 0; i < 4; i++)
208                 val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
209
210         change = val != chip->spdif_status;
211         chip->spdif_status = val;
212
213         mutex_unlock(&chip->audio_mutex);
214         return change;
215 }
216
217 static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol,
218         struct snd_ctl_elem_info *uinfo)
219 {
220         uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
221         uinfo->count = 1;
222         return 0;
223 }
224
225 static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol,
226         struct snd_ctl_elem_value *ucontrol)
227 {
228         /*
229          * bcm2835 supports only consumer mode and sets all other format flags
230          * automatically. So the only thing left is signalling non-audio content
231          */
232         ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO;
233         return 0;
234 }
235
236 static struct snd_kcontrol_new snd_bcm2835_spdif[] = {
237         {
238                 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
239                 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
240                 .info = snd_bcm2835_spdif_default_info,
241                 .get = snd_bcm2835_spdif_default_get,
242                 .put = snd_bcm2835_spdif_default_put
243         },
244         {
245                 .access = SNDRV_CTL_ELEM_ACCESS_READ,
246                 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
247                 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
248                 .info = snd_bcm2835_spdif_mask_info,
249                 .get = snd_bcm2835_spdif_mask_get,
250         },
251 };
252
253 int snd_bcm2835_new_ctl(struct bcm2835_chip *chip)
254 {
255         int err;
256         unsigned int idx;
257
258         strcpy(chip->card->mixername, "Broadcom Mixer");
259         for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
260                 err = snd_ctl_add(chip->card,
261                                   snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
262                 if (err < 0)
263                         return err;
264         }
265         for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) {
266                 err = snd_ctl_add(chip->card,
267                                   snd_ctl_new1(&snd_bcm2835_spdif[idx], chip));
268                 if (err < 0)
269                         return err;
270         }
271         return 0;
272 }
273
274 static struct snd_kcontrol_new snd_bcm2835_headphones_ctl[] = {
275         {
276                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
277                 .name = "Headphone Playback Volume",
278                 .index = 0,
279                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
280                           SNDRV_CTL_ELEM_ACCESS_TLV_READ,
281                 .private_value = PCM_PLAYBACK_VOLUME,
282                 .info = snd_bcm2835_ctl_info,
283                 .get = snd_bcm2835_ctl_get,
284                 .put = snd_bcm2835_ctl_put,
285                 .count = 1,
286                 .tlv = {.p = snd_bcm2835_db_scale}
287         },
288         {
289                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
290                 .name = "Headphone Playback Switch",
291                 .index = 0,
292                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
293                 .private_value = PCM_PLAYBACK_MUTE,
294                 .info = snd_bcm2835_ctl_info,
295                 .get = snd_bcm2835_ctl_get,
296                 .put = snd_bcm2835_ctl_put,
297                 .count = 1,
298         }
299 };
300
301 int snd_bcm2835_new_headphones_ctl(struct bcm2835_chip *chip)
302 {
303         int err;
304         unsigned int idx;
305
306         strcpy(chip->card->mixername, "Broadcom Mixer");
307         for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_headphones_ctl); idx++) {
308                 err = snd_ctl_add(chip->card,
309                                   snd_ctl_new1(&snd_bcm2835_headphones_ctl[idx],
310                                                chip));
311                 if (err)
312                         return err;
313         }
314         return 0;
315 }
316
317 static struct snd_kcontrol_new snd_bcm2835_hdmi[] = {
318         {
319                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
320                 .name = "HDMI Playback Volume",
321                 .index = 0,
322                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
323                           SNDRV_CTL_ELEM_ACCESS_TLV_READ,
324                 .private_value = PCM_PLAYBACK_VOLUME,
325                 .info = snd_bcm2835_ctl_info,
326                 .get = snd_bcm2835_ctl_get,
327                 .put = snd_bcm2835_ctl_put,
328                 .count = 1,
329                 .tlv = {.p = snd_bcm2835_db_scale}
330         },
331         {
332                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
333                 .name = "HDMI Playback Switch",
334                 .index = 0,
335                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
336                 .private_value = PCM_PLAYBACK_MUTE,
337                 .info = snd_bcm2835_ctl_info,
338                 .get = snd_bcm2835_ctl_get,
339                 .put = snd_bcm2835_ctl_put,
340                 .count = 1,
341         }
342 };
343
344 int snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip *chip)
345 {
346         int err;
347         unsigned int idx;
348
349         strcpy(chip->card->mixername, "Broadcom Mixer");
350         for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_hdmi); idx++) {
351                 err = snd_ctl_add(chip->card,
352                                   snd_ctl_new1(&snd_bcm2835_hdmi[idx], chip));
353                 if (err)
354                         return err;
355         }
356         return 0;
357 }
358