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