aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/txx9/txx9aclc.c
diff options
context:
space:
mode:
authorLiam Girdwood <lrg@slimlogic.co.uk>2010-03-17 16:15:21 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-08-12 09:00:00 -0400
commitf0fba2ad1b6b53d5360125c41953b7afcd6deff0 (patch)
treef6ad50905f8daa616593c978d7ae992e73241180 /sound/soc/txx9/txx9aclc.c
parentbda7d2a862e6b788bca2d02d38a07966a9c92e48 (diff)
ASoC: multi-component - ASoC Multi-Component Support
This patch extends the ASoC API to allow sound cards to have more than one CODEC and more than one platform DMA controller. This is achieved by dividing some current ASoC structures that contain both driver data and device data into structures that only either contain device data or driver data. i.e. struct snd_soc_codec ---> struct snd_soc_codec (device data) +-> struct snd_soc_codec_driver (driver data) struct snd_soc_platform ---> struct snd_soc_platform (device data) +-> struct snd_soc_platform_driver (driver data) struct snd_soc_dai ---> struct snd_soc_dai (device data) +-> struct snd_soc_dai_driver (driver data) struct snd_soc_device ---> deleted This now allows ASoC to be more tightly aligned with the Linux driver model and also means that every ASoC codec, platform and (platform) DAI is a kernel device. ASoC component private data is now stored as device private data. The ASoC sound card struct snd_soc_card has also been updated to store lists of it's components rather than a pointer to a codec and platform. The PCM runtime struct soc_pcm_runtime now has pointers to all its components. This patch adds DAPM support for ASoC multi-component and removes struct snd_soc_socdev from DAPM core. All DAPM calls are now made on a card, codec or runtime PCM level basis rather than using snd_soc_socdev. Other notable multi-component changes:- * Stream operations now de-reference less structures. * close_delayed work() now runs on a DAI basis rather than looping all DAIs in a card. * PM suspend()/resume() operations can now handle N CODECs and Platforms per sound card. * Added soc_bind_dai_link() to bind the component devices to the sound card. * Added soc_dai_link_probe() and soc_dai_link_remove() to probe and remove DAI link components. * sysfs entries can now be registered per component per card. * snd_soc_new_pcms() functionailty rolled into dai_link_probe(). * snd_soc_register_codec() now does all the codec list and mutex init. This patch changes the probe() and remove() of the CODEC drivers as follows:- o Make CODEC driver a platform driver o Moved all struct snd_soc_codec list, mutex, etc initialiasation to core. o Removed all static codec pointers (drivers now support > 1 codec dev) o snd_soc_register_pcms() now done by core. o snd_soc_register_dai() folded into snd_soc_register_codec(). CS4270 portions: Acked-by: Timur Tabi <timur@freescale.com> Some TLV320aic23 and Cirrus platform fixes. Signed-off-by: Ryan Mallon <ryan@bluewatersys.com> TI CODEC and OMAP fixes Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Signed-off-by: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> Signed-off-by: Jarkko Nikula <jhnikula@gmail.com> Samsung platform and misc fixes :- Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Reviewed-by: Jassi Brar <jassi.brar@samsung.com> Signed-off-by: Seungwhan Youn <sw.youn@samsung.com> MPC8610 and PPC fixes. Signed-off-by: Timur Tabi <timur@freescale.com> i.MX fixes and some core fixes. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> J4740 platform fixes:- Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> CC: Tony Lindgren <tony@atomide.com> CC: Nicolas Ferre <nicolas.ferre@atmel.com> CC: Kevin Hilman <khilman@deeprootsystems.com> CC: Sascha Hauer <s.hauer@pengutronix.de> CC: Atsushi Nemoto <anemo@mba.ocn.ne.jp> CC: Kuninori Morimoto <morimoto.kuninori@renesas.com> CC: Daniel Gloeckner <dg@emlix.com> CC: Manuel Lauss <mano@roarinelk.homelinux.net> CC: Mike Frysinger <vapier.adi@gmail.com> CC: Arnaud Patard <apatard@mandriva.com> CC: Wan ZongShun <mcuos.com@gmail.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc/txx9/txx9aclc.c')
-rw-r--r--sound/soc/txx9/txx9aclc.c141
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
25static 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? */
30static struct txx9aclc_plat_drvdata *txx9aclc_drvdata;
31
32static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
33 struct txx9aclc_dmadata *dmadata);
34
25static const struct snd_pcm_hardware txx9aclc_pcm_hardware = { 35static 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)
202static int txx9aclc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 207static 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
245static int txx9aclc_pcm_open(struct snd_pcm_substream *substream) 247static 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)
291static int txx9aclc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, 291static 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
319exit:
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
298static bool filter(struct dma_chan *chan, void *param) 328static bool filter(struct dma_chan *chan, void *param)
@@ -314,7 +344,7 @@ static bool filter(struct dma_chan *chan, void *param)
314static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev, 344static 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
348static int txx9aclc_pcm_probe(struct platform_device *pdev) 378static 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
372exit:
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
381static int txx9aclc_pcm_remove(struct platform_device *pdev) 384static 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
409struct snd_soc_platform txx9aclc_soc_platform = { 410static 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};
417EXPORT_SYMBOL_GPL(txx9aclc_soc_platform);
418 417
419static int __init txx9aclc_soc_platform_init(void) 418static 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
424static void __exit txx9aclc_soc_platform_exit(void) 423static 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
429module_init(txx9aclc_soc_platform_init); 429static struct platform_driver txx9aclc_pcm_driver = {
430module_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
439static int __init snd_txx9aclc_pcm_init(void)
440{
441 return platform_driver_register(&txx9aclc_pcm_driver);
442}
443module_init(snd_txx9aclc_pcm_init);
444
445static void __exit snd_txx9aclc_pcm_exit(void)
446{
447 platform_driver_unregister(&txx9aclc_pcm_driver);
448}
449module_exit(snd_txx9aclc_pcm_exit);
431 450
432MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>"); 451MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
433MODULE_DESCRIPTION("TXx9 ACLC Audio DMA driver"); 452MODULE_DESCRIPTION("TXx9 ACLC Audio DMA driver");