diff options
Diffstat (limited to 'sound/soc/au1x/dbdma2.c')
-rw-r--r-- | sound/soc/au1x/dbdma2.c | 95 |
1 files changed, 29 insertions, 66 deletions
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index 6d9f4c624949..10fdd2854e58 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c | |||
@@ -10,9 +10,6 @@ | |||
10 | * | 10 | * |
11 | * DMA glue for Au1x-PSC audio. | 11 | * DMA glue for Au1x-PSC audio. |
12 | * | 12 | * |
13 | * NOTE: all of these drivers can only work with a SINGLE instance | ||
14 | * of a PSC. Multiple independent audio devices are impossible | ||
15 | * with ASoC v1. | ||
16 | */ | 13 | */ |
17 | 14 | ||
18 | 15 | ||
@@ -61,9 +58,6 @@ struct au1xpsc_audio_dmadata { | |||
61 | int msbits; | 58 | int msbits; |
62 | }; | 59 | }; |
63 | 60 | ||
64 | /* instance data. There can be only one, MacLeod!!!! */ | ||
65 | static struct au1xpsc_audio_dmadata *au1xpsc_audio_pcmdma[2]; | ||
66 | |||
67 | /* | 61 | /* |
68 | * These settings are somewhat okay, at least on my machine audio plays | 62 | * These settings are somewhat okay, at least on my machine audio plays |
69 | * almost skip-free. Especially the 64kB buffer seems to help a LOT. | 63 | * almost skip-free. Especially the 64kB buffer seems to help a LOT. |
@@ -199,6 +193,14 @@ out: | |||
199 | return 0; | 193 | return 0; |
200 | } | 194 | } |
201 | 195 | ||
196 | static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream *ss) | ||
197 | { | ||
198 | struct snd_soc_pcm_runtime *rtd = ss->private_data; | ||
199 | struct au1xpsc_audio_dmadata *pcd = | ||
200 | snd_soc_platform_get_drvdata(rtd->platform); | ||
201 | return &pcd[SUBSTREAM_TYPE(ss)]; | ||
202 | } | ||
203 | |||
202 | static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream, | 204 | static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream, |
203 | struct snd_pcm_hw_params *params) | 205 | struct snd_pcm_hw_params *params) |
204 | { | 206 | { |
@@ -211,7 +213,7 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
211 | goto out; | 213 | goto out; |
212 | 214 | ||
213 | stype = SUBSTREAM_TYPE(substream); | 215 | stype = SUBSTREAM_TYPE(substream); |
214 | pcd = au1xpsc_audio_pcmdma[stype]; | 216 | pcd = to_dmadata(substream); |
215 | 217 | ||
216 | DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d " | 218 | DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d " |
217 | "runtime->min_align %d\n", | 219 | "runtime->min_align %d\n", |
@@ -249,8 +251,7 @@ static int au1xpsc_pcm_hw_free(struct snd_pcm_substream *substream) | |||
249 | 251 | ||
250 | static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream) | 252 | static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream) |
251 | { | 253 | { |
252 | struct au1xpsc_audio_dmadata *pcd = | 254 | struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream); |
253 | au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]; | ||
254 | 255 | ||
255 | au1xxx_dbdma_reset(pcd->ddma_chan); | 256 | au1xxx_dbdma_reset(pcd->ddma_chan); |
256 | 257 | ||
@@ -267,7 +268,7 @@ static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream) | |||
267 | 268 | ||
268 | static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | 269 | static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) |
269 | { | 270 | { |
270 | u32 c = au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->ddma_chan; | 271 | u32 c = to_dmadata(substream)->ddma_chan; |
271 | 272 | ||
272 | switch (cmd) { | 273 | switch (cmd) { |
273 | case SNDRV_PCM_TRIGGER_START: | 274 | case SNDRV_PCM_TRIGGER_START: |
@@ -287,8 +288,7 @@ static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
287 | static snd_pcm_uframes_t | 288 | static snd_pcm_uframes_t |
288 | au1xpsc_pcm_pointer(struct snd_pcm_substream *substream) | 289 | au1xpsc_pcm_pointer(struct snd_pcm_substream *substream) |
289 | { | 290 | { |
290 | return bytes_to_frames(substream->runtime, | 291 | return bytes_to_frames(substream->runtime, to_dmadata(substream)->pos); |
291 | au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->pos); | ||
292 | } | 292 | } |
293 | 293 | ||
294 | static int au1xpsc_pcm_open(struct snd_pcm_substream *substream) | 294 | static int au1xpsc_pcm_open(struct snd_pcm_substream *substream) |
@@ -299,7 +299,7 @@ static int au1xpsc_pcm_open(struct snd_pcm_substream *substream) | |||
299 | 299 | ||
300 | static int au1xpsc_pcm_close(struct snd_pcm_substream *substream) | 300 | static int au1xpsc_pcm_close(struct snd_pcm_substream *substream) |
301 | { | 301 | { |
302 | au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]); | 302 | au1x_pcm_dbdma_free(to_dmadata(substream)); |
303 | return 0; | 303 | return 0; |
304 | } | 304 | } |
305 | 305 | ||
@@ -329,42 +329,21 @@ static int au1xpsc_pcm_new(struct snd_card *card, | |||
329 | return 0; | 329 | return 0; |
330 | } | 330 | } |
331 | 331 | ||
332 | static int au1xpsc_pcm_probe(struct platform_device *pdev) | ||
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 */ | 332 | /* au1xpsc audio platform */ |
346 | struct snd_soc_platform au1xpsc_soc_platform = { | 333 | struct snd_soc_platform_driver au1xpsc_soc_platform = { |
347 | .name = "au1xpsc-pcm-dbdma", | 334 | .ops = &au1xpsc_pcm_ops, |
348 | .probe = au1xpsc_pcm_probe, | ||
349 | .remove = au1xpsc_pcm_remove, | ||
350 | .pcm_ops = &au1xpsc_pcm_ops, | ||
351 | .pcm_new = au1xpsc_pcm_new, | 335 | .pcm_new = au1xpsc_pcm_new, |
352 | .pcm_free = au1xpsc_pcm_free_dma_buffers, | 336 | .pcm_free = au1xpsc_pcm_free_dma_buffers, |
353 | }; | 337 | }; |
354 | EXPORT_SYMBOL_GPL(au1xpsc_soc_platform); | ||
355 | 338 | ||
356 | static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev) | 339 | static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev) |
357 | { | 340 | { |
341 | struct au1xpsc_audio_dmadata *dmadata; | ||
358 | struct resource *r; | 342 | struct resource *r; |
359 | int ret; | 343 | int ret; |
360 | 344 | ||
361 | if (au1xpsc_audio_pcmdma[PCM_TX] || au1xpsc_audio_pcmdma[PCM_RX]) | 345 | dmadata = kzalloc(2 * sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL); |
362 | return -EBUSY; | 346 | if (!dmadata) |
363 | |||
364 | /* TX DMA */ | ||
365 | au1xpsc_audio_pcmdma[PCM_TX] | ||
366 | = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL); | ||
367 | if (!au1xpsc_audio_pcmdma[PCM_TX]) | ||
368 | return -ENOMEM; | 347 | return -ENOMEM; |
369 | 348 | ||
370 | r = platform_get_resource(pdev, IORESOURCE_DMA, 0); | 349 | r = platform_get_resource(pdev, IORESOURCE_DMA, 0); |
@@ -372,47 +351,33 @@ static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev) | |||
372 | ret = -ENODEV; | 351 | ret = -ENODEV; |
373 | goto out1; | 352 | goto out1; |
374 | } | 353 | } |
375 | (au1xpsc_audio_pcmdma[PCM_TX])->ddma_id = r->start; | 354 | dmadata[PCM_TX].ddma_id = r->start; |
376 | 355 | ||
377 | /* RX DMA */ | 356 | /* RX DMA */ |
378 | au1xpsc_audio_pcmdma[PCM_RX] | ||
379 | = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL); | ||
380 | if (!au1xpsc_audio_pcmdma[PCM_RX]) | ||
381 | return -ENOMEM; | ||
382 | |||
383 | r = platform_get_resource(pdev, IORESOURCE_DMA, 1); | 357 | r = platform_get_resource(pdev, IORESOURCE_DMA, 1); |
384 | if (!r) { | 358 | if (!r) { |
385 | ret = -ENODEV; | 359 | ret = -ENODEV; |
386 | goto out2; | 360 | goto out1; |
387 | } | 361 | } |
388 | (au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start; | 362 | dmadata[PCM_RX].ddma_id = r->start; |
363 | |||
364 | platform_set_drvdata(pdev, dmadata); | ||
389 | 365 | ||
390 | ret = snd_soc_register_platform(&au1xpsc_soc_platform); | 366 | ret = snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform); |
391 | if (!ret) | 367 | if (!ret) |
392 | return ret; | 368 | return ret; |
393 | 369 | ||
394 | out2: | ||
395 | kfree(au1xpsc_audio_pcmdma[PCM_RX]); | ||
396 | au1xpsc_audio_pcmdma[PCM_RX] = NULL; | ||
397 | out1: | 370 | out1: |
398 | kfree(au1xpsc_audio_pcmdma[PCM_TX]); | 371 | kfree(dmadata); |
399 | au1xpsc_audio_pcmdma[PCM_TX] = NULL; | ||
400 | return ret; | 372 | return ret; |
401 | } | 373 | } |
402 | 374 | ||
403 | static int __devexit au1xpsc_pcm_drvremove(struct platform_device *pdev) | 375 | static int __devexit au1xpsc_pcm_drvremove(struct platform_device *pdev) |
404 | { | 376 | { |
405 | int i; | 377 | struct au1xpsc_audio_dmadata *dmadata = platform_get_drvdata(pdev); |
406 | 378 | ||
407 | snd_soc_unregister_platform(&au1xpsc_soc_platform); | 379 | snd_soc_unregister_platform(&pdev->dev); |
408 | 380 | kfree(dmadata); | |
409 | for (i = 0; i < 2; i++) { | ||
410 | if (au1xpsc_audio_pcmdma[i]) { | ||
411 | au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]); | ||
412 | kfree(au1xpsc_audio_pcmdma[i]); | ||
413 | au1xpsc_audio_pcmdma[i] = NULL; | ||
414 | } | ||
415 | } | ||
416 | 381 | ||
417 | return 0; | 382 | return 0; |
418 | } | 383 | } |
@@ -428,8 +393,6 @@ static struct platform_driver au1xpsc_pcm_driver = { | |||
428 | 393 | ||
429 | static int __init au1xpsc_audio_dbdma_load(void) | 394 | static int __init au1xpsc_audio_dbdma_load(void) |
430 | { | 395 | { |
431 | au1xpsc_audio_pcmdma[PCM_TX] = NULL; | ||
432 | au1xpsc_audio_pcmdma[PCM_RX] = NULL; | ||
433 | return platform_driver_register(&au1xpsc_pcm_driver); | 396 | return platform_driver_register(&au1xpsc_pcm_driver); |
434 | } | 397 | } |
435 | 398 | ||
@@ -467,7 +430,7 @@ struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev) | |||
467 | res[1].start = res[1].end = id[1]; | 430 | res[1].start = res[1].end = id[1]; |
468 | res[0].flags = res[1].flags = IORESOURCE_DMA; | 431 | res[0].flags = res[1].flags = IORESOURCE_DMA; |
469 | 432 | ||
470 | pd = platform_device_alloc("au1xpsc-pcm", -1); | 433 | pd = platform_device_alloc("au1xpsc-pcm", pdev->id); |
471 | if (!pd) | 434 | if (!pd) |
472 | goto out; | 435 | goto out; |
473 | 436 | ||