Skip to content

Commit 62572b0

Browse files
committed
bcm2708: alsa sound driver
Signed-off-by: popcornmix <[email protected]>
1 parent 94071db commit 62572b0

File tree

11 files changed

+2243
-0
lines changed

11 files changed

+2243
-0
lines changed

arch/arm/configs/bcmrpi_cutdown_defconfig

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,26 @@ CONFIG_FRAMEBUFFER_CONSOLE=y
208208
CONFIG_LOGO=y
209209
# CONFIG_LOGO_LINUX_MONO is not set
210210
# CONFIG_LOGO_LINUX_VGA16 is not set
211+
CONFIG_SOUND=y
212+
CONFIG_SND=m
213+
CONFIG_SND_SEQUENCER=m
214+
CONFIG_SND_SEQ_DUMMY=m
215+
CONFIG_SND_MIXER_OSS=m
216+
CONFIG_SND_PCM_OSS=m
217+
CONFIG_SND_SEQUENCER_OSS=y
218+
CONFIG_SND_HRTIMER=m
219+
CONFIG_SND_DUMMY=m
220+
CONFIG_SND_ALOOP=m
221+
CONFIG_SND_VIRMIDI=m
222+
CONFIG_SND_MTPAV=m
223+
CONFIG_SND_SERIAL_U16550=m
224+
CONFIG_SND_MPU401=m
225+
CONFIG_SND_BCM2835=m
226+
CONFIG_SND_USB_AUDIO=m
227+
CONFIG_SND_USB_UA101=m
228+
CONFIG_SND_USB_CAIAQ=m
229+
CONFIG_SND_USB_6FIRE=m
230+
CONFIG_SOUND_PRIME=m
211231
CONFIG_HID_PID=y
212232
CONFIG_USB_HIDDEV=y
213233
CONFIG_HID_A4TECH=m

arch/arm/configs/bcmrpi_defconfig

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,26 @@ CONFIG_FRAMEBUFFER_CONSOLE=y
225225
CONFIG_LOGO=y
226226
# CONFIG_LOGO_LINUX_MONO is not set
227227
# CONFIG_LOGO_LINUX_VGA16 is not set
228+
CONFIG_SOUND=y
229+
CONFIG_SND=m
230+
CONFIG_SND_SEQUENCER=m
231+
CONFIG_SND_SEQ_DUMMY=m
232+
CONFIG_SND_MIXER_OSS=m
233+
CONFIG_SND_PCM_OSS=m
234+
CONFIG_SND_SEQUENCER_OSS=y
235+
CONFIG_SND_HRTIMER=m
236+
CONFIG_SND_DUMMY=m
237+
CONFIG_SND_ALOOP=m
238+
CONFIG_SND_VIRMIDI=m
239+
CONFIG_SND_MTPAV=m
240+
CONFIG_SND_SERIAL_U16550=m
241+
CONFIG_SND_MPU401=m
242+
CONFIG_SND_BCM2835=m
243+
CONFIG_SND_USB_AUDIO=m
244+
CONFIG_SND_USB_UA101=m
245+
CONFIG_SND_USB_CAIAQ=m
246+
CONFIG_SND_USB_6FIRE=m
247+
CONFIG_SOUND_PRIME=m
228248
CONFIG_HID_PID=y
229249
CONFIG_USB_HIDDEV=y
230250
CONFIG_HID_A4TECH=m

arch/arm/mach-bcm2708/bcm2708.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,58 @@ struct platform_device bcm2708_powerman_device = {
431431
.coherent_dma_mask = 0xffffffffUL},
432432
};
433433

434+
435+
static struct platform_device bcm2708_alsa_devices[] = {
436+
[0] = {
437+
.name = "bcm2835_AUD0",
438+
.id = 0, /* first audio device */
439+
.resource = 0,
440+
.num_resources = 0,
441+
},
442+
[1] = {
443+
.name = "bcm2835_AUD1",
444+
.id = 1, /* second audio device */
445+
.resource = 0,
446+
.num_resources = 0,
447+
},
448+
[2] = {
449+
.name = "bcm2835_AUD2",
450+
.id = 2, /* third audio device */
451+
.resource = 0,
452+
.num_resources = 0,
453+
},
454+
[3] = {
455+
.name = "bcm2835_AUD3",
456+
.id = 3, /* forth audio device */
457+
.resource = 0,
458+
.num_resources = 0,
459+
},
460+
[4] = {
461+
.name = "bcm2835_AUD4",
462+
.id = 4, /* fifth audio device */
463+
.resource = 0,
464+
.num_resources = 0,
465+
},
466+
[5] = {
467+
.name = "bcm2835_AUD5",
468+
.id = 5, /* sixth audio device */
469+
.resource = 0,
470+
.num_resources = 0,
471+
},
472+
[6] = {
473+
.name = "bcm2835_AUD6",
474+
.id = 6, /* seventh audio device */
475+
.resource = 0,
476+
.num_resources = 0,
477+
},
478+
[7] = {
479+
.name = "bcm2835_AUD7",
480+
.id = 7, /* eighth audio device */
481+
.resource = 0,
482+
.num_resources = 0,
483+
},
484+
};
485+
434486
int __init bcm_register_device(struct platform_device *pdev)
435487
{
436488
int ret;
@@ -539,6 +591,8 @@ void __init bcm2708_init(void)
539591
bcm_register_device(&bcm2708_emmc_device);
540592
#endif
541593
bcm2708_init_led();
594+
for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++)
595+
bcm_register_device(&bcm2708_alsa_devices[i]);
542596

543597
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
544598
struct amba_device *d = amba_devs[i];

sound/arm/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,12 @@ config SND_PXA2XX_AC97
3939
Say Y or M if you want to support any AC97 codec attached to
4040
the PXA2xx AC97 interface.
4141

42+
config SND_BCM2835
43+
tristate "BCM2835 ALSA driver"
44+
depends on ARCH_BCM2708 && BCM2708_VCHIQ && SND
45+
select SND_PCM
46+
help
47+
Say Y or M if you want to support BCM2835 Alsa pcm card driver
48+
4249
endif # SND_ARM
4350

sound/arm/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,8 @@ snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_AC97) += pxa2xx-ac97-lib.o
1414

1515
obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
1616
snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
17+
18+
obj-$(CONFIG_SND_BCM2835) += snd-bcm2835.o
19+
snd-bcm2835-objs := bcm2835.o bcm2835-ctl.o bcm2835-pcm.o bcm2835-vchiq.o
20+
21+
ccflags-y += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000

sound/arm/bcm2835-ctl.c

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
/*****************************************************************************
2+
* Copyright 2011 Broadcom Corporation. All rights reserved.
3+
*
4+
* Unless you and Broadcom execute a separate written software license
5+
* agreement governing use of this software, this software is licensed to you
6+
* under the terms of the GNU General Public License version 2, available at
7+
* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
8+
*
9+
* Notwithstanding the above, under no circumstances may you combine this
10+
* software in any way with any other Broadcom software provided under a
11+
* license other than the GPL, without Broadcom's express prior written
12+
* consent.
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+
34+
#include "bcm2835.h"
35+
36+
/* volume maximum and minimum in terms of 0.01dB */
37+
#define CTRL_VOL_MAX 400
38+
#define CTRL_VOL_MIN -10239 /* originally -10240 */
39+
40+
41+
static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
42+
struct snd_ctl_elem_info *uinfo)
43+
{
44+
audio_info(" ... IN\n");
45+
if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
46+
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
47+
uinfo->count = 1;
48+
uinfo->value.integer.min = CTRL_VOL_MIN;
49+
uinfo->value.integer.max = CTRL_VOL_MAX; /* 2303 */
50+
} else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
51+
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
52+
uinfo->count = 1;
53+
uinfo->value.integer.min = 0;
54+
uinfo->value.integer.max = 1;
55+
} else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
56+
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
57+
uinfo->count = 1;
58+
uinfo->value.integer.min = 0;
59+
uinfo->value.integer.max = AUDIO_DEST_MAX-1;
60+
}
61+
audio_info(" ... OUT\n");
62+
return 0;
63+
}
64+
65+
/* toggles mute on or off depending on the value of nmute, and returns
66+
* 1 if the mute value was changed, otherwise 0
67+
*/
68+
static int toggle_mute(struct bcm2835_chip *chip, int nmute)
69+
{
70+
/* if settings are ok, just return 0 */
71+
if(chip->mute == nmute)
72+
return 0;
73+
74+
/* if the sound is muted then we need to unmute */
75+
if(chip->mute == CTRL_VOL_MUTE)
76+
{
77+
chip->volume = chip->old_volume; /* copy the old volume back */
78+
audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
79+
}
80+
else /* otherwise we mute */
81+
{
82+
chip->old_volume = chip->volume;
83+
chip->volume = 26214; /* set volume to minimum level AKA mute */
84+
audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
85+
}
86+
87+
chip->mute = nmute;
88+
return 1;
89+
}
90+
91+
static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
92+
struct snd_ctl_elem_value *ucontrol)
93+
{
94+
struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
95+
96+
BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
97+
98+
if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
99+
ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
100+
else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
101+
ucontrol->value.integer.value[0] = chip->mute;
102+
else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
103+
ucontrol->value.integer.value[0] = chip->dest;
104+
105+
return 0;
106+
}
107+
108+
static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
109+
struct snd_ctl_elem_value *ucontrol)
110+
{
111+
struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
112+
int changed = 0;
113+
114+
if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
115+
audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
116+
if (chip->mute == CTRL_VOL_MUTE) {
117+
/* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
118+
return 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
119+
}
120+
if (changed
121+
|| (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
122+
123+
chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
124+
changed = 1;
125+
}
126+
127+
} else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
128+
/* Now implemented */
129+
audio_info(" Mute attempted\n");
130+
changed = toggle_mute(chip, ucontrol->value.integer.value[0]);
131+
132+
} else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
133+
if (ucontrol->value.integer.value[0] != chip->dest) {
134+
chip->dest = ucontrol->value.integer.value[0];
135+
changed = 1;
136+
}
137+
}
138+
139+
if (changed) {
140+
if (bcm2835_audio_set_ctls(chip))
141+
printk(KERN_ERR "Failed to set ALSA controls..\n");
142+
}
143+
144+
return changed;
145+
}
146+
147+
static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
148+
149+
static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
150+
{
151+
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
152+
.name = "PCM Playback Volume",
153+
.index = 0,
154+
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
155+
.private_value = PCM_PLAYBACK_VOLUME,
156+
.info = snd_bcm2835_ctl_info,
157+
.get = snd_bcm2835_ctl_get,
158+
.put = snd_bcm2835_ctl_put,
159+
.count = 1,
160+
.tlv = {.p = snd_bcm2835_db_scale}
161+
},
162+
{
163+
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
164+
.name = "PCM Playback Switch",
165+
.index = 0,
166+
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
167+
.private_value = PCM_PLAYBACK_MUTE,
168+
.info = snd_bcm2835_ctl_info,
169+
.get = snd_bcm2835_ctl_get,
170+
.put = snd_bcm2835_ctl_put,
171+
.count = 1,
172+
},
173+
{
174+
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
175+
.name = "PCM Playback Route",
176+
.index = 0,
177+
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
178+
.private_value = PCM_PLAYBACK_DEVICE,
179+
.info = snd_bcm2835_ctl_info,
180+
.get = snd_bcm2835_ctl_get,
181+
.put = snd_bcm2835_ctl_put,
182+
.count = 1,
183+
},
184+
};
185+
186+
int snd_bcm2835_new_ctl(bcm2835_chip_t * chip)
187+
{
188+
int err;
189+
unsigned int idx;
190+
191+
strcpy(chip->card->mixername, "Broadcom Mixer");
192+
for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
193+
err =
194+
snd_ctl_add(chip->card,
195+
snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
196+
if (err < 0)
197+
return err;
198+
}
199+
return 0;
200+
}

0 commit comments

Comments
 (0)