CC: kernel: update kernel 3.18 to version 3.18.23
[15.05/openwrt.git] / target / linux / brcm2708 / patches-3.18 / 0013-bcm2708-alsa-sound-driver.patch
1 From 40fe0b17b886f30b316614830eedf0cfc755bbbd Mon Sep 17 00:00:00 2001
2 From: popcornmix <popcornmix@gmail.com>
3 Date: Mon, 26 Mar 2012 22:15:50 +0100
4 Subject: [PATCH 013/114] bcm2708: alsa sound driver
5
6     Signed-off-by: popcornmix <popcornmix@gmail.com>
7
8 alsa: add mmap support and some cleanups to bcm2835 ALSA driver
9
10 snd-bcm2835: Add support for spdif/hdmi passthrough
11
12 This adds a dedicated subdevice which can be used for passthrough of non-audio
13 formats (ie encoded a52) through the hdmi audio link. In addition to this
14 driver extension an appropriate card config is required to make alsa-lib
15 support the AES parameters for this device.
16
17 snd-bcm2708: Add mutex, improve logging
18
19 Fix for ALSA driver crash
20
21 Avoids an issue when closing and opening vchiq where a message can arrive before service handle has been written
22
23 alsa: reduce severity of expected warning message
24
25 snd-bcm2708: Fix dmesg spam for non-error case
26 ---
27  arch/arm/configs/bcmrpi_defconfig                  |  20 +
28  arch/arm/mach-bcm2708/bcm2708.c                    |  54 ++
29  .../interface/vchiq_arm/vchiq_kern_lib.c           |   7 +-
30  .../vc04_services/interface/vchiq_arm/vchiq_shim.c |  12 +-
31  sound/arm/Kconfig                                  |   7 +
32  sound/arm/Makefile                                 |   5 +
33  sound/arm/bcm2835-ctl.c                            | 323 ++++++++
34  sound/arm/bcm2835-pcm.c                            | 552 +++++++++++++
35  sound/arm/bcm2835-vchiq.c                          | 902 +++++++++++++++++++++
36  sound/arm/bcm2835.c                                | 420 ++++++++++
37  sound/arm/bcm2835.h                                | 167 ++++
38  sound/arm/vc_vchi_audioserv_defs.h                 | 116 +++
39  12 files changed, 2578 insertions(+), 7 deletions(-)
40  create mode 100755 sound/arm/bcm2835-ctl.c
41  create mode 100755 sound/arm/bcm2835-pcm.c
42  create mode 100755 sound/arm/bcm2835-vchiq.c
43  create mode 100755 sound/arm/bcm2835.c
44  create mode 100755 sound/arm/bcm2835.h
45  create mode 100644 sound/arm/vc_vchi_audioserv_defs.h
46
47 --- a/arch/arm/configs/bcmrpi_defconfig
48 +++ b/arch/arm/configs/bcmrpi_defconfig
49 @@ -202,6 +202,26 @@ CONFIG_FRAMEBUFFER_CONSOLE=y
50  CONFIG_LOGO=y
51  # CONFIG_LOGO_LINUX_MONO is not set
52  # CONFIG_LOGO_LINUX_VGA16 is not set
53 +CONFIG_SOUND=y
54 +CONFIG_SND=m
55 +CONFIG_SND_SEQUENCER=m
56 +CONFIG_SND_SEQ_DUMMY=m
57 +CONFIG_SND_MIXER_OSS=m
58 +CONFIG_SND_PCM_OSS=m
59 +CONFIG_SND_SEQUENCER_OSS=y
60 +CONFIG_SND_HRTIMER=m
61 +CONFIG_SND_DUMMY=m
62 +CONFIG_SND_ALOOP=m
63 +CONFIG_SND_VIRMIDI=m
64 +CONFIG_SND_MTPAV=m
65 +CONFIG_SND_SERIAL_U16550=m
66 +CONFIG_SND_MPU401=m
67 +CONFIG_SND_BCM2835=m
68 +CONFIG_SND_USB_AUDIO=m
69 +CONFIG_SND_USB_UA101=m
70 +CONFIG_SND_USB_CAIAQ=m
71 +CONFIG_SND_USB_6FIRE=m
72 +CONFIG_SOUND_PRIME=m
73  CONFIG_HID_A4TECH=m
74  CONFIG_HID_ACRUX=m
75  CONFIG_HID_APPLE=m
76 --- a/arch/arm/mach-bcm2708/bcm2708.c
77 +++ b/arch/arm/mach-bcm2708/bcm2708.c
78 @@ -403,6 +403,58 @@ struct platform_device bcm2708_powerman_
79                 .coherent_dma_mask = 0xffffffffUL},
80  };
81  
82 +
83 +static struct platform_device bcm2708_alsa_devices[] = {
84 +       [0] = {
85 +              .name = "bcm2835_AUD0",
86 +              .id = 0,         /* first audio device */
87 +              .resource = 0,
88 +              .num_resources = 0,
89 +              },
90 +       [1] = {
91 +              .name = "bcm2835_AUD1",
92 +              .id = 1,         /* second audio device */
93 +              .resource = 0,
94 +              .num_resources = 0,
95 +              },
96 +       [2] = {
97 +              .name = "bcm2835_AUD2",
98 +              .id = 2,         /* third audio device */
99 +              .resource = 0,
100 +              .num_resources = 0,
101 +              },
102 +       [3] = {
103 +              .name = "bcm2835_AUD3",
104 +              .id = 3,         /* forth audio device */
105 +              .resource = 0,
106 +              .num_resources = 0,
107 +              },
108 +       [4] = {
109 +              .name = "bcm2835_AUD4",
110 +              .id = 4,         /* fifth audio device */
111 +              .resource = 0,
112 +              .num_resources = 0,
113 +              },
114 +       [5] = {
115 +              .name = "bcm2835_AUD5",
116 +              .id = 5,         /* sixth audio device */
117 +              .resource = 0,
118 +              .num_resources = 0,
119 +              },
120 +       [6] = {
121 +              .name = "bcm2835_AUD6",
122 +              .id = 6,         /* seventh audio device */
123 +              .resource = 0,
124 +              .num_resources = 0,
125 +              },
126 +       [7] = {
127 +              .name = "bcm2835_AUD7",
128 +              .id = 7,         /* eighth audio device */
129 +              .resource = 0,
130 +              .num_resources = 0,
131 +              },
132 +};
133 +
134  int __init bcm_register_device(struct platform_device *pdev)
135  {
136         int ret;
137 @@ -508,6 +560,8 @@ void __init bcm2708_init(void)
138         bcm_register_device(&bcm2708_powerman_device);
139  
140         bcm2708_init_led();
141 +       for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++)
142 +               bcm_register_device(&bcm2708_alsa_devices[i]);
143  
144         for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
145                 struct amba_device *d = amba_devs[i];
146 --- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
147 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
148 @@ -288,11 +288,12 @@ VCHIQ_STATUS_T vchiq_open_service(
149                 NULL);
150  
151         if (service) {
152 +               *phandle = service->handle;
153                 status = vchiq_open_service_internal(service, current->pid);
154 -               if (status == VCHIQ_SUCCESS)
155 -                       *phandle = service->handle;
156 -               else
157 +               if (status != VCHIQ_SUCCESS) {
158                         vchiq_remove_service(service->handle);
159 +                       *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
160 +               }
161         }
162  
163  failed:
164 --- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
165 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
166 @@ -634,6 +634,9 @@ int32_t vchi_service_open(VCHI_INSTANCE_
167  {
168         VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
169         SHIM_SERVICE_T *service = service_alloc(instance, setup);
170 +
171 +       *handle = (VCHI_SERVICE_HANDLE_T)service;
172 +
173         if (service) {
174                 VCHIQ_SERVICE_PARAMS_T params;
175                 VCHIQ_STATUS_T status;
176 @@ -650,11 +653,10 @@ int32_t vchi_service_open(VCHI_INSTANCE_
177                 if (status != VCHIQ_SUCCESS) {
178                         service_free(service);
179                         service = NULL;
180 +                       *handle = NULL;
181                 }
182         }
183  
184 -       *handle = (VCHI_SERVICE_HANDLE_T)service;
185 -
186         return (service != NULL) ? 0 : -1;
187  }
188  EXPORT_SYMBOL(vchi_service_open);
189 @@ -665,6 +667,9 @@ int32_t vchi_service_create(VCHI_INSTANC
190  {
191         VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
192         SHIM_SERVICE_T *service = service_alloc(instance, setup);
193 +
194 +       *handle = (VCHI_SERVICE_HANDLE_T)service;
195 +
196         if (service) {
197                 VCHIQ_SERVICE_PARAMS_T params;
198                 VCHIQ_STATUS_T status;
199 @@ -680,11 +685,10 @@ int32_t vchi_service_create(VCHI_INSTANC
200                 if (status != VCHIQ_SUCCESS) {
201                         service_free(service);
202                         service = NULL;
203 +                       *handle = NULL;
204                 }
205         }
206  
207 -       *handle = (VCHI_SERVICE_HANDLE_T)service;
208 -
209         return (service != NULL) ? 0 : -1;
210  }
211  EXPORT_SYMBOL(vchi_service_create);
212 --- a/sound/arm/Kconfig
213 +++ b/sound/arm/Kconfig
214 @@ -40,5 +40,12 @@ config SND_PXA2XX_AC97
215           Say Y or M if you want to support any AC97 codec attached to
216           the PXA2xx AC97 interface.
217  
218 +config SND_BCM2835
219 +       tristate "BCM2835 ALSA driver"
220 +       depends on ARCH_BCM2708 && BCM2708_VCHIQ && SND
221 +       select SND_PCM
222 +       help
223 +         Say Y or M if you want to support BCM2835 Alsa pcm card driver
224 +
225  endif  # SND_ARM
226  
227 --- a/sound/arm/Makefile
228 +++ b/sound/arm/Makefile
229 @@ -14,3 +14,8 @@ snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_A
230  
231  obj-$(CONFIG_SND_PXA2XX_AC97)  += snd-pxa2xx-ac97.o
232  snd-pxa2xx-ac97-objs           := pxa2xx-ac97.o
233 +
234 +obj-$(CONFIG_SND_BCM2835)      += snd-bcm2835.o
235 +snd-bcm2835-objs               := bcm2835.o bcm2835-ctl.o bcm2835-pcm.o bcm2835-vchiq.o
236 +
237 +ccflags-y += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000
238 --- /dev/null
239 +++ b/sound/arm/bcm2835-ctl.c
240 @@ -0,0 +1,323 @@
241 +/*****************************************************************************
242 +* Copyright 2011 Broadcom Corporation.  All rights reserved.
243 +*
244 +* Unless you and Broadcom execute a separate written software license
245 +* agreement governing use of this software, this software is licensed to you
246 +* under the terms of the GNU General Public License version 2, available at
247 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
248 +*
249 +* Notwithstanding the above, under no circumstances may you combine this
250 +* software in any way with any other Broadcom software provided under a
251 +* license other than the GPL, without Broadcom's express prior written
252 +* consent.
253 +*****************************************************************************/
254 +
255 +#include <linux/platform_device.h>
256 +#include <linux/init.h>
257 +#include <linux/io.h>
258 +#include <linux/jiffies.h>
259 +#include <linux/slab.h>
260 +#include <linux/time.h>
261 +#include <linux/wait.h>
262 +#include <linux/delay.h>
263 +#include <linux/moduleparam.h>
264 +#include <linux/sched.h>
265 +
266 +#include <sound/core.h>
267 +#include <sound/control.h>
268 +#include <sound/pcm.h>
269 +#include <sound/pcm_params.h>
270 +#include <sound/rawmidi.h>
271 +#include <sound/initval.h>
272 +#include <sound/tlv.h>
273 +#include <sound/asoundef.h>
274 +
275 +#include "bcm2835.h"
276 +
277 +/* volume maximum and minimum in terms of 0.01dB */
278 +#define CTRL_VOL_MAX 400
279 +#define CTRL_VOL_MIN -10239 /* originally -10240 */
280 +
281 +
282 +static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
283 +                               struct snd_ctl_elem_info *uinfo)
284 +{
285 +       audio_info(" ... IN\n");
286 +       if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
287 +               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
288 +               uinfo->count = 1;
289 +               uinfo->value.integer.min = CTRL_VOL_MIN;
290 +               uinfo->value.integer.max = CTRL_VOL_MAX;      /* 2303 */
291 +       } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
292 +               uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
293 +               uinfo->count = 1;
294 +               uinfo->value.integer.min = 0;
295 +               uinfo->value.integer.max = 1;
296 +       } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
297 +               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
298 +               uinfo->count = 1;
299 +               uinfo->value.integer.min = 0;
300 +               uinfo->value.integer.max = AUDIO_DEST_MAX-1;
301 +       }
302 +       audio_info(" ... OUT\n");
303 +       return 0;
304 +}
305 +
306 +/* toggles mute on or off depending on the value of nmute, and returns
307 + * 1 if the mute value was changed, otherwise 0
308 + */
309 +static int toggle_mute(struct bcm2835_chip *chip, int nmute)
310 +{
311 +       /* if settings are ok, just return 0 */
312 +       if(chip->mute == nmute)
313 +               return 0;
314 +
315 +       /* if the sound is muted then we need to unmute */
316 +       if(chip->mute == CTRL_VOL_MUTE)
317 +       {
318 +               chip->volume = chip->old_volume; /* copy the old volume back */
319 +               audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
320 +       }
321 +       else /* otherwise we mute */
322 +       {
323 +               chip->old_volume = chip->volume;
324 +               chip->volume = 26214; /* set volume to minimum level AKA mute */
325 +               audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
326 +       }
327 +
328 +       chip->mute = nmute;
329 +       return 1;
330 +}
331 +
332 +static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
333 +                              struct snd_ctl_elem_value *ucontrol)
334 +{
335 +       struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
336 +
337 +       BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
338 +
339 +       if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
340 +               ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
341 +       else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
342 +               ucontrol->value.integer.value[0] = chip->mute;
343 +       else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
344 +               ucontrol->value.integer.value[0] = chip->dest;
345 +
346 +       return 0;
347 +}
348 +
349 +static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
350 +                              struct snd_ctl_elem_value *ucontrol)
351 +{
352 +       struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
353 +       int changed = 0;
354 +
355 +       if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
356 +               audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
357 +               if (chip->mute == CTRL_VOL_MUTE) {
358 +                       /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
359 +                       return 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
360 +               }
361 +               if (changed
362 +                   || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
363 +
364 +                       chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
365 +                       changed = 1;
366 +               }
367 +
368 +       } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
369 +               /* Now implemented */
370 +               audio_info(" Mute attempted\n");
371 +               changed = toggle_mute(chip, ucontrol->value.integer.value[0]);
372 +
373 +       } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
374 +               if (ucontrol->value.integer.value[0] != chip->dest) {
375 +                       chip->dest = ucontrol->value.integer.value[0];
376 +                       changed = 1;
377 +               }
378 +       }
379 +
380 +       if (changed) {
381 +               if (bcm2835_audio_set_ctls(chip))
382 +                       printk(KERN_ERR "Failed to set ALSA controls..\n");
383 +       }
384 +
385 +       return changed;
386 +}
387 +
388 +static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
389 +
390 +static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
391 +       {
392 +        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
393 +        .name = "PCM Playback Volume",
394 +        .index = 0,
395 +        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
396 +        .private_value = PCM_PLAYBACK_VOLUME,
397 +        .info = snd_bcm2835_ctl_info,
398 +        .get = snd_bcm2835_ctl_get,
399 +        .put = snd_bcm2835_ctl_put,
400 +        .count = 1,
401 +        .tlv = {.p = snd_bcm2835_db_scale}
402 +       },
403 +       {
404 +        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
405 +        .name = "PCM Playback Switch",
406 +        .index = 0,
407 +        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
408 +        .private_value = PCM_PLAYBACK_MUTE,
409 +        .info = snd_bcm2835_ctl_info,
410 +        .get = snd_bcm2835_ctl_get,
411 +        .put = snd_bcm2835_ctl_put,
412 +        .count = 1,
413 +        },
414 +       {
415 +        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
416 +        .name = "PCM Playback Route",
417 +        .index = 0,
418 +        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
419 +        .private_value = PCM_PLAYBACK_DEVICE,
420 +        .info = snd_bcm2835_ctl_info,
421 +        .get = snd_bcm2835_ctl_get,
422 +        .put = snd_bcm2835_ctl_put,
423 +        .count = 1,
424 +       },
425 +};
426 +
427 +static int snd_bcm2835_spdif_default_info(struct snd_kcontrol *kcontrol,
428 +                                         struct snd_ctl_elem_info *uinfo)
429 +{
430 +       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
431 +       uinfo->count = 1;
432 +       return 0;
433 +}
434 +
435 +static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol,
436 +                                        struct snd_ctl_elem_value *ucontrol)
437 +{
438 +       struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
439 +       int i;
440 +
441 +       for (i = 0; i < 4; i++)
442 +               ucontrol->value.iec958.status[i] =
443 +                       (chip->spdif_status >> (i * 8)) && 0xff;
444 +
445 +       return 0;
446 +}
447 +
448 +static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol,
449 +                                        struct snd_ctl_elem_value *ucontrol)
450 +{
451 +       struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
452 +       unsigned int val = 0;
453 +       int i, change;
454 +
455 +       for (i = 0; i < 4; i++)
456 +               val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
457 +
458 +       change = val != chip->spdif_status;
459 +       chip->spdif_status = val;
460 +
461 +       return change;
462 +}
463 +
464 +static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol,
465 +                                      struct snd_ctl_elem_info *uinfo)
466 +{
467 +       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
468 +       uinfo->count = 1;
469 +       return 0;
470 +}
471 +
472 +static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol,
473 +                                     struct snd_ctl_elem_value *ucontrol)
474 +{
475 +       /* bcm2835 supports only consumer mode and sets all other format flags
476 +        * automatically. So the only thing left is signalling non-audio
477 +        * content */
478 +       ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO;
479 +       return 0;
480 +}
481 +
482 +static int snd_bcm2835_spdif_stream_info(struct snd_kcontrol *kcontrol,
483 +                                        struct snd_ctl_elem_info *uinfo)
484 +{
485 +       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
486 +       uinfo->count = 1;
487 +       return 0;
488 +}
489 +
490 +static int snd_bcm2835_spdif_stream_get(struct snd_kcontrol *kcontrol,
491 +                                       struct snd_ctl_elem_value *ucontrol)
492 +{
493 +       struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
494 +       int i;
495 +
496 +       for (i = 0; i < 4; i++)
497 +               ucontrol->value.iec958.status[i] =
498 +                       (chip->spdif_status >> (i * 8)) & 0xff;
499 +       return 0;
500 +}
501 +
502 +static int snd_bcm2835_spdif_stream_put(struct snd_kcontrol *kcontrol,
503 +                                       struct snd_ctl_elem_value *ucontrol)
504 +{
505 +       struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
506 +       unsigned int val = 0;
507 +       int i, change;
508 +
509 +       for (i = 0; i < 4; i++)
510 +               val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
511 +       change = val != chip->spdif_status;
512 +       chip->spdif_status = val;
513 +
514 +       return change;
515 +}
516 +
517 +static struct snd_kcontrol_new snd_bcm2835_spdif[] = {
518 +       {
519 +               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
520 +               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
521 +               .info = snd_bcm2835_spdif_default_info,
522 +               .get = snd_bcm2835_spdif_default_get,
523 +               .put = snd_bcm2835_spdif_default_put
524 +       },
525 +       {
526 +               .access = SNDRV_CTL_ELEM_ACCESS_READ,
527 +               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
528 +               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
529 +               .info = snd_bcm2835_spdif_mask_info,
530 +               .get = snd_bcm2835_spdif_mask_get,
531 +       },
532 +       {
533 +               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
534 +                       SNDRV_CTL_ELEM_ACCESS_INACTIVE,
535 +               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
536 +               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
537 +               .info = snd_bcm2835_spdif_stream_info,
538 +               .get = snd_bcm2835_spdif_stream_get,
539 +               .put = snd_bcm2835_spdif_stream_put,
540 +       },
541 +};
542 +
543 +int snd_bcm2835_new_ctl(bcm2835_chip_t * chip)
544 +{
545 +       int err;
546 +       unsigned int idx;
547 +
548 +       strcpy(chip->card->mixername, "Broadcom Mixer");
549 +       for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
550 +               err =
551 +                   snd_ctl_add(chip->card,
552 +                               snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
553 +               if (err < 0)
554 +                       return err;
555 +       }
556 +       for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) {
557 +               err = snd_ctl_add(chip->card,
558 +                               snd_ctl_new1(&snd_bcm2835_spdif[idx], chip));
559 +               if (err < 0)
560 +                       return err;
561 +       }
562 +       return 0;
563 +}
564 --- /dev/null
565 +++ b/sound/arm/bcm2835-pcm.c
566 @@ -0,0 +1,552 @@
567 +/*****************************************************************************
568 +* Copyright 2011 Broadcom Corporation.  All rights reserved.
569 +*
570 +* Unless you and Broadcom execute a separate written software license
571 +* agreement governing use of this software, this software is licensed to you
572 +* under the terms of the GNU General Public License version 2, available at
573 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
574 +*
575 +* Notwithstanding the above, under no circumstances may you combine this
576 +* software in any way with any other Broadcom software provided under a
577 +* license other than the GPL, without Broadcom's express prior written
578 +* consent.
579 +*****************************************************************************/
580 +
581 +#include <linux/interrupt.h>
582 +#include <linux/slab.h>
583 +
584 +#include <sound/asoundef.h>
585 +
586 +#include "bcm2835.h"
587 +
588 +/* hardware definition */
589 +static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
590 +       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
591 +                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
592 +       .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
593 +       .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
594 +       .rate_min = 8000,
595 +       .rate_max = 48000,
596 +       .channels_min = 1,
597 +       .channels_max = 2,
598 +       .buffer_bytes_max = 128 * 1024,
599 +       .period_bytes_min =   1 * 1024,
600 +       .period_bytes_max = 128 * 1024,
601 +       .periods_min = 1,
602 +       .periods_max = 128,
603 +};
604 +
605 +static struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
606 +       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
607 +                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
608 +       .formats = SNDRV_PCM_FMTBIT_S16_LE,
609 +       .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
610 +               SNDRV_PCM_RATE_48000,
611 +       .rate_min = 44100,
612 +       .rate_max = 48000,
613 +       .channels_min = 2,
614 +       .channels_max = 2,
615 +       .buffer_bytes_max = 128 * 1024,
616 +       .period_bytes_min =   1 * 1024,
617 +       .period_bytes_max = 128 * 1024,
618 +       .periods_min = 1,
619 +       .periods_max = 128,
620 +};
621 +
622 +static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
623 +{
624 +       audio_info("Freeing up alsa stream here ..\n");
625 +       if (runtime->private_data)
626 +               kfree(runtime->private_data);
627 +       runtime->private_data = NULL;
628 +}
629 +
630 +static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id)
631 +{
632 +       bcm2835_alsa_stream_t *alsa_stream = (bcm2835_alsa_stream_t *) dev_id;
633 +       uint32_t consumed = 0;
634 +       int new_period = 0;
635 +
636 +       audio_info(" .. IN\n");
637 +
638 +       audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
639 +                  alsa_stream ? alsa_stream->substream : 0);
640 +
641 +       if (alsa_stream->open)
642 +               consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
643 +
644 +       /* We get called only if playback was triggered, So, the number of buffers we retrieve in
645 +        * each iteration are the buffers that have been played out already
646 +        */
647 +
648 +       if (alsa_stream->period_size) {
649 +               if ((alsa_stream->pos / alsa_stream->period_size) !=
650 +                   ((alsa_stream->pos + consumed) / alsa_stream->period_size))
651 +                       new_period = 1;
652 +       }
653 +       audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n",
654 +                     alsa_stream->pos,
655 +                     consumed,
656 +                     alsa_stream->buffer_size,
657 +                         (int)(alsa_stream->period_size*alsa_stream->substream->runtime->periods),
658 +                         frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr),
659 +                         new_period);
660 +       if (alsa_stream->buffer_size) {
661 +               alsa_stream->pos += consumed &~ (1<<30);
662 +               alsa_stream->pos %= alsa_stream->buffer_size;
663 +       }
664 +
665 +       if (alsa_stream->substream) {
666 +               if (new_period)
667 +                       snd_pcm_period_elapsed(alsa_stream->substream);
668 +       } else {
669 +               audio_warning(" unexpected NULL substream\n");
670 +       }
671 +       audio_info(" .. OUT\n");
672 +
673 +       return IRQ_HANDLED;
674 +}
675 +
676 +/* open callback */
677 +static int snd_bcm2835_playback_open_generic(
678 +               struct snd_pcm_substream *substream, int spdif)
679 +{
680 +       bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
681 +       struct snd_pcm_runtime *runtime = substream->runtime;
682 +       bcm2835_alsa_stream_t *alsa_stream;
683 +       int idx;
684 +       int err;
685 +
686 +       audio_info(" .. IN (%d)\n", substream->number);
687 +
688 +       if(mutex_lock_interruptible(&chip->audio_mutex))
689 +       {
690 +               audio_error("Interrupted whilst waiting for lock\n");
691 +               return -EINTR;
692 +       }
693 +       audio_info("Alsa open (%d)\n", substream->number);
694 +       idx = substream->number;
695 +
696 +       if (spdif && chip->opened != 0)
697 +               return -EBUSY;
698 +       else if (!spdif && (chip->opened & (1 << idx)))
699 +               return -EBUSY;
700 +
701 +       if (idx > MAX_SUBSTREAMS) {
702 +               audio_error
703 +                   ("substream(%d) device doesn't exist max(%d) substreams allowed\n",
704 +                    idx, MAX_SUBSTREAMS);
705 +               err = -ENODEV;
706 +               goto out;
707 +       }
708 +
709 +       /* Check if we are ready */
710 +       if (!(chip->avail_substreams & (1 << idx))) {
711 +               /* We are not ready yet */
712 +               audio_error("substream(%d) device is not ready yet\n", idx);
713 +               err = -EAGAIN;
714 +               goto out;
715 +       }
716 +
717 +       alsa_stream = kzalloc(sizeof(bcm2835_alsa_stream_t), GFP_KERNEL);
718 +       if (alsa_stream == NULL) {
719 +               err = -ENOMEM;
720 +               goto out;
721 +       }
722 +
723 +       /* Initialise alsa_stream */
724 +       alsa_stream->chip = chip;
725 +       alsa_stream->substream = substream;
726 +       alsa_stream->idx = idx;
727 +
728 +       sema_init(&alsa_stream->buffers_update_sem, 0);
729 +       sema_init(&alsa_stream->control_sem, 0);
730 +       spin_lock_init(&alsa_stream->lock);
731 +
732 +       /* Enabled in start trigger, called on each "fifo irq" after that */
733 +       alsa_stream->enable_fifo_irq = 0;
734 +       alsa_stream->fifo_irq_handler = bcm2835_playback_fifo_irq;
735 +
736 +       err = bcm2835_audio_open(alsa_stream);
737 +       if (err != 0) {
738 +               kfree(alsa_stream);
739 +               return err;
740 +       }
741 +       runtime->private_data = alsa_stream;
742 +       runtime->private_free = snd_bcm2835_playback_free;
743 +       if (spdif) {
744 +               runtime->hw = snd_bcm2835_playback_spdif_hw;
745 +       } else {
746 +               /* clear spdif status, as we are not in spdif mode */
747 +               chip->spdif_status = 0;
748 +               runtime->hw = snd_bcm2835_playback_hw;
749 +       }
750 +       /* minimum 16 bytes alignment (for vchiq bulk transfers) */
751 +       snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
752 +                                  16);
753 +
754 +       chip->alsa_stream[idx] = alsa_stream;
755 +
756 +       chip->opened |= (1 << idx);
757 +       alsa_stream->open = 1;
758 +       alsa_stream->draining = 1;
759 +
760 +out:
761 +       mutex_unlock(&chip->audio_mutex);
762 +
763 +       audio_info(" .. OUT =%d\n", err);
764 +
765 +       return err;
766 +}
767 +
768 +static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
769 +{
770 +       return snd_bcm2835_playback_open_generic(substream, 0);
771 +}
772 +
773 +static int snd_bcm2835_playback_spdif_open(struct snd_pcm_substream *substream)
774 +{
775 +       return snd_bcm2835_playback_open_generic(substream, 1);
776 +}
777 +
778 +/* close callback */
779 +static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
780 +{
781 +       /* the hardware-specific codes will be here */
782 +
783 +       bcm2835_chip_t *chip;
784 +       struct snd_pcm_runtime *runtime;
785 +       bcm2835_alsa_stream_t *alsa_stream;
786 +
787 +       audio_info(" .. IN\n");
788 +
789 +       chip = snd_pcm_substream_chip(substream);
790 +       if(mutex_lock_interruptible(&chip->audio_mutex))
791 +       {
792 +               audio_error("Interrupted whilst waiting for lock\n");
793 +               return -EINTR;
794 +       }
795 +       runtime = substream->runtime;
796 +       alsa_stream = runtime->private_data;
797 +
798 +       audio_info("Alsa close\n");
799 +
800 +       /*
801 +        * Call stop if it's still running. This happens when app
802 +        * is force killed and we don't get a stop trigger.
803 +        */
804 +       if (alsa_stream->running) {
805 +               int err;
806 +               err = bcm2835_audio_stop(alsa_stream);
807 +               alsa_stream->running = 0;
808 +               if (err != 0)
809 +                       audio_error(" Failed to STOP alsa device\n");
810 +       }
811 +
812 +       alsa_stream->period_size = 0;
813 +       alsa_stream->buffer_size = 0;
814 +
815 +       if (alsa_stream->open) {
816 +               alsa_stream->open = 0;
817 +               bcm2835_audio_close(alsa_stream);
818 +       }
819 +       if (alsa_stream->chip)
820 +               alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
821 +       /*
822 +        * Do not free up alsa_stream here, it will be freed up by
823 +        * runtime->private_free callback we registered in *_open above
824 +        */
825 +
826 +       chip->opened &= ~(1 << substream->number);
827 +
828 +       mutex_unlock(&chip->audio_mutex);
829 +       audio_info(" .. OUT\n");
830 +
831 +       return 0;
832 +}
833 +
834 +/* hw_params callback */
835 +static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
836 +                                    struct snd_pcm_hw_params *params)
837 +{
838 +       struct snd_pcm_runtime *runtime = substream->runtime;
839 +       bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
840 +       int err;
841 +
842 +       audio_info(" .. IN\n");
843 +
844 +       err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
845 +       if (err < 0) {
846 +               audio_error
847 +                   (" pcm_lib_malloc failed to allocated pages for buffers\n");
848 +               return err;
849 +       }
850 +
851 +       alsa_stream->channels = params_channels(params);
852 +       alsa_stream->params_rate = params_rate(params);
853 +       alsa_stream->pcm_format_width = snd_pcm_format_width(params_format (params));
854 +       audio_info(" .. OUT\n");
855 +
856 +       return err;
857 +}
858 +
859 +/* hw_free callback */
860 +static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
861 +{
862 +       audio_info(" .. IN\n");
863 +       return snd_pcm_lib_free_pages(substream);
864 +}
865 +
866 +/* prepare callback */
867 +static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
868 +{
869 +       bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
870 +       struct snd_pcm_runtime *runtime = substream->runtime;
871 +       bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
872 +       int channels;
873 +       int err;
874 +
875 +       audio_info(" .. IN\n");
876 +
877 +       /* notify the vchiq that it should enter spdif passthrough mode by
878 +        * setting channels=0 (see
879 +        * https://github.com/raspberrypi/linux/issues/528) */
880 +       if (chip->spdif_status & IEC958_AES0_NONAUDIO)
881 +               channels = 0;
882 +       else
883 +               channels = alsa_stream->channels;
884 +
885 +       err = bcm2835_audio_set_params(alsa_stream, channels,
886 +                                      alsa_stream->params_rate,
887 +                                      alsa_stream->pcm_format_width);
888 +       if (err < 0) {
889 +               audio_error(" error setting hw params\n");
890 +       }
891 +
892 +       bcm2835_audio_setup(alsa_stream);
893 +
894 +       /* in preparation of the stream, set the controls (volume level) of the stream */
895 +       bcm2835_audio_set_ctls(alsa_stream->chip);
896 +
897 +
898 +       memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
899 +
900 +       alsa_stream->pcm_indirect.hw_buffer_size =
901 +       alsa_stream->pcm_indirect.sw_buffer_size =
902 +               snd_pcm_lib_buffer_bytes(substream);
903 +
904 +       alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
905 +       alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
906 +       alsa_stream->pos = 0;
907 +
908 +       audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
909 +                     alsa_stream->buffer_size, alsa_stream->period_size,
910 +                     alsa_stream->pos, runtime->frame_bits);
911 +
912 +       audio_info(" .. OUT\n");
913 +       return 0;
914 +}
915 +
916 +static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
917 +                                   struct snd_pcm_indirect *rec, size_t bytes)
918 +{
919 +       struct snd_pcm_runtime *runtime = substream->runtime;
920 +       bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
921 +       void *src = (void *)(substream->runtime->dma_area + rec->sw_data);
922 +       int err;
923 +
924 +       err = bcm2835_audio_write(alsa_stream, bytes, src);
925 +       if (err)
926 +               audio_error(" Failed to transfer to alsa device (%d)\n", err);
927 +
928 +}
929 +
930 +static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
931 +{
932 +       struct snd_pcm_runtime *runtime = substream->runtime;
933 +       bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
934 +       struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
935 +
936 +       pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
937 +       snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
938 +                                          snd_bcm2835_pcm_transfer);
939 +       return 0;
940 +}
941 +
942 +/* trigger callback */
943 +static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
944 +{
945 +       struct snd_pcm_runtime *runtime = substream->runtime;
946 +       bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
947 +       int err = 0;
948 +
949 +       audio_info(" .. IN\n");
950 +
951 +       switch (cmd) {
952 +       case SNDRV_PCM_TRIGGER_START:
953 +               audio_debug("bcm2835_AUDIO_TRIGGER_START running=%d\n",
954 +                             alsa_stream->running);
955 +               if (!alsa_stream->running) {
956 +                       err = bcm2835_audio_start(alsa_stream);
957 +                       if (err == 0) {
958 +                               alsa_stream->pcm_indirect.hw_io =
959 +                               alsa_stream->pcm_indirect.hw_data =
960 +                                       bytes_to_frames(runtime,
961 +                                                       alsa_stream->pos);
962 +                               substream->ops->ack(substream);
963 +                               alsa_stream->running = 1;
964 +                               alsa_stream->draining = 1;
965 +                       } else {
966 +                               audio_error(" Failed to START alsa device (%d)\n", err);
967 +                       }
968 +               }
969 +               break;
970 +       case SNDRV_PCM_TRIGGER_STOP:
971 +               audio_debug
972 +                   ("bcm2835_AUDIO_TRIGGER_STOP running=%d draining=%d\n",
973 +                            alsa_stream->running, runtime->status->state == SNDRV_PCM_STATE_DRAINING);
974 +               if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
975 +                       audio_info("DRAINING\n");
976 +                       alsa_stream->draining = 1;
977 +               } else {
978 +                       audio_info("DROPPING\n");
979 +                       alsa_stream->draining = 0;
980 +               }
981 +               if (alsa_stream->running) {
982 +                       err = bcm2835_audio_stop(alsa_stream);
983 +                       if (err != 0)
984 +                               audio_error(" Failed to STOP alsa device (%d)\n", err);
985 +                       alsa_stream->running = 0;
986 +               }
987 +               break;
988 +       default:
989 +               err = -EINVAL;
990 +       }
991 +
992 +       audio_info(" .. OUT\n");
993 +       return err;
994 +}
995 +
996 +/* pointer callback */
997 +static snd_pcm_uframes_t
998 +snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
999 +{
1000 +       struct snd_pcm_runtime *runtime = substream->runtime;
1001 +       bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
1002 +
1003 +       audio_info(" .. IN\n");
1004 +
1005 +       audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0,
1006 +                     frames_to_bytes(runtime, runtime->status->hw_ptr),
1007 +                     frames_to_bytes(runtime, runtime->control->appl_ptr),
1008 +                     alsa_stream->pos);
1009 +
1010 +       audio_info(" .. OUT\n");
1011 +       return snd_pcm_indirect_playback_pointer(substream,
1012 +                                                &alsa_stream->pcm_indirect,
1013 +                                                alsa_stream->pos);
1014 +}
1015 +
1016 +static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
1017 +                                    unsigned int cmd, void *arg)
1018 +{
1019 +       int ret = snd_pcm_lib_ioctl(substream, cmd, arg);
1020 +       audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream,
1021 +                   cmd, arg, arg ? *(unsigned *)arg : 0, ret);
1022 +       return ret;
1023 +}
1024 +
1025 +/* operators */
1026 +static struct snd_pcm_ops snd_bcm2835_playback_ops = {
1027 +       .open = snd_bcm2835_playback_open,
1028 +       .close = snd_bcm2835_playback_close,
1029 +       .ioctl = snd_bcm2835_pcm_lib_ioctl,
1030 +       .hw_params = snd_bcm2835_pcm_hw_params,
1031 +       .hw_free = snd_bcm2835_pcm_hw_free,
1032 +       .prepare = snd_bcm2835_pcm_prepare,
1033 +       .trigger = snd_bcm2835_pcm_trigger,
1034 +       .pointer = snd_bcm2835_pcm_pointer,
1035 +       .ack = snd_bcm2835_pcm_ack,
1036 +};
1037 +
1038 +static struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = {
1039 +       .open = snd_bcm2835_playback_spdif_open,
1040 +       .close = snd_bcm2835_playback_close,
1041 +       .ioctl = snd_bcm2835_pcm_lib_ioctl,
1042 +       .hw_params = snd_bcm2835_pcm_hw_params,
1043 +       .hw_free = snd_bcm2835_pcm_hw_free,
1044 +       .prepare = snd_bcm2835_pcm_prepare,
1045 +       .trigger = snd_bcm2835_pcm_trigger,
1046 +       .pointer = snd_bcm2835_pcm_pointer,
1047 +       .ack = snd_bcm2835_pcm_ack,
1048 +};
1049 +
1050 +/* create a pcm device */
1051 +int snd_bcm2835_new_pcm(bcm2835_chip_t * chip)
1052 +{
1053 +       struct snd_pcm *pcm;
1054 +       int err;
1055 +
1056 +       audio_info(" .. IN\n");
1057 +       mutex_init(&chip->audio_mutex);
1058 +       if(mutex_lock_interruptible(&chip->audio_mutex))
1059 +       {
1060 +               audio_error("Interrupted whilst waiting for lock\n");
1061 +               return -EINTR;
1062 +       }
1063 +       err =
1064 +           snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm);
1065 +       if (err < 0)
1066 +               return err;
1067 +       pcm->private_data = chip;
1068 +       strcpy(pcm->name, "bcm2835 ALSA");
1069 +       chip->pcm = pcm;
1070 +       chip->dest = AUDIO_DEST_AUTO;
1071 +       chip->volume = alsa2chip(0);
1072 +       chip->mute = CTRL_VOL_UNMUTE;   /*disable mute on startup */
1073 +       /* set operators */
1074 +       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1075 +                       &snd_bcm2835_playback_ops);
1076 +
1077 +       /* pre-allocation of buffers */
1078 +       /* NOTE: this may fail */
1079 +       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
1080 +                                             snd_dma_continuous_data
1081 +                                             (GFP_KERNEL), 64 * 1024,
1082 +                                             64 * 1024);
1083 +
1084 +       mutex_unlock(&chip->audio_mutex);
1085 +       audio_info(" .. OUT\n");
1086 +
1087 +       return 0;
1088 +}
1089 +
1090 +int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip)
1091 +{
1092 +       struct snd_pcm *pcm;
1093 +       int err;
1094 +
1095 +       audio_info(" .. IN\n");
1096 +       if(mutex_lock_interruptible(&chip->audio_mutex))
1097 +       {
1098 +               audio_error("Interrupted whilst waiting for lock\n");
1099 +               return -EINTR;
1100 +       }
1101 +       err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm);
1102 +       if (err < 0)
1103 +               return err;
1104 +
1105 +       pcm->private_data = chip;
1106 +       strcpy(pcm->name, "bcm2835 IEC958/HDMI");
1107 +       chip->pcm_spdif = pcm;
1108 +       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1109 +                       &snd_bcm2835_playback_spdif_ops);
1110 +
1111 +       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
1112 +                                             snd_dma_continuous_data (GFP_KERNEL),
1113 +                                             64 * 1024, 64 * 1024);
1114 +       mutex_unlock(&chip->audio_mutex);
1115 +       audio_info(" .. OUT\n");
1116 +
1117 +       return 0;
1118 +}
1119 --- /dev/null
1120 +++ b/sound/arm/bcm2835-vchiq.c
1121 @@ -0,0 +1,902 @@
1122 +/*****************************************************************************
1123 +* Copyright 2011 Broadcom Corporation.  All rights reserved.
1124 +*
1125 +* Unless you and Broadcom execute a separate written software license
1126 +* agreement governing use of this software, this software is licensed to you
1127 +* under the terms of the GNU General Public License version 2, available at
1128 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
1129 +*
1130 +* Notwithstanding the above, under no circumstances may you combine this
1131 +* software in any way with any other Broadcom software provided under a
1132 +* license other than the GPL, without Broadcom's express prior written
1133 +* consent.
1134 +*****************************************************************************/
1135 +
1136 +#include <linux/device.h>
1137 +#include <sound/core.h>
1138 +#include <sound/initval.h>
1139 +#include <sound/pcm.h>
1140 +#include <linux/io.h>
1141 +#include <linux/interrupt.h>
1142 +#include <linux/fs.h>
1143 +#include <linux/file.h>
1144 +#include <linux/mm.h>
1145 +#include <linux/syscalls.h>
1146 +#include <asm/uaccess.h>
1147 +#include <linux/slab.h>
1148 +#include <linux/delay.h>
1149 +#include <linux/atomic.h>
1150 +#include <linux/module.h>
1151 +#include <linux/completion.h>
1152 +
1153 +#include "bcm2835.h"
1154 +
1155 +/* ---- Include Files -------------------------------------------------------- */
1156 +
1157 +#include "interface/vchi/vchi.h"
1158 +#include "vc_vchi_audioserv_defs.h"
1159 +
1160 +/* ---- Private Constants and Types ------------------------------------------ */
1161 +
1162 +#define BCM2835_AUDIO_STOP           0
1163 +#define BCM2835_AUDIO_START          1
1164 +#define BCM2835_AUDIO_WRITE          2
1165 +
1166 +/* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
1167 +#ifdef AUDIO_DEBUG_ENABLE
1168 +       #define LOG_ERR( fmt, arg... )   pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
1169 +       #define LOG_WARN( fmt, arg... )  pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
1170 +       #define LOG_INFO( fmt, arg... )  pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
1171 +       #define LOG_DBG( fmt, arg... )   pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
1172 +#else
1173 +       #define LOG_ERR( fmt, arg... )   pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
1174 +       #define LOG_WARN( fmt, arg... )
1175 +       #define LOG_INFO( fmt, arg... )
1176 +       #define LOG_DBG( fmt, arg... )
1177 +#endif
1178 +
1179 +typedef struct opaque_AUDIO_INSTANCE_T {
1180 +       uint32_t num_connections;
1181 +       VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
1182 +       struct completion msg_avail_comp;
1183 +       struct mutex vchi_mutex;
1184 +       bcm2835_alsa_stream_t *alsa_stream;
1185 +       int32_t result;
1186 +       short peer_version;
1187 +} AUDIO_INSTANCE_T;
1188 +
1189 +bool force_bulk = false;
1190 +
1191 +/* ---- Private Variables ---------------------------------------------------- */
1192 +
1193 +/* ---- Private Function Prototypes ------------------------------------------ */
1194 +
1195 +/* ---- Private Functions ---------------------------------------------------- */
1196 +
1197 +static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream);
1198 +static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream);
1199 +static int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
1200 +                                     uint32_t count, void *src);
1201 +
1202 +typedef struct {
1203 +       struct work_struct my_work;
1204 +       bcm2835_alsa_stream_t *alsa_stream;
1205 +       int cmd;
1206 +       void *src;
1207 +       uint32_t count;
1208 +} my_work_t;
1209 +
1210 +static void my_wq_function(struct work_struct *work)
1211 +{
1212 +       my_work_t *w = (my_work_t *) work;
1213 +       int ret = -9;
1214 +       LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd);
1215 +       switch (w->cmd) {
1216 +       case BCM2835_AUDIO_START:
1217 +               ret = bcm2835_audio_start_worker(w->alsa_stream);
1218 +               break;
1219 +       case BCM2835_AUDIO_STOP:
1220 +               ret = bcm2835_audio_stop_worker(w->alsa_stream);
1221 +               break;
1222 +       case BCM2835_AUDIO_WRITE:
1223 +               ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
1224 +                                                w->src);
1225 +               break;
1226 +       default:
1227 +               LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
1228 +               break;
1229 +       }
1230 +       kfree((void *)work);
1231 +       LOG_DBG(" .. OUT %d\n", ret);
1232 +}
1233 +
1234 +int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream)
1235 +{
1236 +       int ret = -1;
1237 +       LOG_DBG(" .. IN\n");
1238 +       if (alsa_stream->my_wq) {
1239 +               my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
1240 +               /*--- Queue some work (item 1) ---*/
1241 +               if (work) {
1242 +                       INIT_WORK((struct work_struct *)work, my_wq_function);
1243 +                       work->alsa_stream = alsa_stream;
1244 +                       work->cmd = BCM2835_AUDIO_START;
1245 +                       if (queue_work
1246 +                           (alsa_stream->my_wq, (struct work_struct *)work))
1247 +                               ret = 0;
1248 +               } else
1249 +                       LOG_ERR(" .. Error: NULL work kmalloc\n");
1250 +       }
1251 +       LOG_DBG(" .. OUT %d\n", ret);
1252 +       return ret;
1253 +}
1254 +
1255 +int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream)
1256 +{
1257 +       int ret = -1;
1258 +       LOG_DBG(" .. IN\n");
1259 +       if (alsa_stream->my_wq) {
1260 +               my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
1261 +                /*--- Queue some work (item 1) ---*/
1262 +               if (work) {
1263 +                       INIT_WORK((struct work_struct *)work, my_wq_function);
1264 +                       work->alsa_stream = alsa_stream;
1265 +                       work->cmd = BCM2835_AUDIO_STOP;
1266 +                       if (queue_work
1267 +                           (alsa_stream->my_wq, (struct work_struct *)work))
1268 +                               ret = 0;
1269 +               } else
1270 +                       LOG_ERR(" .. Error: NULL work kmalloc\n");
1271 +       }
1272 +       LOG_DBG(" .. OUT %d\n", ret);
1273 +       return ret;
1274 +}
1275 +
1276 +int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream,
1277 +                       uint32_t count, void *src)
1278 +{
1279 +       int ret = -1;
1280 +       LOG_DBG(" .. IN\n");
1281 +       if (alsa_stream->my_wq) {
1282 +               my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
1283 +                /*--- Queue some work (item 1) ---*/
1284 +               if (work) {
1285 +                       INIT_WORK((struct work_struct *)work, my_wq_function);
1286 +                       work->alsa_stream = alsa_stream;
1287 +                       work->cmd = BCM2835_AUDIO_WRITE;
1288 +                       work->src = src;
1289 +                       work->count = count;
1290 +                       if (queue_work
1291 +                           (alsa_stream->my_wq, (struct work_struct *)work))
1292 +                               ret = 0;
1293 +               } else
1294 +                       LOG_ERR(" .. Error: NULL work kmalloc\n");
1295 +       }
1296 +       LOG_DBG(" .. OUT %d\n", ret);
1297 +       return ret;
1298 +}
1299 +
1300 +void my_workqueue_init(bcm2835_alsa_stream_t * alsa_stream)
1301 +{
1302 +       alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
1303 +       return;
1304 +}
1305 +
1306 +void my_workqueue_quit(bcm2835_alsa_stream_t * alsa_stream)
1307 +{
1308 +       if (alsa_stream->my_wq) {
1309 +               flush_workqueue(alsa_stream->my_wq);
1310 +               destroy_workqueue(alsa_stream->my_wq);
1311 +               alsa_stream->my_wq = NULL;
1312 +       }
1313 +       return;
1314 +}
1315 +
1316 +static void audio_vchi_callback(void *param,
1317 +                               const VCHI_CALLBACK_REASON_T reason,
1318 +                               void *msg_handle)
1319 +{
1320 +       AUDIO_INSTANCE_T *instance = (AUDIO_INSTANCE_T *) param;
1321 +       int32_t status;
1322 +       int32_t msg_len;
1323 +       VC_AUDIO_MSG_T m;
1324 +       LOG_DBG(" .. IN instance=%p, handle=%p, alsa=%p, reason=%d, handle=%p\n",
1325 +               instance, instance ? instance->vchi_handle[0] : NULL, instance ? instance->alsa_stream : NULL, reason, msg_handle);
1326 +
1327 +       if (reason != VCHI_CALLBACK_MSG_AVAILABLE) {
1328 +               return;
1329 +       }
1330 +       if (!instance) {
1331 +               LOG_ERR(" .. instance is null\n");
1332 +               BUG();
1333 +               return;
1334 +  }
1335 +  if (!instance->vchi_handle[0]) {
1336 +               LOG_ERR(" .. instance->vchi_handle[0] is null\n");
1337 +               BUG();
1338 +               return;
1339 +  }
1340 +       status = vchi_msg_dequeue(instance->vchi_handle[0],
1341 +                                 &m, sizeof m, &msg_len, VCHI_FLAGS_NONE);
1342 +       if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
1343 +               LOG_DBG
1344 +                   (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
1345 +                    instance, m.u.result.success);
1346 +               instance->result = m.u.result.success;
1347 +               complete(&instance->msg_avail_comp);
1348 +       } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
1349 +               bcm2835_alsa_stream_t *alsa_stream = instance->alsa_stream;
1350 +               irq_handler_t callback = (irq_handler_t) m.u.complete.callback;
1351 +               LOG_DBG
1352 +                   (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
1353 +                    instance, m.u.complete.count);
1354 +               if (alsa_stream && callback) {
1355 +                       atomic_add(m.u.complete.count, &alsa_stream->retrieved);
1356 +                       callback(0, alsa_stream);
1357 +               } else {
1358 +                       LOG_ERR(" .. unexpected alsa_stream=%p, callback=%p\n",
1359 +                               alsa_stream, callback);
1360 +               }
1361 +       } else {
1362 +               LOG_ERR(" .. unexpected m.type=%d\n", m.type);
1363 +       }
1364 +       LOG_DBG(" .. OUT\n");
1365 +}
1366 +
1367 +static AUDIO_INSTANCE_T *vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
1368 +                                           VCHI_CONNECTION_T **
1369 +                                           vchi_connections,
1370 +                                           uint32_t num_connections)
1371 +{
1372 +       uint32_t i;
1373 +       AUDIO_INSTANCE_T *instance;
1374 +       int status;
1375 +
1376 +       LOG_DBG("%s: start", __func__);
1377 +
1378 +       if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
1379 +               LOG_ERR("%s: unsupported number of connections %u (max=%u)\n",
1380 +                       __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
1381 +
1382 +               return NULL;
1383 +       }
1384 +       /* Allocate memory for this instance */
1385 +       instance = kmalloc(sizeof(*instance), GFP_KERNEL);
1386 +       if (!instance)
1387 +               return NULL;
1388 +
1389 +       memset(instance, 0, sizeof(*instance));
1390 +       instance->num_connections = num_connections;
1391 +
1392 +       /* Create a lock for exclusive, serialized VCHI connection access */
1393 +       mutex_init(&instance->vchi_mutex);
1394 +       /* Open the VCHI service connections */
1395 +       for (i = 0; i < num_connections; i++) {
1396 +               SERVICE_CREATION_T params = {
1397 +                       VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
1398 +                       VC_AUDIO_SERVER_NAME,   // 4cc service code
1399 +                       vchi_connections[i],    // passed in fn pointers
1400 +                       0,      // rx fifo size (unused)
1401 +                       0,      // tx fifo size (unused)
1402 +                       audio_vchi_callback,    // service callback
1403 +                       instance,       // service callback parameter
1404 +                       1,      //TODO: remove VCOS_FALSE,   // unaligned bulk recieves
1405 +                       1,      //TODO: remove VCOS_FALSE,   // unaligned bulk transmits
1406 +                       0       // want crc check on bulk transfers
1407 +               };
1408 +
1409 +               LOG_DBG("%s: about to open %i\n", __func__, i);
1410 +               status = vchi_service_open(vchi_instance, &params,
1411 +                                          &instance->vchi_handle[i]);
1412 +               LOG_DBG("%s: opened %i: %p=%d\n", __func__, i, instance->vchi_handle[i], status);
1413 +               if (status) {
1414 +                       LOG_ERR
1415 +                           ("%s: failed to open VCHI service connection (status=%d)\n",
1416 +                            __func__, status);
1417 +
1418 +                       goto err_close_services;
1419 +               }
1420 +               /* Finished with the service for now */
1421 +               vchi_service_release(instance->vchi_handle[i]);
1422 +       }
1423 +
1424 +       LOG_DBG("%s: okay\n", __func__);
1425 +       return instance;
1426 +
1427 +err_close_services:
1428 +       for (i = 0; i < instance->num_connections; i++) {
1429 +               LOG_ERR("%s: closing %i: %p\n", __func__, i, instance->vchi_handle[i]);
1430 +               if (instance->vchi_handle[i])
1431 +                       vchi_service_close(instance->vchi_handle[i]);
1432 +       }
1433 +
1434 +       kfree(instance);
1435 +       LOG_ERR("%s: error\n", __func__);
1436 +
1437 +       return NULL;
1438 +}
1439 +
1440 +static int32_t vc_vchi_audio_deinit(AUDIO_INSTANCE_T * instance)
1441 +{
1442 +       uint32_t i;
1443 +
1444 +       LOG_DBG(" .. IN\n");
1445 +
1446 +       if (instance == NULL) {
1447 +               LOG_ERR("%s: invalid handle %p\n", __func__, instance);
1448 +
1449 +               return -1;
1450 +       }
1451 +
1452 +       LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
1453 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1454 +       {
1455 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1456 +               return -EINTR;
1457 +       }
1458 +
1459 +       /* Close all VCHI service connections */
1460 +       for (i = 0; i < instance->num_connections; i++) {
1461 +               int32_t success;
1462 +               LOG_DBG(" .. %i:closing %p\n", i, instance->vchi_handle[i]);
1463 +               vchi_service_use(instance->vchi_handle[i]);
1464 +
1465 +               success = vchi_service_close(instance->vchi_handle[i]);
1466 +               if (success != 0) {
1467 +                       LOG_ERR
1468 +                           ("%s: failed to close VCHI service connection (status=%d)\n",
1469 +                            __func__, success);
1470 +               }
1471 +       }
1472 +
1473 +       mutex_unlock(&instance->vchi_mutex);
1474 +
1475 +       kfree(instance);
1476 +
1477 +       LOG_DBG(" .. OUT\n");
1478 +
1479 +       return 0;
1480 +}
1481 +
1482 +static int bcm2835_audio_open_connection(bcm2835_alsa_stream_t * alsa_stream)
1483 +{
1484 +       static VCHI_INSTANCE_T vchi_instance;
1485 +       static VCHI_CONNECTION_T *vchi_connection;
1486 +       static int initted;
1487 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1488 +       int ret;
1489 +       LOG_DBG(" .. IN\n");
1490 +
1491 +       LOG_INFO("%s: start\n", __func__);
1492 +       BUG_ON(instance);
1493 +       if (instance) {
1494 +               LOG_ERR("%s: VCHI instance already open (%p)\n",
1495 +                       __func__, instance);
1496 +               instance->alsa_stream = alsa_stream;
1497 +               alsa_stream->instance = instance;
1498 +               ret = 0;        // xxx todo -1;
1499 +               goto err_free_mem;
1500 +       }
1501 +
1502 +       /* Initialize and create a VCHI connection */
1503 +       if (!initted) {
1504 +         ret = vchi_initialise(&vchi_instance);
1505 +         if (ret != 0) {
1506 +                 LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n",
1507 +                         __func__, ret);
1508 +
1509 +                 ret = -EIO;
1510 +                 goto err_free_mem;
1511 +         }
1512 +         ret = vchi_connect(NULL, 0, vchi_instance);
1513 +         if (ret != 0) {
1514 +                 LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n",
1515 +                         __func__, ret);
1516 +
1517 +                 ret = -EIO;
1518 +                 goto err_free_mem;
1519 +         }
1520 +       initted = 1;
1521 +       }
1522 +
1523 +       /* Initialize an instance of the audio service */
1524 +       instance = vc_vchi_audio_init(vchi_instance, &vchi_connection, 1);
1525 +
1526 +       if (instance == NULL) {
1527 +               LOG_ERR("%s: failed to initialize audio service\n", __func__);
1528 +
1529 +               ret = -EPERM;
1530 +               goto err_free_mem;
1531 +       }
1532 +
1533 +       instance->alsa_stream = alsa_stream;
1534 +       alsa_stream->instance = instance;
1535 +
1536 +       LOG_DBG(" success !\n");
1537 +err_free_mem:
1538 +       LOG_DBG(" .. OUT\n");
1539 +
1540 +       return ret;
1541 +}
1542 +
1543 +int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream)
1544 +{
1545 +       AUDIO_INSTANCE_T *instance;
1546 +       VC_AUDIO_MSG_T m;
1547 +       int32_t success;
1548 +       int ret;
1549 +       LOG_DBG(" .. IN\n");
1550 +
1551 +       my_workqueue_init(alsa_stream);
1552 +
1553 +       ret = bcm2835_audio_open_connection(alsa_stream);
1554 +       if (ret != 0) {
1555 +               ret = -1;
1556 +               goto exit;
1557 +       }
1558 +       instance = alsa_stream->instance;
1559 +       LOG_DBG(" instance (%p)\n", instance);
1560 +
1561 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1562 +       {
1563 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1564 +               return -EINTR;
1565 +       }
1566 +       vchi_service_use(instance->vchi_handle[0]);
1567 +
1568 +       m.type = VC_AUDIO_MSG_TYPE_OPEN;
1569 +
1570 +       /* Send the message to the videocore */
1571 +       success = vchi_msg_queue(instance->vchi_handle[0],
1572 +                                &m, sizeof m,
1573 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1574 +
1575 +       if (success != 0) {
1576 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1577 +                       __func__, success);
1578 +
1579 +               ret = -1;
1580 +               goto unlock;
1581 +       }
1582 +
1583 +       ret = 0;
1584 +
1585 +unlock:
1586 +       vchi_service_release(instance->vchi_handle[0]);
1587 +       mutex_unlock(&instance->vchi_mutex);
1588 +exit:
1589 +       LOG_DBG(" .. OUT\n");
1590 +       return ret;
1591 +}
1592 +
1593 +static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
1594 +                                      bcm2835_chip_t * chip)
1595 +{
1596 +       VC_AUDIO_MSG_T m;
1597 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1598 +       int32_t success;
1599 +       int ret;
1600 +       LOG_DBG(" .. IN\n");
1601 +
1602 +       LOG_INFO
1603 +           (" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
1604 +
1605 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1606 +       {
1607 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1608 +               return -EINTR;
1609 +       }
1610 +       vchi_service_use(instance->vchi_handle[0]);
1611 +
1612 +       instance->result = -1;
1613 +
1614 +       m.type = VC_AUDIO_MSG_TYPE_CONTROL;
1615 +       m.u.control.dest = chip->dest;
1616 +       m.u.control.volume = chip->volume;
1617 +
1618 +       /* Create the message available completion */
1619 +       init_completion(&instance->msg_avail_comp);
1620 +
1621 +       /* Send the message to the videocore */
1622 +       success = vchi_msg_queue(instance->vchi_handle[0],
1623 +                                &m, sizeof m,
1624 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1625 +
1626 +       if (success != 0) {
1627 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1628 +                       __func__, success);
1629 +
1630 +               ret = -1;
1631 +               goto unlock;
1632 +       }
1633 +
1634 +       /* We are expecting a reply from the videocore */
1635 +       ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
1636 +       if (ret) {
1637 +               LOG_ERR("%s: failed on waiting for event (status=%d)\n",
1638 +                       __func__, success);
1639 +               goto unlock;
1640 +       }
1641 +
1642 +       if (instance->result != 0) {
1643 +               LOG_ERR("%s: result=%d\n", __func__, instance->result);
1644 +
1645 +               ret = -1;
1646 +               goto unlock;
1647 +       }
1648 +
1649 +       ret = 0;
1650 +
1651 +unlock:
1652 +       vchi_service_release(instance->vchi_handle[0]);
1653 +       mutex_unlock(&instance->vchi_mutex);
1654 +
1655 +       LOG_DBG(" .. OUT\n");
1656 +       return ret;
1657 +}
1658 +
1659 +int bcm2835_audio_set_ctls(bcm2835_chip_t * chip)
1660 +{
1661 +       int i;
1662 +       int ret = 0;
1663 +       LOG_DBG(" .. IN\n");
1664 +       LOG_DBG(" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
1665 +
1666 +       /* change ctls for all substreams */
1667 +       for (i = 0; i < MAX_SUBSTREAMS; i++) {
1668 +               if (chip->avail_substreams & (1 << i)) {
1669 +                       if (!chip->alsa_stream[i])
1670 +                       {
1671 +                               LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams);
1672 +                               ret = 0;
1673 +                       }
1674 +                       else if (bcm2835_audio_set_ctls_chan /* returns 0 on success */
1675 +                                (chip->alsa_stream[i], chip) != 0)
1676 +                                {
1677 +                                       LOG_ERR("Couldn't set the controls for stream %d\n", i);
1678 +                                       ret = -1;
1679 +                                }
1680 +                       else LOG_DBG(" Controls set for stream %d\n", i);
1681 +               }
1682 +       }
1683 +       LOG_DBG(" .. OUT ret=%d\n", ret);
1684 +       return ret;
1685 +}
1686 +
1687 +int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
1688 +                            uint32_t channels, uint32_t samplerate,
1689 +                            uint32_t bps)
1690 +{
1691 +       VC_AUDIO_MSG_T m;
1692 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1693 +       int32_t success;
1694 +       int ret;
1695 +       LOG_DBG(" .. IN\n");
1696 +
1697 +       LOG_INFO
1698 +           (" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
1699 +            channels, samplerate, bps);
1700 +
1701 +       /* resend ctls - alsa_stream may not have been open when first send */
1702 +       ret = bcm2835_audio_set_ctls_chan(alsa_stream, alsa_stream->chip);
1703 +       if (ret != 0) {
1704 +               LOG_ERR(" Alsa controls not supported\n");
1705 +               return -EINVAL;
1706 +       }
1707 +
1708 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1709 +       {
1710 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1711 +               return -EINTR;
1712 +       }
1713 +       vchi_service_use(instance->vchi_handle[0]);
1714 +
1715 +       instance->result = -1;
1716 +
1717 +       m.type = VC_AUDIO_MSG_TYPE_CONFIG;
1718 +       m.u.config.channels = channels;
1719 +       m.u.config.samplerate = samplerate;
1720 +       m.u.config.bps = bps;
1721 +
1722 +       /* Create the message available completion */
1723 +       init_completion(&instance->msg_avail_comp);
1724 +
1725 +       /* Send the message to the videocore */
1726 +       success = vchi_msg_queue(instance->vchi_handle[0],
1727 +                                &m, sizeof m,
1728 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1729 +
1730 +       if (success != 0) {
1731 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1732 +                       __func__, success);
1733 +
1734 +               ret = -1;
1735 +               goto unlock;
1736 +       }
1737 +
1738 +       /* We are expecting a reply from the videocore */
1739 +       ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
1740 +       if (ret) {
1741 +               LOG_ERR("%s: failed on waiting for event (status=%d)\n",
1742 +                       __func__, success);
1743 +               goto unlock;
1744 +       }
1745 +
1746 +       if (instance->result != 0) {
1747 +               LOG_ERR("%s: result=%d", __func__, instance->result);
1748 +
1749 +               ret = -1;
1750 +               goto unlock;
1751 +       }
1752 +
1753 +       ret = 0;
1754 +
1755 +unlock:
1756 +       vchi_service_release(instance->vchi_handle[0]);
1757 +       mutex_unlock(&instance->vchi_mutex);
1758 +
1759 +       LOG_DBG(" .. OUT\n");
1760 +       return ret;
1761 +}
1762 +
1763 +int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream)
1764 +{
1765 +       LOG_DBG(" .. IN\n");
1766 +
1767 +       LOG_DBG(" .. OUT\n");
1768 +
1769 +       return 0;
1770 +}
1771 +
1772 +static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream)
1773 +{
1774 +       VC_AUDIO_MSG_T m;
1775 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1776 +       int32_t success;
1777 +       int ret;
1778 +       LOG_DBG(" .. IN\n");
1779 +
1780 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1781 +       {
1782 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1783 +               return -EINTR;
1784 +       }
1785 +       vchi_service_use(instance->vchi_handle[0]);
1786 +
1787 +       m.type = VC_AUDIO_MSG_TYPE_START;
1788 +
1789 +       /* Send the message to the videocore */
1790 +       success = vchi_msg_queue(instance->vchi_handle[0],
1791 +                                &m, sizeof m,
1792 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1793 +
1794 +       if (success != 0) {
1795 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1796 +                       __func__, success);
1797 +
1798 +               ret = -1;
1799 +               goto unlock;
1800 +       }
1801 +
1802 +       ret = 0;
1803 +
1804 +unlock:
1805 +       vchi_service_release(instance->vchi_handle[0]);
1806 +       mutex_unlock(&instance->vchi_mutex);
1807 +       LOG_DBG(" .. OUT\n");
1808 +       return ret;
1809 +}
1810 +
1811 +static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream)
1812 +{
1813 +       VC_AUDIO_MSG_T m;
1814 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1815 +       int32_t success;
1816 +       int ret;
1817 +       LOG_DBG(" .. IN\n");
1818 +
1819 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1820 +       {
1821 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1822 +               return -EINTR;
1823 +       }
1824 +       vchi_service_use(instance->vchi_handle[0]);
1825 +
1826 +       m.type = VC_AUDIO_MSG_TYPE_STOP;
1827 +       m.u.stop.draining = alsa_stream->draining;
1828 +
1829 +       /* Send the message to the videocore */
1830 +       success = vchi_msg_queue(instance->vchi_handle[0],
1831 +                                &m, sizeof m,
1832 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1833 +
1834 +       if (success != 0) {
1835 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1836 +                       __func__, success);
1837 +
1838 +               ret = -1;
1839 +               goto unlock;
1840 +       }
1841 +
1842 +       ret = 0;
1843 +
1844 +unlock:
1845 +       vchi_service_release(instance->vchi_handle[0]);
1846 +       mutex_unlock(&instance->vchi_mutex);
1847 +       LOG_DBG(" .. OUT\n");
1848 +       return ret;
1849 +}
1850 +
1851 +int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
1852 +{
1853 +       VC_AUDIO_MSG_T m;
1854 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1855 +       int32_t success;
1856 +       int ret;
1857 +       LOG_DBG(" .. IN\n");
1858 +
1859 +       my_workqueue_quit(alsa_stream);
1860 +
1861 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1862 +       {
1863 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1864 +               return -EINTR;
1865 +       }
1866 +       vchi_service_use(instance->vchi_handle[0]);
1867 +
1868 +       m.type = VC_AUDIO_MSG_TYPE_CLOSE;
1869 +
1870 +       /* Create the message available completion */
1871 +       init_completion(&instance->msg_avail_comp);
1872 +
1873 +       /* Send the message to the videocore */
1874 +       success = vchi_msg_queue(instance->vchi_handle[0],
1875 +                                &m, sizeof m,
1876 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1877 +
1878 +       if (success != 0) {
1879 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1880 +                       __func__, success);
1881 +               ret = -1;
1882 +               goto unlock;
1883 +       }
1884 +
1885 +       ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
1886 +       if (ret) {
1887 +               LOG_ERR("%s: failed on waiting for event (status=%d)\n",
1888 +                       __func__, success);
1889 +               goto unlock;
1890 +       }
1891 +       if (instance->result != 0) {
1892 +               LOG_ERR("%s: failed result (status=%d)\n",
1893 +                       __func__, instance->result);
1894 +
1895 +               ret = -1;
1896 +               goto unlock;
1897 +       }
1898 +
1899 +       ret = 0;
1900 +
1901 +unlock:
1902 +       vchi_service_release(instance->vchi_handle[0]);
1903 +       mutex_unlock(&instance->vchi_mutex);
1904 +
1905 +       /* Stop the audio service */
1906 +       if (instance) {
1907 +               vc_vchi_audio_deinit(instance);
1908 +               alsa_stream->instance = NULL;
1909 +       }
1910 +       LOG_DBG(" .. OUT\n");
1911 +       return ret;
1912 +}
1913 +
1914 +int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
1915 +                              uint32_t count, void *src)
1916 +{
1917 +       VC_AUDIO_MSG_T m;
1918 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1919 +       int32_t success;
1920 +       int ret;
1921 +
1922 +       LOG_DBG(" .. IN\n");
1923 +
1924 +       LOG_INFO(" Writing %d bytes from %p\n", count, src);
1925 +
1926 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1927 +       {
1928 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1929 +               return -EINTR;
1930 +       }
1931 +       vchi_service_use(instance->vchi_handle[0]);
1932 +
1933 +       if ( instance->peer_version==0 && vchi_get_peer_version(instance->vchi_handle[0], &instance->peer_version) == 0 ) {
1934 +               LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
1935 +       }
1936 +       m.type = VC_AUDIO_MSG_TYPE_WRITE;
1937 +       m.u.write.count = count;
1938 +       // old version uses bulk, new version uses control
1939 +       m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0:4000;
1940 +       m.u.write.callback = alsa_stream->fifo_irq_handler;
1941 +       m.u.write.cookie = alsa_stream;
1942 +       m.u.write.silence = src == NULL;
1943 +
1944 +       /* Send the message to the videocore */
1945 +       success = vchi_msg_queue(instance->vchi_handle[0],
1946 +                                &m, sizeof m,
1947 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1948 +
1949 +       if (success != 0) {
1950 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1951 +                       __func__, success);
1952 +
1953 +               ret = -1;
1954 +               goto unlock;
1955 +       }
1956 +       if (!m.u.write.silence) {
1957 +               if (m.u.write.max_packet == 0) {
1958 +                       /* Send the message to the videocore */
1959 +                       success = vchi_bulk_queue_transmit(instance->vchi_handle[0],
1960 +                                                          src, count,
1961 +                                                          0 *
1962 +                                                          VCHI_FLAGS_BLOCK_UNTIL_QUEUED
1963 +                                                          +
1964 +                                                          1 *
1965 +                                                          VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
1966 +                                                          NULL);
1967 +               } else {
1968 +                       while (count > 0) {
1969 +                               int bytes = min((int)m.u.write.max_packet, (int)count);
1970 +                               success = vchi_msg_queue(instance->vchi_handle[0],
1971 +                                                        src, bytes,
1972 +                                                        VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1973 +                               src = (char *)src + bytes;
1974 +                               count -= bytes;
1975 +                       }
1976 +               }
1977 +               if (success != 0) {
1978 +                       LOG_ERR
1979 +                           ("%s: failed on vchi_bulk_queue_transmit (status=%d)\n",
1980 +                            __func__, success);
1981 +
1982 +                       ret = -1;
1983 +                       goto unlock;
1984 +               }
1985 +       }
1986 +       ret = 0;
1987 +
1988 +unlock:
1989 +       vchi_service_release(instance->vchi_handle[0]);
1990 +       mutex_unlock(&instance->vchi_mutex);
1991 +       LOG_DBG(" .. OUT\n");
1992 +       return ret;
1993 +}
1994 +
1995 +/**
1996 +  * Returns all buffers from arm->vc
1997 +  */
1998 +void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream)
1999 +{
2000 +       LOG_DBG(" .. IN\n");
2001 +       LOG_DBG(" .. OUT\n");
2002 +       return;
2003 +}
2004 +
2005 +/**
2006 +  * Forces VC to flush(drop) its filled playback buffers and
2007 +  * return them the us. (VC->ARM)
2008 +  */
2009 +void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream)
2010 +{
2011 +       LOG_DBG(" .. IN\n");
2012 +       LOG_DBG(" .. OUT\n");
2013 +}
2014 +
2015 +uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream)
2016 +{
2017 +       uint32_t count = atomic_read(&alsa_stream->retrieved);
2018 +       atomic_sub(count, &alsa_stream->retrieved);
2019 +       return count;
2020 +}
2021 +
2022 +module_param(force_bulk, bool, 0444);
2023 +MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
2024 --- /dev/null
2025 +++ b/sound/arm/bcm2835.c
2026 @@ -0,0 +1,420 @@
2027 +/*****************************************************************************
2028 +* Copyright 2011 Broadcom Corporation.  All rights reserved.
2029 +*
2030 +* Unless you and Broadcom execute a separate written software license
2031 +* agreement governing use of this software, this software is licensed to you
2032 +* under the terms of the GNU General Public License version 2, available at
2033 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
2034 +*
2035 +* Notwithstanding the above, under no circumstances may you combine this
2036 +* software in any way with any other Broadcom software provided under a
2037 +* license other than the GPL, without Broadcom's express prior written
2038 +* consent.
2039 +*****************************************************************************/
2040 +
2041 +#include <linux/platform_device.h>
2042 +
2043 +#include <linux/init.h>
2044 +#include <linux/slab.h>
2045 +#include <linux/module.h>
2046 +
2047 +#include "bcm2835.h"
2048 +
2049 +/* module parameters (see "Module Parameters") */
2050 +/* SNDRV_CARDS: maximum number of cards supported by this module */
2051 +static int index[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = -1 };
2052 +static char *id[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = NULL };
2053 +static int enable[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = 1 };
2054 +
2055 +/* HACKY global pointers needed for successive probes to work : ssp
2056 + * But compared against the changes we will have to do in VC audio_ipc code
2057 + * to export 8 audio_ipc devices as a single IPC device and then monitor all
2058 + * four devices in a thread, this gets things done quickly and should be easier
2059 + * to debug if we run into issues
2060 + */
2061 +
2062 +static struct snd_card *g_card = NULL;
2063 +static bcm2835_chip_t *g_chip = NULL;
2064 +
2065 +static int snd_bcm2835_free(bcm2835_chip_t * chip)
2066 +{
2067 +       kfree(chip);
2068 +       return 0;
2069 +}
2070 +
2071 +/* component-destructor
2072 + * (see "Management of Cards and Components")
2073 + */
2074 +static int snd_bcm2835_dev_free(struct snd_device *device)
2075 +{
2076 +       return snd_bcm2835_free(device->device_data);
2077 +}
2078 +
2079 +/* chip-specific constructor
2080 + * (see "Management of Cards and Components")
2081 + */
2082 +static int snd_bcm2835_create(struct snd_card *card,
2083 +                                       struct platform_device *pdev,
2084 +                                       bcm2835_chip_t ** rchip)
2085 +{
2086 +       bcm2835_chip_t *chip;
2087 +       int err;
2088 +       static struct snd_device_ops ops = {
2089 +               .dev_free = snd_bcm2835_dev_free,
2090 +       };
2091 +
2092 +       *rchip = NULL;
2093 +
2094 +       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
2095 +       if (chip == NULL)
2096 +               return -ENOMEM;
2097 +
2098 +       chip->card = card;
2099 +
2100 +       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
2101 +       if (err < 0) {
2102 +               snd_bcm2835_free(chip);
2103 +               return err;
2104 +       }
2105 +
2106 +       *rchip = chip;
2107 +       return 0;
2108 +}
2109 +
2110 +static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
2111 +{
2112 +       static int dev;
2113 +       bcm2835_chip_t *chip;
2114 +       struct snd_card *card;
2115 +       int err;
2116 +
2117 +       if (dev >= MAX_SUBSTREAMS)
2118 +               return -ENODEV;
2119 +
2120 +       if (!enable[dev]) {
2121 +               dev++;
2122 +               return -ENOENT;
2123 +       }
2124 +
2125 +       if (dev > 0)
2126 +               goto add_register_map;
2127 +
2128 +       err = snd_card_new(NULL, index[dev], id[dev], THIS_MODULE, 0, &g_card);
2129 +       if (err < 0)
2130 +               goto out;
2131 +
2132 +       snd_card_set_dev(g_card, &pdev->dev);
2133 +       strcpy(g_card->driver, "bcm2835");
2134 +       strcpy(g_card->shortname, "bcm2835 ALSA");
2135 +       sprintf(g_card->longname, "%s", g_card->shortname);
2136 +
2137 +       err = snd_bcm2835_create(g_card, pdev, &chip);
2138 +       if (err < 0) {
2139 +               dev_err(&pdev->dev, "Failed to create bcm2835 chip\n");
2140 +               goto out_bcm2835_create;
2141 +       }
2142 +
2143 +       g_chip = chip;
2144 +       err = snd_bcm2835_new_pcm(chip);
2145 +       if (err < 0) {
2146 +               dev_err(&pdev->dev, "Failed to create new BCM2835 pcm device\n");
2147 +               goto out_bcm2835_new_pcm;
2148 +       }
2149 +
2150 +       err = snd_bcm2835_new_spdif_pcm(chip);
2151 +       if (err < 0) {
2152 +               dev_err(&pdev->dev, "Failed to create new BCM2835 spdif pcm device\n");
2153 +               goto out_bcm2835_new_spdif;
2154 +       }
2155 +
2156 +       err = snd_bcm2835_new_ctl(chip);
2157 +       if (err < 0) {
2158 +               dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n");
2159 +               goto out_bcm2835_new_ctl;
2160 +       }
2161 +
2162 +add_register_map:
2163 +       card = g_card;
2164 +       chip = g_chip;
2165 +
2166 +       BUG_ON(!(card && chip));
2167 +
2168 +       chip->avail_substreams |= (1 << dev);
2169 +       chip->pdev[dev] = pdev;
2170 +
2171 +       if (dev == 0) {
2172 +               err = snd_card_register(card);
2173 +               if (err < 0) {
2174 +                       dev_err(&pdev->dev,
2175 +                               "Failed to register bcm2835 ALSA card \n");
2176 +                       goto out_card_register;
2177 +               }
2178 +               platform_set_drvdata(pdev, card);
2179 +               audio_info("bcm2835 ALSA card created!\n");
2180 +       } else {
2181 +               audio_info("bcm2835 ALSA chip created!\n");
2182 +               platform_set_drvdata(pdev, (void *)dev);
2183 +       }
2184 +
2185 +       dev++;
2186 +
2187 +       return 0;
2188 +
2189 +out_card_register:
2190 +out_bcm2835_new_ctl:
2191 +out_bcm2835_new_spdif:
2192 +out_bcm2835_new_pcm:
2193 +out_bcm2835_create:
2194 +       BUG_ON(!g_card);
2195 +       if (snd_card_free(g_card))
2196 +               dev_err(&pdev->dev, "Failed to free Registered alsa card\n");
2197 +       g_card = NULL;
2198 +out:
2199 +       dev = SNDRV_CARDS;      /* stop more avail_substreams from being probed */
2200 +       dev_err(&pdev->dev, "BCM2835 ALSA Probe failed !!\n");
2201 +       return err;
2202 +}
2203 +
2204 +static int snd_bcm2835_alsa_remove(struct platform_device *pdev)
2205 +{
2206 +       uint32_t idx;
2207 +       void *drv_data;
2208 +
2209 +       drv_data = platform_get_drvdata(pdev);
2210 +
2211 +       if (drv_data == (void *)g_card) {
2212 +               /* This is the card device */
2213 +               snd_card_free((struct snd_card *)drv_data);
2214 +               g_card = NULL;
2215 +               g_chip = NULL;
2216 +       } else {
2217 +               idx = (uint32_t) drv_data;
2218 +               if (g_card != NULL) {
2219 +                       BUG_ON(!g_chip);
2220 +                       /* We pass chip device numbers in audio ipc devices
2221 +                        * other than the one we registered our card with
2222 +                        */
2223 +                       idx = (uint32_t) drv_data;
2224 +                       BUG_ON(!idx || idx > MAX_SUBSTREAMS);
2225 +                       g_chip->avail_substreams &= ~(1 << idx);
2226 +                       /* There should be atleast one substream registered
2227 +                        * after we are done here, as it wil be removed when
2228 +                        * the *remove* is called for the card device
2229 +                        */
2230 +                       BUG_ON(!g_chip->avail_substreams);
2231 +               }
2232 +       }
2233 +
2234 +       platform_set_drvdata(pdev, NULL);
2235 +
2236 +       return 0;
2237 +}
2238 +
2239 +#ifdef CONFIG_PM
2240 +static int snd_bcm2835_alsa_suspend(struct platform_device *pdev,
2241 +                                   pm_message_t state)
2242 +{
2243 +       return 0;
2244 +}
2245 +
2246 +static int snd_bcm2835_alsa_resume(struct platform_device *pdev)
2247 +{
2248 +       return 0;
2249 +}
2250 +
2251 +#endif
2252 +
2253 +static struct platform_driver bcm2835_alsa0_driver = {
2254 +       .probe = snd_bcm2835_alsa_probe,
2255 +       .remove = snd_bcm2835_alsa_remove,
2256 +#ifdef CONFIG_PM
2257 +       .suspend = snd_bcm2835_alsa_suspend,
2258 +       .resume = snd_bcm2835_alsa_resume,
2259 +#endif
2260 +       .driver = {
2261 +                  .name = "bcm2835_AUD0",
2262 +                  .owner = THIS_MODULE,
2263 +                  },
2264 +};
2265 +
2266 +static struct platform_driver bcm2835_alsa1_driver = {
2267 +       .probe = snd_bcm2835_alsa_probe,
2268 +       .remove = snd_bcm2835_alsa_remove,
2269 +#ifdef CONFIG_PM
2270 +       .suspend = snd_bcm2835_alsa_suspend,
2271 +       .resume = snd_bcm2835_alsa_resume,
2272 +#endif
2273 +       .driver = {
2274 +                  .name = "bcm2835_AUD1",
2275 +                  .owner = THIS_MODULE,
2276 +                  },
2277 +};
2278 +
2279 +static struct platform_driver bcm2835_alsa2_driver = {
2280 +       .probe = snd_bcm2835_alsa_probe,
2281 +       .remove = snd_bcm2835_alsa_remove,
2282 +#ifdef CONFIG_PM
2283 +       .suspend = snd_bcm2835_alsa_suspend,
2284 +       .resume = snd_bcm2835_alsa_resume,
2285 +#endif
2286 +       .driver = {
2287 +                  .name = "bcm2835_AUD2",
2288 +                  .owner = THIS_MODULE,
2289 +                  },
2290 +};
2291 +
2292 +static struct platform_driver bcm2835_alsa3_driver = {
2293 +       .probe = snd_bcm2835_alsa_probe,
2294 +       .remove = snd_bcm2835_alsa_remove,
2295 +#ifdef CONFIG_PM
2296 +       .suspend = snd_bcm2835_alsa_suspend,
2297 +       .resume = snd_bcm2835_alsa_resume,
2298 +#endif
2299 +       .driver = {
2300 +                  .name = "bcm2835_AUD3",
2301 +                  .owner = THIS_MODULE,
2302 +                  },
2303 +};
2304 +
2305 +static struct platform_driver bcm2835_alsa4_driver = {
2306 +       .probe = snd_bcm2835_alsa_probe,
2307 +       .remove = snd_bcm2835_alsa_remove,
2308 +#ifdef CONFIG_PM
2309 +       .suspend = snd_bcm2835_alsa_suspend,
2310 +       .resume = snd_bcm2835_alsa_resume,
2311 +#endif
2312 +       .driver = {
2313 +                  .name = "bcm2835_AUD4",
2314 +                  .owner = THIS_MODULE,
2315 +                  },
2316 +};
2317 +
2318 +static struct platform_driver bcm2835_alsa5_driver = {
2319 +       .probe = snd_bcm2835_alsa_probe,
2320 +       .remove = snd_bcm2835_alsa_remove,
2321 +#ifdef CONFIG_PM
2322 +       .suspend = snd_bcm2835_alsa_suspend,
2323 +       .resume = snd_bcm2835_alsa_resume,
2324 +#endif
2325 +       .driver = {
2326 +                  .name = "bcm2835_AUD5",
2327 +                  .owner = THIS_MODULE,
2328 +                  },
2329 +};
2330 +
2331 +static struct platform_driver bcm2835_alsa6_driver = {
2332 +       .probe = snd_bcm2835_alsa_probe,
2333 +       .remove = snd_bcm2835_alsa_remove,
2334 +#ifdef CONFIG_PM
2335 +       .suspend = snd_bcm2835_alsa_suspend,
2336 +       .resume = snd_bcm2835_alsa_resume,
2337 +#endif
2338 +       .driver = {
2339 +                  .name = "bcm2835_AUD6",
2340 +                  .owner = THIS_MODULE,
2341 +                  },
2342 +};
2343 +
2344 +static struct platform_driver bcm2835_alsa7_driver = {
2345 +       .probe = snd_bcm2835_alsa_probe,
2346 +       .remove = snd_bcm2835_alsa_remove,
2347 +#ifdef CONFIG_PM
2348 +       .suspend = snd_bcm2835_alsa_suspend,
2349 +       .resume = snd_bcm2835_alsa_resume,
2350 +#endif
2351 +       .driver = {
2352 +                  .name = "bcm2835_AUD7",
2353 +                  .owner = THIS_MODULE,
2354 +                  },
2355 +};
2356 +
2357 +static int bcm2835_alsa_device_init(void)
2358 +{
2359 +       int err;
2360 +       err = platform_driver_register(&bcm2835_alsa0_driver);
2361 +       if (err) {
2362 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2363 +               goto out;
2364 +       }
2365 +
2366 +       err = platform_driver_register(&bcm2835_alsa1_driver);
2367 +       if (err) {
2368 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2369 +               goto unregister_0;
2370 +       }
2371 +
2372 +       err = platform_driver_register(&bcm2835_alsa2_driver);
2373 +       if (err) {
2374 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2375 +               goto unregister_1;
2376 +       }
2377 +
2378 +       err = platform_driver_register(&bcm2835_alsa3_driver);
2379 +       if (err) {
2380 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2381 +               goto unregister_2;
2382 +       }
2383 +
2384 +       err = platform_driver_register(&bcm2835_alsa4_driver);
2385 +       if (err) {
2386 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2387 +               goto unregister_3;
2388 +       }
2389 +
2390 +       err = platform_driver_register(&bcm2835_alsa5_driver);
2391 +       if (err) {
2392 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2393 +               goto unregister_4;
2394 +       }
2395 +
2396 +       err = platform_driver_register(&bcm2835_alsa6_driver);
2397 +       if (err) {
2398 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2399 +               goto unregister_5;
2400 +       }
2401 +
2402 +       err = platform_driver_register(&bcm2835_alsa7_driver);
2403 +       if (err) {
2404 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2405 +               goto unregister_6;
2406 +       }
2407 +
2408 +       return 0;
2409 +
2410 +unregister_6:
2411 +       platform_driver_unregister(&bcm2835_alsa6_driver);
2412 +unregister_5:
2413 +       platform_driver_unregister(&bcm2835_alsa5_driver);
2414 +unregister_4:
2415 +       platform_driver_unregister(&bcm2835_alsa4_driver);
2416 +unregister_3:
2417 +       platform_driver_unregister(&bcm2835_alsa3_driver);
2418 +unregister_2:
2419 +       platform_driver_unregister(&bcm2835_alsa2_driver);
2420 +unregister_1:
2421 +       platform_driver_unregister(&bcm2835_alsa1_driver);
2422 +unregister_0:
2423 +       platform_driver_unregister(&bcm2835_alsa0_driver);
2424 +out:
2425 +       return err;
2426 +}
2427 +
2428 +static void bcm2835_alsa_device_exit(void)
2429 +{
2430 +       platform_driver_unregister(&bcm2835_alsa0_driver);
2431 +       platform_driver_unregister(&bcm2835_alsa1_driver);
2432 +       platform_driver_unregister(&bcm2835_alsa2_driver);
2433 +       platform_driver_unregister(&bcm2835_alsa3_driver);
2434 +       platform_driver_unregister(&bcm2835_alsa4_driver);
2435 +       platform_driver_unregister(&bcm2835_alsa5_driver);
2436 +       platform_driver_unregister(&bcm2835_alsa6_driver);
2437 +       platform_driver_unregister(&bcm2835_alsa7_driver);
2438 +}
2439 +
2440 +late_initcall(bcm2835_alsa_device_init);
2441 +module_exit(bcm2835_alsa_device_exit);
2442 +
2443 +MODULE_AUTHOR("Dom Cobley");
2444 +MODULE_DESCRIPTION("Alsa driver for BCM2835 chip");
2445 +MODULE_LICENSE("GPL");
2446 +MODULE_ALIAS("platform:bcm2835_alsa");
2447 --- /dev/null
2448 +++ b/sound/arm/bcm2835.h
2449 @@ -0,0 +1,167 @@
2450 +/*****************************************************************************
2451 +* Copyright 2011 Broadcom Corporation.  All rights reserved.
2452 +*
2453 +* Unless you and Broadcom execute a separate written software license
2454 +* agreement governing use of this software, this software is licensed to you
2455 +* under the terms of the GNU General Public License version 2, available at
2456 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
2457 +*
2458 +* Notwithstanding the above, under no circumstances may you combine this
2459 +* software in any way with any other Broadcom software provided under a
2460 +* license other than the GPL, without Broadcom's express prior written
2461 +* consent.
2462 +*****************************************************************************/
2463 +
2464 +#ifndef __SOUND_ARM_BCM2835_H
2465 +#define __SOUND_ARM_BCM2835_H
2466 +
2467 +#include <linux/device.h>
2468 +#include <linux/list.h>
2469 +#include <linux/interrupt.h>
2470 +#include <linux/wait.h>
2471 +#include <sound/core.h>
2472 +#include <sound/initval.h>
2473 +#include <sound/pcm.h>
2474 +#include <sound/pcm_params.h>
2475 +#include <sound/pcm-indirect.h>
2476 +#include <linux/workqueue.h>
2477 +
2478 +/*
2479 +#define AUDIO_DEBUG_ENABLE
2480 +#define AUDIO_VERBOSE_DEBUG_ENABLE
2481 +*/
2482 +
2483 +/* Debug macros */
2484 +
2485 +#ifdef AUDIO_DEBUG_ENABLE
2486 +#ifdef AUDIO_VERBOSE_DEBUG_ENABLE
2487 +
2488 +#define audio_debug(fmt, arg...)       \
2489 +       printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
2490 +
2491 +#define audio_info(fmt, arg...)        \
2492 +       printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
2493 +
2494 +#else
2495 +
2496 +#define audio_debug(fmt, arg...)
2497 +
2498 +#define audio_info(fmt, arg...)
2499 +
2500 +#endif /* AUDIO_VERBOSE_DEBUG_ENABLE */
2501 +
2502 +#else
2503 +
2504 +#define audio_debug(fmt, arg...)
2505 +
2506 +#define audio_info(fmt, arg...)
2507 +
2508 +#endif /* AUDIO_DEBUG_ENABLE */
2509 +
2510 +#define audio_error(fmt, arg...)       \
2511 +       printk(KERN_ERR"%s:%d " fmt, __func__, __LINE__, ##arg)
2512 +
2513 +#define audio_warning(fmt, arg...)     \
2514 +       printk(KERN_WARNING"%s:%d " fmt, __func__, __LINE__, ##arg)
2515 +
2516 +#define audio_alert(fmt, arg...)       \
2517 +       printk(KERN_ALERT"%s:%d " fmt, __func__, __LINE__, ##arg)
2518 +
2519 +#define MAX_SUBSTREAMS                 (8)
2520 +#define AVAIL_SUBSTREAMS_MASK          (0xff)
2521 +enum {
2522 +       CTRL_VOL_MUTE,
2523 +       CTRL_VOL_UNMUTE
2524 +};
2525 +
2526 +/* macros for alsa2chip and chip2alsa, instead of functions */
2527 +
2528 +#define alsa2chip(vol) (uint)(-((vol << 8) / 100))     /* convert alsa to chip volume (defined as macro rather than function call) */
2529 +#define chip2alsa(vol) -((vol * 100) >> 8)                     /* convert chip to alsa volume */
2530 +
2531 +/* Some constants for values .. */
2532 +typedef enum {
2533 +       AUDIO_DEST_AUTO = 0,
2534 +       AUDIO_DEST_HEADPHONES = 1,
2535 +       AUDIO_DEST_HDMI = 2,
2536 +       AUDIO_DEST_MAX,
2537 +} SND_BCM2835_ROUTE_T;
2538 +
2539 +typedef enum {
2540 +       PCM_PLAYBACK_VOLUME,
2541 +       PCM_PLAYBACK_MUTE,
2542 +       PCM_PLAYBACK_DEVICE,
2543 +} SND_BCM2835_CTRL_T;
2544 +
2545 +/* definition of the chip-specific record */
2546 +typedef struct bcm2835_chip {
2547 +       struct snd_card *card;
2548 +       struct snd_pcm *pcm;
2549 +       struct snd_pcm *pcm_spdif;
2550 +       /* Bitmat for valid reg_base and irq numbers */
2551 +       uint32_t avail_substreams;
2552 +       struct platform_device *pdev[MAX_SUBSTREAMS];
2553 +       struct bcm2835_alsa_stream *alsa_stream[MAX_SUBSTREAMS];
2554 +
2555 +       int volume;
2556 +       int old_volume; /* stores the volume value whist muted */
2557 +       int dest;
2558 +       int mute;
2559 +
2560 +       unsigned int opened;
2561 +       unsigned int spdif_status;
2562 +       struct mutex audio_mutex;
2563 +} bcm2835_chip_t;
2564 +
2565 +typedef struct bcm2835_alsa_stream {
2566 +       bcm2835_chip_t *chip;
2567 +       struct snd_pcm_substream *substream;
2568 +       struct snd_pcm_indirect pcm_indirect;
2569 +
2570 +       struct semaphore buffers_update_sem;
2571 +       struct semaphore control_sem;
2572 +       spinlock_t lock;
2573 +       volatile uint32_t control;
2574 +       volatile uint32_t status;
2575 +
2576 +       int open;
2577 +       int running;
2578 +       int draining;
2579 +
2580 +       int channels;
2581 +       int params_rate;
2582 +       int pcm_format_width;
2583 +
2584 +       unsigned int pos;
2585 +       unsigned int buffer_size;
2586 +       unsigned int period_size;
2587 +
2588 +       uint32_t enable_fifo_irq;
2589 +       irq_handler_t fifo_irq_handler;
2590 +
2591 +       atomic_t retrieved;
2592 +       struct opaque_AUDIO_INSTANCE_T *instance;
2593 +       struct workqueue_struct *my_wq;
2594 +       int idx;
2595 +} bcm2835_alsa_stream_t;
2596 +
2597 +int snd_bcm2835_new_ctl(bcm2835_chip_t * chip);
2598 +int snd_bcm2835_new_pcm(bcm2835_chip_t * chip);
2599 +int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip);
2600 +
2601 +int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream);
2602 +int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream);
2603 +int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
2604 +                            uint32_t channels, uint32_t samplerate,
2605 +                            uint32_t bps);
2606 +int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream);
2607 +int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream);
2608 +int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream);
2609 +int bcm2835_audio_set_ctls(bcm2835_chip_t * chip);
2610 +int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
2611 +                       void *src);
2612 +uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream);
2613 +void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream);
2614 +void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream);
2615 +
2616 +#endif /* __SOUND_ARM_BCM2835_H */
2617 --- /dev/null
2618 +++ b/sound/arm/vc_vchi_audioserv_defs.h
2619 @@ -0,0 +1,116 @@
2620 +/*****************************************************************************
2621 +* Copyright 2011 Broadcom Corporation.  All rights reserved.
2622 +*
2623 +* Unless you and Broadcom execute a separate written software license
2624 +* agreement governing use of this software, this software is licensed to you
2625 +* under the terms of the GNU General Public License version 2, available at
2626 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
2627 +*
2628 +* Notwithstanding the above, under no circumstances may you combine this
2629 +* software in any way with any other Broadcom software provided under a
2630 +* license other than the GPL, without Broadcom's express prior written
2631 +* consent.
2632 +*****************************************************************************/
2633 +
2634 +#ifndef _VC_AUDIO_DEFS_H_
2635 +#define _VC_AUDIO_DEFS_H_
2636 +
2637 +#define VC_AUDIOSERV_MIN_VER 1
2638 +#define VC_AUDIOSERV_VER 2
2639 +
2640 +// FourCC code used for VCHI connection
2641 +#define VC_AUDIO_SERVER_NAME  MAKE_FOURCC("AUDS")
2642 +
2643 +// Maximum message length
2644 +#define VC_AUDIO_MAX_MSG_LEN  (sizeof( VC_AUDIO_MSG_T ))
2645 +
2646 +// List of screens that are currently supported
2647 +// All message types supported for HOST->VC direction
2648 +typedef enum {
2649 +       VC_AUDIO_MSG_TYPE_RESULT,       // Generic result
2650 +       VC_AUDIO_MSG_TYPE_COMPLETE,     // Generic result
2651 +       VC_AUDIO_MSG_TYPE_CONFIG,       // Configure audio
2652 +       VC_AUDIO_MSG_TYPE_CONTROL,      // Configure audio
2653 +       VC_AUDIO_MSG_TYPE_OPEN, // Configure audio
2654 +       VC_AUDIO_MSG_TYPE_CLOSE,        // Configure audio
2655 +       VC_AUDIO_MSG_TYPE_START,        // Configure audio
2656 +       VC_AUDIO_MSG_TYPE_STOP, // Configure audio
2657 +       VC_AUDIO_MSG_TYPE_WRITE,        // Configure audio
2658 +       VC_AUDIO_MSG_TYPE_MAX
2659 +} VC_AUDIO_MSG_TYPE;
2660 +
2661 +// configure the audio
2662 +typedef struct {
2663 +       uint32_t channels;
2664 +       uint32_t samplerate;
2665 +       uint32_t bps;
2666 +
2667 +} VC_AUDIO_CONFIG_T;
2668 +
2669 +typedef struct {
2670 +       uint32_t volume;
2671 +       uint32_t dest;
2672 +
2673 +} VC_AUDIO_CONTROL_T;
2674 +
2675 +// audio
2676 +typedef struct {
2677 +       uint32_t dummy;
2678 +
2679 +} VC_AUDIO_OPEN_T;
2680 +
2681 +// audio
2682 +typedef struct {
2683 +       uint32_t dummy;
2684 +
2685 +} VC_AUDIO_CLOSE_T;
2686 +// audio
2687 +typedef struct {
2688 +       uint32_t dummy;
2689 +
2690 +} VC_AUDIO_START_T;
2691 +// audio
2692 +typedef struct {
2693 +       uint32_t draining;
2694 +
2695 +} VC_AUDIO_STOP_T;
2696 +
2697 +// configure the write audio samples
2698 +typedef struct {
2699 +       uint32_t count;         // in bytes
2700 +       void *callback;
2701 +       void *cookie;
2702 +       uint16_t silence;
2703 +       uint16_t max_packet;
2704 +} VC_AUDIO_WRITE_T;
2705 +
2706 +// Generic result for a request (VC->HOST)
2707 +typedef struct {
2708 +       int32_t success;        // Success value
2709 +
2710 +} VC_AUDIO_RESULT_T;
2711 +
2712 +// Generic result for a request (VC->HOST)
2713 +typedef struct {
2714 +       int32_t count;          // Success value
2715 +       void *callback;
2716 +       void *cookie;
2717 +} VC_AUDIO_COMPLETE_T;
2718 +
2719 +// Message header for all messages in HOST->VC direction
2720 +typedef struct {
2721 +       int32_t type;           // Message type (VC_AUDIO_MSG_TYPE)
2722 +       union {
2723 +               VC_AUDIO_CONFIG_T config;
2724 +               VC_AUDIO_CONTROL_T control;
2725 +               VC_AUDIO_OPEN_T open;
2726 +               VC_AUDIO_CLOSE_T close;
2727 +               VC_AUDIO_START_T start;
2728 +               VC_AUDIO_STOP_T stop;
2729 +               VC_AUDIO_WRITE_T write;
2730 +               VC_AUDIO_RESULT_T result;
2731 +               VC_AUDIO_COMPLETE_T complete;
2732 +       } u;
2733 +} VC_AUDIO_MSG_T;
2734 +
2735 +#endif // _VC_AUDIO_DEFS_H_