diff options
Diffstat (limited to 'sound/soc/au1x/dbdma2.c')
-rw-r--r-- | sound/soc/au1x/dbdma2.c | 129 |
1 files changed, 102 insertions, 27 deletions
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index 594c6c5b7838..6d9f4c624949 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Au12x0/Au1550 PSC ALSA ASoC audio support. | 2 | * Au12x0/Au1550 PSC ALSA ASoC audio support. |
3 | * | 3 | * |
4 | * (c) 2007-2008 MSC Vertriebsges.m.b.H., | 4 | * (c) 2007-2008 MSC Vertriebsges.m.b.H., |
5 | * Manuel Lauss <mano@roarinelk.homelinux.net> | 5 | * Manuel Lauss <manuel.lauss@gmail.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
@@ -51,8 +51,8 @@ struct au1xpsc_audio_dmadata { | |||
51 | struct snd_pcm_substream *substream; | 51 | struct snd_pcm_substream *substream; |
52 | unsigned long curr_period; /* current segment DDMA is working on */ | 52 | unsigned long curr_period; /* current segment DDMA is working on */ |
53 | unsigned long q_period; /* queue period(s) */ | 53 | unsigned long q_period; /* queue period(s) */ |
54 | unsigned long dma_area; /* address of queued DMA area */ | 54 | dma_addr_t dma_area; /* address of queued DMA area */ |
55 | unsigned long dma_area_s; /* start address of DMA area */ | 55 | dma_addr_t dma_area_s; /* start address of DMA area */ |
56 | unsigned long pos; /* current byte position being played */ | 56 | unsigned long pos; /* current byte position being played */ |
57 | unsigned long periods; /* number of SG segments in total */ | 57 | unsigned long periods; /* number of SG segments in total */ |
58 | unsigned long period_bytes; /* size in bytes of one SG segment */ | 58 | unsigned long period_bytes; /* size in bytes of one SG segment */ |
@@ -94,8 +94,7 @@ static const struct snd_pcm_hardware au1xpsc_pcm_hardware = { | |||
94 | 94 | ||
95 | static void au1x_pcm_queue_tx(struct au1xpsc_audio_dmadata *cd) | 95 | static void au1x_pcm_queue_tx(struct au1xpsc_audio_dmadata *cd) |
96 | { | 96 | { |
97 | au1xxx_dbdma_put_source_flags(cd->ddma_chan, | 97 | au1xxx_dbdma_put_source(cd->ddma_chan, cd->dma_area, |
98 | (void *)phys_to_virt(cd->dma_area), | ||
99 | cd->period_bytes, DDMA_FLAGS_IE); | 98 | cd->period_bytes, DDMA_FLAGS_IE); |
100 | 99 | ||
101 | /* update next-to-queue period */ | 100 | /* update next-to-queue period */ |
@@ -109,9 +108,8 @@ static void au1x_pcm_queue_tx(struct au1xpsc_audio_dmadata *cd) | |||
109 | 108 | ||
110 | static void au1x_pcm_queue_rx(struct au1xpsc_audio_dmadata *cd) | 109 | static void au1x_pcm_queue_rx(struct au1xpsc_audio_dmadata *cd) |
111 | { | 110 | { |
112 | au1xxx_dbdma_put_dest_flags(cd->ddma_chan, | 111 | au1xxx_dbdma_put_dest(cd->ddma_chan, cd->dma_area, |
113 | (void *)phys_to_virt(cd->dma_area), | 112 | cd->period_bytes, DDMA_FLAGS_IE); |
114 | cd->period_bytes, DDMA_FLAGS_IE); | ||
115 | 113 | ||
116 | /* update next-to-queue period */ | 114 | /* update next-to-queue period */ |
117 | ++cd->q_period; | 115 | ++cd->q_period; |
@@ -233,7 +231,7 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
233 | pcd->substream = substream; | 231 | pcd->substream = substream; |
234 | pcd->period_bytes = params_period_bytes(params); | 232 | pcd->period_bytes = params_period_bytes(params); |
235 | pcd->periods = params_periods(params); | 233 | pcd->periods = params_periods(params); |
236 | pcd->dma_area_s = pcd->dma_area = (unsigned long)runtime->dma_addr; | 234 | pcd->dma_area_s = pcd->dma_area = runtime->dma_addr; |
237 | pcd->q_period = 0; | 235 | pcd->q_period = 0; |
238 | pcd->curr_period = 0; | 236 | pcd->curr_period = 0; |
239 | pcd->pos = 0; | 237 | pcd->pos = 0; |
@@ -333,6 +331,30 @@ static int au1xpsc_pcm_new(struct snd_card *card, | |||
333 | 331 | ||
334 | static int au1xpsc_pcm_probe(struct platform_device *pdev) | 332 | static int au1xpsc_pcm_probe(struct platform_device *pdev) |
335 | { | 333 | { |
334 | if (!au1xpsc_audio_pcmdma[PCM_TX] || !au1xpsc_audio_pcmdma[PCM_RX]) | ||
335 | return -ENODEV; | ||
336 | |||
337 | return 0; | ||
338 | } | ||
339 | |||
340 | static int au1xpsc_pcm_remove(struct platform_device *pdev) | ||
341 | { | ||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | /* au1xpsc audio platform */ | ||
346 | struct snd_soc_platform au1xpsc_soc_platform = { | ||
347 | .name = "au1xpsc-pcm-dbdma", | ||
348 | .probe = au1xpsc_pcm_probe, | ||
349 | .remove = au1xpsc_pcm_remove, | ||
350 | .pcm_ops = &au1xpsc_pcm_ops, | ||
351 | .pcm_new = au1xpsc_pcm_new, | ||
352 | .pcm_free = au1xpsc_pcm_free_dma_buffers, | ||
353 | }; | ||
354 | EXPORT_SYMBOL_GPL(au1xpsc_soc_platform); | ||
355 | |||
356 | static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev) | ||
357 | { | ||
336 | struct resource *r; | 358 | struct resource *r; |
337 | int ret; | 359 | int ret; |
338 | 360 | ||
@@ -365,7 +387,9 @@ static int au1xpsc_pcm_probe(struct platform_device *pdev) | |||
365 | } | 387 | } |
366 | (au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start; | 388 | (au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start; |
367 | 389 | ||
368 | return 0; | 390 | ret = snd_soc_register_platform(&au1xpsc_soc_platform); |
391 | if (!ret) | ||
392 | return ret; | ||
369 | 393 | ||
370 | out2: | 394 | out2: |
371 | kfree(au1xpsc_audio_pcmdma[PCM_RX]); | 395 | kfree(au1xpsc_audio_pcmdma[PCM_RX]); |
@@ -376,10 +400,12 @@ out1: | |||
376 | return ret; | 400 | return ret; |
377 | } | 401 | } |
378 | 402 | ||
379 | static int au1xpsc_pcm_remove(struct platform_device *pdev) | 403 | static int __devexit au1xpsc_pcm_drvremove(struct platform_device *pdev) |
380 | { | 404 | { |
381 | int i; | 405 | int i; |
382 | 406 | ||
407 | snd_soc_unregister_platform(&au1xpsc_soc_platform); | ||
408 | |||
383 | for (i = 0; i < 2; i++) { | 409 | for (i = 0; i < 2; i++) { |
384 | if (au1xpsc_audio_pcmdma[i]) { | 410 | if (au1xpsc_audio_pcmdma[i]) { |
385 | au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]); | 411 | au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]); |
@@ -391,32 +417,81 @@ static int au1xpsc_pcm_remove(struct platform_device *pdev) | |||
391 | return 0; | 417 | return 0; |
392 | } | 418 | } |
393 | 419 | ||
394 | /* au1xpsc audio platform */ | 420 | static struct platform_driver au1xpsc_pcm_driver = { |
395 | struct snd_soc_platform au1xpsc_soc_platform = { | 421 | .driver = { |
396 | .name = "au1xpsc-pcm-dbdma", | 422 | .name = "au1xpsc-pcm", |
397 | .probe = au1xpsc_pcm_probe, | 423 | .owner = THIS_MODULE, |
398 | .remove = au1xpsc_pcm_remove, | 424 | }, |
399 | .pcm_ops = &au1xpsc_pcm_ops, | 425 | .probe = au1xpsc_pcm_drvprobe, |
400 | .pcm_new = au1xpsc_pcm_new, | 426 | .remove = __devexit_p(au1xpsc_pcm_drvremove), |
401 | .pcm_free = au1xpsc_pcm_free_dma_buffers, | ||
402 | }; | 427 | }; |
403 | EXPORT_SYMBOL_GPL(au1xpsc_soc_platform); | ||
404 | 428 | ||
405 | static int __init au1xpsc_audio_dbdma_init(void) | 429 | static int __init au1xpsc_audio_dbdma_load(void) |
406 | { | 430 | { |
407 | au1xpsc_audio_pcmdma[PCM_TX] = NULL; | 431 | au1xpsc_audio_pcmdma[PCM_TX] = NULL; |
408 | au1xpsc_audio_pcmdma[PCM_RX] = NULL; | 432 | au1xpsc_audio_pcmdma[PCM_RX] = NULL; |
409 | return snd_soc_register_platform(&au1xpsc_soc_platform); | 433 | return platform_driver_register(&au1xpsc_pcm_driver); |
410 | } | 434 | } |
411 | 435 | ||
412 | static void __exit au1xpsc_audio_dbdma_exit(void) | 436 | static void __exit au1xpsc_audio_dbdma_unload(void) |
413 | { | 437 | { |
414 | snd_soc_unregister_platform(&au1xpsc_soc_platform); | 438 | platform_driver_unregister(&au1xpsc_pcm_driver); |
439 | } | ||
440 | |||
441 | module_init(au1xpsc_audio_dbdma_load); | ||
442 | module_exit(au1xpsc_audio_dbdma_unload); | ||
443 | |||
444 | |||
445 | struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev) | ||
446 | { | ||
447 | struct resource *res, *r; | ||
448 | struct platform_device *pd; | ||
449 | int id[2]; | ||
450 | int ret; | ||
451 | |||
452 | r = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
453 | if (!r) | ||
454 | return NULL; | ||
455 | id[0] = r->start; | ||
456 | |||
457 | r = platform_get_resource(pdev, IORESOURCE_DMA, 1); | ||
458 | if (!r) | ||
459 | return NULL; | ||
460 | id[1] = r->start; | ||
461 | |||
462 | res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL); | ||
463 | if (!res) | ||
464 | return NULL; | ||
465 | |||
466 | res[0].start = res[0].end = id[0]; | ||
467 | res[1].start = res[1].end = id[1]; | ||
468 | res[0].flags = res[1].flags = IORESOURCE_DMA; | ||
469 | |||
470 | pd = platform_device_alloc("au1xpsc-pcm", -1); | ||
471 | if (!pd) | ||
472 | goto out; | ||
473 | |||
474 | pd->resource = res; | ||
475 | pd->num_resources = 2; | ||
476 | |||
477 | ret = platform_device_add(pd); | ||
478 | if (!ret) | ||
479 | return pd; | ||
480 | |||
481 | platform_device_put(pd); | ||
482 | out: | ||
483 | kfree(res); | ||
484 | return NULL; | ||
415 | } | 485 | } |
486 | EXPORT_SYMBOL_GPL(au1xpsc_pcm_add); | ||
416 | 487 | ||
417 | module_init(au1xpsc_audio_dbdma_init); | 488 | void au1xpsc_pcm_destroy(struct platform_device *dmapd) |
418 | module_exit(au1xpsc_audio_dbdma_exit); | 489 | { |
490 | if (dmapd) | ||
491 | platform_device_unregister(dmapd); | ||
492 | } | ||
493 | EXPORT_SYMBOL_GPL(au1xpsc_pcm_destroy); | ||
419 | 494 | ||
420 | MODULE_LICENSE("GPL"); | 495 | MODULE_LICENSE("GPL"); |
421 | MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver"); | 496 | MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver"); |
422 | MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); | 497 | MODULE_AUTHOR("Manuel Lauss"); |