diff options
Diffstat (limited to 'sound/soc/txx9/txx9aclc.c')
-rw-r--r-- | sound/soc/txx9/txx9aclc.c | 141 |
1 files changed, 80 insertions, 61 deletions
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index 0e3452303ea6..f4aa4e03c888 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c | |||
@@ -22,6 +22,16 @@ | |||
22 | #include <sound/soc.h> | 22 | #include <sound/soc.h> |
23 | #include "txx9aclc.h" | 23 | #include "txx9aclc.h" |
24 | 24 | ||
25 | static struct txx9aclc_soc_device { | ||
26 | struct txx9aclc_dmadata dmadata[2]; | ||
27 | } txx9aclc_soc_device; | ||
28 | |||
29 | /* REVISIT: How to find txx9aclc_drvdata from snd_ac97? */ | ||
30 | static struct txx9aclc_plat_drvdata *txx9aclc_drvdata; | ||
31 | |||
32 | static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev, | ||
33 | struct txx9aclc_dmadata *dmadata); | ||
34 | |||
25 | static const struct snd_pcm_hardware txx9aclc_pcm_hardware = { | 35 | static const struct snd_pcm_hardware txx9aclc_pcm_hardware = { |
26 | /* | 36 | /* |
27 | * REVISIT: SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | 37 | * REVISIT: SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
@@ -46,7 +56,6 @@ static int txx9aclc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
46 | struct snd_pcm_hw_params *params) | 56 | struct snd_pcm_hw_params *params) |
47 | { | 57 | { |
48 | struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); | 58 | struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); |
49 | struct snd_soc_device *socdev = rtd->socdev; | ||
50 | struct snd_pcm_runtime *runtime = substream->runtime; | 59 | struct snd_pcm_runtime *runtime = substream->runtime; |
51 | struct txx9aclc_dmadata *dmadata = runtime->private_data; | 60 | struct txx9aclc_dmadata *dmadata = runtime->private_data; |
52 | int ret; | 61 | int ret; |
@@ -55,13 +64,13 @@ static int txx9aclc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
55 | if (ret < 0) | 64 | if (ret < 0) |
56 | return ret; | 65 | return ret; |
57 | 66 | ||
58 | dev_dbg(socdev->dev, | 67 | dev_dbg(rtd->platform->dev, |
59 | "runtime->dma_area = %#lx dma_addr = %#lx dma_bytes = %zd " | 68 | "runtime->dma_area = %#lx dma_addr = %#lx dma_bytes = %zd " |
60 | "runtime->min_align %ld\n", | 69 | "runtime->min_align %ld\n", |
61 | (unsigned long)runtime->dma_area, | 70 | (unsigned long)runtime->dma_area, |
62 | (unsigned long)runtime->dma_addr, runtime->dma_bytes, | 71 | (unsigned long)runtime->dma_addr, runtime->dma_bytes, |
63 | runtime->min_align); | 72 | runtime->min_align); |
64 | dev_dbg(socdev->dev, | 73 | dev_dbg(rtd->platform->dev, |
65 | "periods %d period_bytes %d stream %d\n", | 74 | "periods %d period_bytes %d stream %d\n", |
66 | params_periods(params), params_period_bytes(params), | 75 | params_periods(params), params_period_bytes(params), |
67 | substream->stream); | 76 | substream->stream); |
@@ -152,11 +161,7 @@ static void txx9aclc_dma_tasklet(unsigned long data) | |||
152 | 161 | ||
153 | spin_lock_irqsave(&dmadata->dma_lock, flags); | 162 | spin_lock_irqsave(&dmadata->dma_lock, flags); |
154 | if (dmadata->frag_count < 0) { | 163 | if (dmadata->frag_count < 0) { |
155 | struct txx9aclc_soc_device *dev = | 164 | struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata; |
156 | container_of(dmadata, struct txx9aclc_soc_device, | ||
157 | dmadata[substream->stream]); | ||
158 | struct txx9aclc_plat_drvdata *drvdata = | ||
159 | txx9aclc_get_plat_drvdata(dev); | ||
160 | void __iomem *base = drvdata->base; | 165 | void __iomem *base = drvdata->base; |
161 | 166 | ||
162 | spin_unlock_irqrestore(&dmadata->dma_lock, flags); | 167 | spin_unlock_irqrestore(&dmadata->dma_lock, flags); |
@@ -202,10 +207,7 @@ static void txx9aclc_dma_tasklet(unsigned long data) | |||
202 | static int txx9aclc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | 207 | static int txx9aclc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) |
203 | { | 208 | { |
204 | struct txx9aclc_dmadata *dmadata = substream->runtime->private_data; | 209 | struct txx9aclc_dmadata *dmadata = substream->runtime->private_data; |
205 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 210 | struct txx9aclc_plat_drvdata *drvdata =txx9aclc_drvdata; |
206 | struct txx9aclc_soc_device *dev = | ||
207 | container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev); | ||
208 | struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev); | ||
209 | void __iomem *base = drvdata->base; | 211 | void __iomem *base = drvdata->base; |
210 | unsigned long flags; | 212 | unsigned long flags; |
211 | int ret = 0; | 213 | int ret = 0; |
@@ -244,9 +246,7 @@ txx9aclc_pcm_pointer(struct snd_pcm_substream *substream) | |||
244 | 246 | ||
245 | static int txx9aclc_pcm_open(struct snd_pcm_substream *substream) | 247 | static int txx9aclc_pcm_open(struct snd_pcm_substream *substream) |
246 | { | 248 | { |
247 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 249 | struct txx9aclc_soc_device *dev = &txx9aclc_soc_device; |
248 | struct txx9aclc_soc_device *dev = | ||
249 | container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev); | ||
250 | struct txx9aclc_dmadata *dmadata = &dev->dmadata[substream->stream]; | 250 | struct txx9aclc_dmadata *dmadata = &dev->dmadata[substream->stream]; |
251 | int ret; | 251 | int ret; |
252 | 252 | ||
@@ -291,8 +291,38 @@ static void txx9aclc_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
291 | static int txx9aclc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | 291 | static int txx9aclc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, |
292 | struct snd_pcm *pcm) | 292 | struct snd_pcm *pcm) |
293 | { | 293 | { |
294 | struct platform_device *pdev = to_platform_device(dai->platform->dev); | ||
295 | struct txx9aclc_soc_device *dev; | ||
296 | struct resource *r; | ||
297 | int i; | ||
298 | int ret; | ||
299 | |||
300 | /* at this point onwards the AC97 component has probed and this will be valid */ | ||
301 | dev = snd_soc_dai_get_drvdata(dai); | ||
302 | |||
303 | dev->dmadata[0].stream = SNDRV_PCM_STREAM_PLAYBACK; | ||
304 | dev->dmadata[1].stream = SNDRV_PCM_STREAM_CAPTURE; | ||
305 | for (i = 0; i < 2; i++) { | ||
306 | r = platform_get_resource(pdev, IORESOURCE_DMA, i); | ||
307 | if (!r) { | ||
308 | ret = -EBUSY; | ||
309 | goto exit; | ||
310 | } | ||
311 | dev->dmadata[i].dma_res = r; | ||
312 | ret = txx9aclc_dma_init(dev, &dev->dmadata[i]); | ||
313 | if (ret) | ||
314 | goto exit; | ||
315 | } | ||
294 | return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | 316 | return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, |
295 | card->dev, 64 * 1024, 4 * 1024 * 1024); | 317 | card->dev, 64 * 1024, 4 * 1024 * 1024); |
318 | |||
319 | exit: | ||
320 | for (i = 0; i < 2; i++) { | ||
321 | if (dev->dmadata[i].dma_chan) | ||
322 | dma_release_channel(dev->dmadata[i].dma_chan); | ||
323 | dev->dmadata[i].dma_chan = NULL; | ||
324 | } | ||
325 | return ret; | ||
296 | } | 326 | } |
297 | 327 | ||
298 | static bool filter(struct dma_chan *chan, void *param) | 328 | static bool filter(struct dma_chan *chan, void *param) |
@@ -314,7 +344,7 @@ static bool filter(struct dma_chan *chan, void *param) | |||
314 | static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev, | 344 | static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev, |
315 | struct txx9aclc_dmadata *dmadata) | 345 | struct txx9aclc_dmadata *dmadata) |
316 | { | 346 | { |
317 | struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev); | 347 | struct txx9aclc_plat_drvdata *drvdata =txx9aclc_drvdata; |
318 | struct txx9dmac_slave *ds = &dmadata->dma_slave; | 348 | struct txx9dmac_slave *ds = &dmadata->dma_slave; |
319 | dma_cap_mask_t mask; | 349 | dma_cap_mask_t mask; |
320 | 350 | ||
@@ -334,7 +364,7 @@ static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev, | |||
334 | dma_cap_set(DMA_SLAVE, mask); | 364 | dma_cap_set(DMA_SLAVE, mask); |
335 | dmadata->dma_chan = dma_request_channel(mask, filter, dmadata); | 365 | dmadata->dma_chan = dma_request_channel(mask, filter, dmadata); |
336 | if (!dmadata->dma_chan) { | 366 | if (!dmadata->dma_chan) { |
337 | dev_err(dev->soc_dev.dev, | 367 | printk(KERN_ERR |
338 | "DMA channel for %s is not available\n", | 368 | "DMA channel for %s is not available\n", |
339 | dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK ? | 369 | dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK ? |
340 | "playback" : "capture"); | 370 | "playback" : "capture"); |
@@ -345,45 +375,16 @@ static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev, | |||
345 | return 0; | 375 | return 0; |
346 | } | 376 | } |
347 | 377 | ||
348 | static int txx9aclc_pcm_probe(struct platform_device *pdev) | 378 | static int txx9aclc_pcm_probe(struct snd_soc_platform *platform) |
349 | { | 379 | { |
350 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 380 | snd_soc_platform_set_drvdata(platform, &txx9aclc_soc_device); |
351 | struct txx9aclc_soc_device *dev = | ||
352 | container_of(socdev, struct txx9aclc_soc_device, soc_dev); | ||
353 | struct resource *r; | ||
354 | int i; | ||
355 | int ret; | ||
356 | |||
357 | dev->dmadata[0].stream = SNDRV_PCM_STREAM_PLAYBACK; | ||
358 | dev->dmadata[1].stream = SNDRV_PCM_STREAM_CAPTURE; | ||
359 | for (i = 0; i < 2; i++) { | ||
360 | r = platform_get_resource(dev->aclc_pdev, IORESOURCE_DMA, i); | ||
361 | if (!r) { | ||
362 | ret = -EBUSY; | ||
363 | goto exit; | ||
364 | } | ||
365 | dev->dmadata[i].dma_res = r; | ||
366 | ret = txx9aclc_dma_init(dev, &dev->dmadata[i]); | ||
367 | if (ret) | ||
368 | goto exit; | ||
369 | } | ||
370 | return 0; | 381 | return 0; |
371 | |||
372 | exit: | ||
373 | for (i = 0; i < 2; i++) { | ||
374 | if (dev->dmadata[i].dma_chan) | ||
375 | dma_release_channel(dev->dmadata[i].dma_chan); | ||
376 | dev->dmadata[i].dma_chan = NULL; | ||
377 | } | ||
378 | return ret; | ||
379 | } | 382 | } |
380 | 383 | ||
381 | static int txx9aclc_pcm_remove(struct platform_device *pdev) | 384 | static int txx9aclc_pcm_remove(struct snd_soc_platform *platform) |
382 | { | 385 | { |
383 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 386 | struct txx9aclc_soc_device *dev = snd_soc_platform_get_drvdata(platform); |
384 | struct txx9aclc_soc_device *dev = | 387 | struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata; |
385 | container_of(socdev, struct txx9aclc_soc_device, soc_dev); | ||
386 | struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev); | ||
387 | void __iomem *base = drvdata->base; | 388 | void __iomem *base = drvdata->base; |
388 | int i; | 389 | int i; |
389 | 390 | ||
@@ -406,28 +407,46 @@ static int txx9aclc_pcm_remove(struct platform_device *pdev) | |||
406 | return 0; | 407 | return 0; |
407 | } | 408 | } |
408 | 409 | ||
409 | struct snd_soc_platform txx9aclc_soc_platform = { | 410 | static struct snd_soc_platform_driver txx9aclc_soc_platform = { |
410 | .name = "txx9aclc-audio", | ||
411 | .probe = txx9aclc_pcm_probe, | 411 | .probe = txx9aclc_pcm_probe, |
412 | .remove = txx9aclc_pcm_remove, | 412 | .remove = txx9aclc_pcm_remove, |
413 | .pcm_ops = &txx9aclc_pcm_ops, | 413 | .ops = &txx9aclc_pcm_ops, |
414 | .pcm_new = txx9aclc_pcm_new, | 414 | .pcm_new = txx9aclc_pcm_new, |
415 | .pcm_free = txx9aclc_pcm_free_dma_buffers, | 415 | .pcm_free = txx9aclc_pcm_free_dma_buffers, |
416 | }; | 416 | }; |
417 | EXPORT_SYMBOL_GPL(txx9aclc_soc_platform); | ||
418 | 417 | ||
419 | static int __init txx9aclc_soc_platform_init(void) | 418 | static int __devinit txx9aclc_soc_platform_probe(struct platform_device *pdev) |
420 | { | 419 | { |
421 | return snd_soc_register_platform(&txx9aclc_soc_platform); | 420 | return snd_soc_register_platform(&pdev->dev, &txx9aclc_soc_platform); |
422 | } | 421 | } |
423 | 422 | ||
424 | static void __exit txx9aclc_soc_platform_exit(void) | 423 | static int __devexit txx9aclc_soc_platform_remove(struct platform_device *pdev) |
425 | { | 424 | { |
426 | snd_soc_unregister_platform(&txx9aclc_soc_platform); | 425 | snd_soc_unregister_platform(&pdev->dev); |
426 | return 0; | ||
427 | } | 427 | } |
428 | 428 | ||
429 | module_init(txx9aclc_soc_platform_init); | 429 | static struct platform_driver txx9aclc_pcm_driver = { |
430 | module_exit(txx9aclc_soc_platform_exit); | 430 | .driver = { |
431 | .name = "txx9aclc-pcm-audio", | ||
432 | .owner = THIS_MODULE, | ||
433 | }, | ||
434 | |||
435 | .probe = txx9aclc_soc_platform_probe, | ||
436 | .remove = __devexit_p(txx9aclc_soc_platform_remove), | ||
437 | }; | ||
438 | |||
439 | static int __init snd_txx9aclc_pcm_init(void) | ||
440 | { | ||
441 | return platform_driver_register(&txx9aclc_pcm_driver); | ||
442 | } | ||
443 | module_init(snd_txx9aclc_pcm_init); | ||
444 | |||
445 | static void __exit snd_txx9aclc_pcm_exit(void) | ||
446 | { | ||
447 | platform_driver_unregister(&txx9aclc_pcm_driver); | ||
448 | } | ||
449 | module_exit(snd_txx9aclc_pcm_exit); | ||
431 | 450 | ||
432 | MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>"); | 451 | MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>"); |
433 | MODULE_DESCRIPTION("TXx9 ACLC Audio DMA driver"); | 452 | MODULE_DESCRIPTION("TXx9 ACLC Audio DMA driver"); |