1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/platform_device.h>
16#include <linux/init.h>
17#include <linux/io.h>
18#include <linux/jiffies.h>
19#include <linux/slab.h>
20#include <linux/time.h>
21#include <linux/wait.h>
22#include <linux/delay.h>
23#include <linux/moduleparam.h>
24#include <linux/sched.h>
25
26#include <sound/core.h>
27#include <sound/control.h>
28#include <sound/pcm.h>
29#include <sound/pcm_params.h>
30#include <sound/rawmidi.h>
31#include <sound/initval.h>
32#include <sound/tlv.h>
33#include <sound/asoundef.h>
34
35#include "bcm2835.h"
36
37
38#define CTRL_VOL_MAX 400
39#define CTRL_VOL_MIN -10239
40
41static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
42 struct snd_ctl_elem_info *uinfo)
43{
44 if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
45 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
46 uinfo->count = 1;
47 uinfo->value.integer.min = CTRL_VOL_MIN;
48 uinfo->value.integer.max = CTRL_VOL_MAX;
49 } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
50 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
51 uinfo->count = 1;
52 uinfo->value.integer.min = 0;
53 uinfo->value.integer.max = 1;
54 } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
55 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
56 uinfo->count = 1;
57 uinfo->value.integer.min = 0;
58 uinfo->value.integer.max = AUDIO_DEST_MAX - 1;
59 }
60 return 0;
61}
62
63
64
65
66static int toggle_mute(struct bcm2835_chip *chip, int nmute)
67{
68
69 if (chip->mute == nmute)
70 return 0;
71
72
73 if (chip->mute == CTRL_VOL_MUTE) {
74 chip->volume = chip->old_volume;
75 audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
76 } else {
77 chip->old_volume = chip->volume;
78 chip->volume = 26214;
79 audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
80 }
81
82 chip->mute = nmute;
83 return 1;
84}
85
86static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
87 struct snd_ctl_elem_value *ucontrol)
88{
89 struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
90
91 if (mutex_lock_interruptible(&chip->audio_mutex))
92 return -EINTR;
93
94 BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
95
96 if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
97 ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
98 else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
99 ucontrol->value.integer.value[0] = chip->mute;
100 else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
101 ucontrol->value.integer.value[0] = chip->dest;
102
103 mutex_unlock(&chip->audio_mutex);
104 return 0;
105}
106
107static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
108 struct snd_ctl_elem_value *ucontrol)
109{
110 struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
111 int changed = 0;
112
113 if (mutex_lock_interruptible(&chip->audio_mutex))
114 return -EINTR;
115
116 if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
117 audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
118 if (chip->mute == CTRL_VOL_MUTE) {
119
120 changed = 1;
121 goto unlock;
122 }
123 if (changed || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
124 chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
125 changed = 1;
126 }
127
128 } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
129
130 audio_info(" Mute attempted\n");
131 changed = toggle_mute(chip, ucontrol->value.integer.value[0]);
132
133 } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
134 if (ucontrol->value.integer.value[0] != chip->dest) {
135 chip->dest = ucontrol->value.integer.value[0];
136 changed = 1;
137 }
138 }
139
140 if (changed && bcm2835_audio_set_ctls(chip))
141 dev_err(chip->card->dev, "Failed to set ALSA controls..\n");
142
143unlock:
144 mutex_unlock(&chip->audio_mutex);
145 return changed;
146}
147
148static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
149
150static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
151 {
152 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
153 .name = "PCM Playback Volume",
154 .index = 0,
155 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
156 .private_value = PCM_PLAYBACK_VOLUME,
157 .info = snd_bcm2835_ctl_info,
158 .get = snd_bcm2835_ctl_get,
159 .put = snd_bcm2835_ctl_put,
160 .count = 1,
161 .tlv = {.p = snd_bcm2835_db_scale}
162 },
163 {
164 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
165 .name = "PCM Playback Switch",
166 .index = 0,
167 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
168 .private_value = PCM_PLAYBACK_MUTE,
169 .info = snd_bcm2835_ctl_info,
170 .get = snd_bcm2835_ctl_get,
171 .put = snd_bcm2835_ctl_put,
172 .count = 1,
173 },
174 {
175 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
176 .name = "PCM Playback Route",
177 .index = 0,
178 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
179 .private_value = PCM_PLAYBACK_DEVICE,
180 .info = snd_bcm2835_ctl_info,
181 .get = snd_bcm2835_ctl_get,
182 .put = snd_bcm2835_ctl_put,
183 .count = 1,
184 },
185};
186
187static int snd_bcm2835_spdif_default_info(struct snd_kcontrol *kcontrol,
188 struct snd_ctl_elem_info *uinfo)
189{
190 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
191 uinfo->count = 1;
192 return 0;
193}
194
195static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol,
196 struct snd_ctl_elem_value *ucontrol)
197{
198 struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
199 int i;
200
201 if (mutex_lock_interruptible(&chip->audio_mutex))
202 return -EINTR;
203
204 for (i = 0; i < 4; i++)
205 ucontrol->value.iec958.status[i] =
206 (chip->spdif_status >> (i * 8)) & 0xff;
207
208 mutex_unlock(&chip->audio_mutex);
209 return 0;
210}
211
212static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol,
213 struct snd_ctl_elem_value *ucontrol)
214{
215 struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
216 unsigned int val = 0;
217 int i, change;
218
219 if (mutex_lock_interruptible(&chip->audio_mutex))
220 return -EINTR;
221
222 for (i = 0; i < 4; i++)
223 val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
224
225 change = val != chip->spdif_status;
226 chip->spdif_status = val;
227
228 mutex_unlock(&chip->audio_mutex);
229 return change;
230}
231
232static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol,
233 struct snd_ctl_elem_info *uinfo)
234{
235 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
236 uinfo->count = 1;
237 return 0;
238}
239
240static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol,
241 struct snd_ctl_elem_value *ucontrol)
242{
243
244
245
246
247 ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO;
248 return 0;
249}
250
251static int snd_bcm2835_spdif_stream_info(struct snd_kcontrol *kcontrol,
252 struct snd_ctl_elem_info *uinfo)
253{
254 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
255 uinfo->count = 1;
256 return 0;
257}
258
259static int snd_bcm2835_spdif_stream_get(struct snd_kcontrol *kcontrol,
260 struct snd_ctl_elem_value *ucontrol)
261{
262 struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
263 int i;
264
265 if (mutex_lock_interruptible(&chip->audio_mutex))
266 return -EINTR;
267
268 for (i = 0; i < 4; i++)
269 ucontrol->value.iec958.status[i] =
270 (chip->spdif_status >> (i * 8)) & 0xff;
271
272 mutex_unlock(&chip->audio_mutex);
273 return 0;
274}
275
276static int snd_bcm2835_spdif_stream_put(struct snd_kcontrol *kcontrol,
277 struct snd_ctl_elem_value *ucontrol)
278{
279 struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
280 unsigned int val = 0;
281 int i, change;
282
283 if (mutex_lock_interruptible(&chip->audio_mutex))
284 return -EINTR;
285
286 for (i = 0; i < 4; i++)
287 val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
288 change = val != chip->spdif_status;
289 chip->spdif_status = val;
290
291 mutex_unlock(&chip->audio_mutex);
292 return change;
293}
294
295static struct snd_kcontrol_new snd_bcm2835_spdif[] = {
296 {
297 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
298 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
299 .info = snd_bcm2835_spdif_default_info,
300 .get = snd_bcm2835_spdif_default_get,
301 .put = snd_bcm2835_spdif_default_put
302 },
303 {
304 .access = SNDRV_CTL_ELEM_ACCESS_READ,
305 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
306 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
307 .info = snd_bcm2835_spdif_mask_info,
308 .get = snd_bcm2835_spdif_mask_get,
309 },
310 {
311 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
312 SNDRV_CTL_ELEM_ACCESS_INACTIVE,
313 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
314 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
315 .info = snd_bcm2835_spdif_stream_info,
316 .get = snd_bcm2835_spdif_stream_get,
317 .put = snd_bcm2835_spdif_stream_put,
318 },
319};
320
321int snd_bcm2835_new_ctl(struct bcm2835_chip *chip)
322{
323 int err;
324 unsigned int idx;
325
326 strcpy(chip->card->mixername, "Broadcom Mixer");
327 for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
328 err = snd_ctl_add(chip->card,
329 snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
330 if (err < 0)
331 return err;
332 }
333 for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) {
334 err = snd_ctl_add(chip->card,
335 snd_ctl_new1(&snd_bcm2835_spdif[idx], chip));
336 if (err < 0)
337 return err;
338 }
339 return 0;
340}
341
342static struct snd_kcontrol_new snd_bcm2835_headphones_ctl[] = {
343 {
344 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
345 .name = "Headphone Playback Volume",
346 .index = 0,
347 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
348 SNDRV_CTL_ELEM_ACCESS_TLV_READ,
349 .private_value = PCM_PLAYBACK_VOLUME,
350 .info = snd_bcm2835_ctl_info,
351 .get = snd_bcm2835_ctl_get,
352 .put = snd_bcm2835_ctl_put,
353 .count = 1,
354 .tlv = {.p = snd_bcm2835_db_scale}
355 },
356 {
357 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
358 .name = "Headphone Playback Switch",
359 .index = 0,
360 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
361 .private_value = PCM_PLAYBACK_MUTE,
362 .info = snd_bcm2835_ctl_info,
363 .get = snd_bcm2835_ctl_get,
364 .put = snd_bcm2835_ctl_put,
365 .count = 1,
366 }
367};
368
369int snd_bcm2835_new_headphones_ctl(struct bcm2835_chip *chip)
370{
371 int err;
372 unsigned int idx;
373
374 strcpy(chip->card->mixername, "Broadcom Mixer");
375 for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_headphones_ctl); idx++) {
376 err = snd_ctl_add(chip->card,
377 snd_ctl_new1(&snd_bcm2835_headphones_ctl[idx],
378 chip));
379 if (err)
380 return err;
381 }
382 return 0;
383}
384
385static struct snd_kcontrol_new snd_bcm2835_hdmi[] = {
386 {
387 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
388 .name = "HDMI Playback Volume",
389 .index = 0,
390 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
391 SNDRV_CTL_ELEM_ACCESS_TLV_READ,
392 .private_value = PCM_PLAYBACK_VOLUME,
393 .info = snd_bcm2835_ctl_info,
394 .get = snd_bcm2835_ctl_get,
395 .put = snd_bcm2835_ctl_put,
396 .count = 1,
397 .tlv = {.p = snd_bcm2835_db_scale}
398 },
399 {
400 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
401 .name = "HDMI Playback Switch",
402 .index = 0,
403 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
404 .private_value = PCM_PLAYBACK_MUTE,
405 .info = snd_bcm2835_ctl_info,
406 .get = snd_bcm2835_ctl_get,
407 .put = snd_bcm2835_ctl_put,
408 .count = 1,
409 }
410};
411
412int snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip *chip)
413{
414 int err;
415 unsigned int idx;
416
417 strcpy(chip->card->mixername, "Broadcom Mixer");
418 for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_hdmi); idx++) {
419 err = snd_ctl_add(chip->card,
420 snd_ctl_new1(&snd_bcm2835_hdmi[idx], chip));
421 if (err)
422 return err;
423 }
424 return 0;
425}
426
427