aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm9705.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/codecs/wm9705.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/codecs/wm9705.c')
-rw-r--r--sound/soc/codecs/wm9705.c116
1 files changed, 50 insertions, 66 deletions
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index 8793341849d1..e4d8f5339c51 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -248,8 +248,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
248{ 248{
249 struct snd_pcm_runtime *runtime = substream->runtime; 249 struct snd_pcm_runtime *runtime = substream->runtime;
250 struct snd_soc_pcm_runtime *rtd = substream->private_data; 250 struct snd_soc_pcm_runtime *rtd = substream->private_data;
251 struct snd_soc_device *socdev = rtd->socdev; 251 struct snd_soc_codec *codec = rtd->codec;
252 struct snd_soc_codec *codec = socdev->card->codec;
253 int reg; 252 int reg;
254 u16 vra; 253 u16 vra;
255 254
@@ -273,9 +272,9 @@ static struct snd_soc_dai_ops wm9705_dai_ops = {
273 .prepare = ac97_prepare, 272 .prepare = ac97_prepare,
274}; 273};
275 274
276struct snd_soc_dai wm9705_dai[] = { 275static struct snd_soc_dai_driver wm9705_dai[] = {
277 { 276 {
278 .name = "AC97 HiFi", 277 .name = "wm9705-hifi",
279 .ac97_control = 1, 278 .ac97_control = 1,
280 .playback = { 279 .playback = {
281 .stream_name = "HiFi Playback", 280 .stream_name = "HiFi Playback",
@@ -294,7 +293,7 @@ struct snd_soc_dai wm9705_dai[] = {
294 .ops = &wm9705_dai_ops, 293 .ops = &wm9705_dai_ops,
295 }, 294 },
296 { 295 {
297 .name = "AC97 Aux", 296 .name = "wm9705-aux",
298 .playback = { 297 .playback = {
299 .stream_name = "Aux Playback", 298 .stream_name = "Aux Playback",
300 .channels_min = 1, 299 .channels_min = 1,
@@ -304,7 +303,6 @@ struct snd_soc_dai wm9705_dai[] = {
304 }, 303 },
305 } 304 }
306}; 305};
307EXPORT_SYMBOL_GPL(wm9705_dai);
308 306
309static int wm9705_reset(struct snd_soc_codec *codec) 307static int wm9705_reset(struct snd_soc_codec *codec)
310{ 308{
@@ -318,20 +316,15 @@ static int wm9705_reset(struct snd_soc_codec *codec)
318} 316}
319 317
320#ifdef CONFIG_PM 318#ifdef CONFIG_PM
321static int wm9705_soc_suspend(struct platform_device *pdev, pm_message_t msg) 319static int wm9705_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
322{ 320{
323 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
324 struct snd_soc_codec *codec = socdev->card->codec;
325
326 soc_ac97_ops.write(codec->ac97, AC97_POWERDOWN, 0xffff); 321 soc_ac97_ops.write(codec->ac97, AC97_POWERDOWN, 0xffff);
327 322
328 return 0; 323 return 0;
329} 324}
330 325
331static int wm9705_soc_resume(struct platform_device *pdev) 326static int wm9705_soc_resume(struct snd_soc_codec *codec)
332{ 327{
333 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
334 struct snd_soc_codec *codec = socdev->card->codec;
335 int i, ret; 328 int i, ret;
336 u16 *cache = codec->reg_cache; 329 u16 *cache = codec->reg_cache;
337 330
@@ -352,49 +345,18 @@ static int wm9705_soc_resume(struct platform_device *pdev)
352#define wm9705_soc_resume NULL 345#define wm9705_soc_resume NULL
353#endif 346#endif
354 347
355static int wm9705_soc_probe(struct platform_device *pdev) 348static int wm9705_soc_probe(struct snd_soc_codec *codec)
356{ 349{
357 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
358 struct snd_soc_codec *codec;
359 int ret = 0; 350 int ret = 0;
360 351
361 printk(KERN_INFO "WM9705 SoC Audio Codec\n"); 352 printk(KERN_INFO "WM9705 SoC Audio Codec\n");
362 353
363 socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
364 GFP_KERNEL);
365 if (socdev->card->codec == NULL)
366 return -ENOMEM;
367 codec = socdev->card->codec;
368 mutex_init(&codec->mutex);
369
370 codec->reg_cache = kmemdup(wm9705_reg, sizeof(wm9705_reg), GFP_KERNEL);
371 if (codec->reg_cache == NULL) {
372 ret = -ENOMEM;
373 goto cache_err;
374 }
375 codec->reg_cache_size = sizeof(wm9705_reg);
376 codec->reg_cache_step = 2;
377
378 codec->name = "WM9705";
379 codec->owner = THIS_MODULE;
380 codec->dai = wm9705_dai;
381 codec->num_dai = ARRAY_SIZE(wm9705_dai);
382 codec->write = ac97_write;
383 codec->read = ac97_read;
384 INIT_LIST_HEAD(&codec->dapm_widgets);
385 INIT_LIST_HEAD(&codec->dapm_paths);
386
387 ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); 354 ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
388 if (ret < 0) { 355 if (ret < 0) {
389 printk(KERN_ERR "wm9705: failed to register AC97 codec\n"); 356 printk(KERN_ERR "wm9705: failed to register AC97 codec\n");
390 goto codec_err; 357 return ret;
391 } 358 }
392 359
393 /* register pcms */
394 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
395 if (ret < 0)
396 goto pcm_err;
397
398 ret = wm9705_reset(codec); 360 ret = wm9705_reset(codec);
399 if (ret) 361 if (ret)
400 goto reset_err; 362 goto reset_err;
@@ -406,40 +368,62 @@ static int wm9705_soc_probe(struct platform_device *pdev)
406 return 0; 368 return 0;
407 369
408reset_err: 370reset_err:
409 snd_soc_free_pcms(socdev);
410pcm_err:
411 snd_soc_free_ac97_codec(codec); 371 snd_soc_free_ac97_codec(codec);
412codec_err:
413 kfree(codec->reg_cache);
414cache_err:
415 kfree(socdev->card->codec);
416 socdev->card->codec = NULL;
417 return ret; 372 return ret;
418} 373}
419 374
420static int wm9705_soc_remove(struct platform_device *pdev) 375static int wm9705_soc_remove(struct snd_soc_codec *codec)
421{ 376{
422 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
423 struct snd_soc_codec *codec = socdev->card->codec;
424
425 if (codec == NULL)
426 return 0;
427
428 snd_soc_dapm_free(socdev);
429 snd_soc_free_pcms(socdev);
430 snd_soc_free_ac97_codec(codec); 377 snd_soc_free_ac97_codec(codec);
431 kfree(codec->reg_cache);
432 kfree(codec);
433 return 0; 378 return 0;
434} 379}
435 380
436struct snd_soc_codec_device soc_codec_dev_wm9705 = { 381static struct snd_soc_codec_driver soc_codec_dev_wm9705 = {
437 .probe = wm9705_soc_probe, 382 .probe = wm9705_soc_probe,
438 .remove = wm9705_soc_remove, 383 .remove = wm9705_soc_remove,
439 .suspend = wm9705_soc_suspend, 384 .suspend = wm9705_soc_suspend,
440 .resume = wm9705_soc_resume, 385 .resume = wm9705_soc_resume,
386 .read = ac97_read,
387 .write = ac97_write,
388 .reg_cache_size = sizeof(wm9705_reg),
389 .reg_word_size = sizeof(u16),
390 .reg_cache_step = 2,
391 .reg_cache_default = wm9705_reg,
392};
393
394static __devinit int wm9705_probe(struct platform_device *pdev)
395{
396 return snd_soc_register_codec(&pdev->dev,
397 &soc_codec_dev_wm9705, wm9705_dai, ARRAY_SIZE(wm9705_dai));
398}
399
400static int __devexit wm9705_remove(struct platform_device *pdev)
401{
402 snd_soc_unregister_codec(&pdev->dev);
403 return 0;
404}
405
406static struct platform_driver wm9705_codec_driver = {
407 .driver = {
408 .name = "wm9705-codec",
409 .owner = THIS_MODULE,
410 },
411
412 .probe = wm9705_probe,
413 .remove = __devexit_p(wm9705_remove),
441}; 414};
442EXPORT_SYMBOL_GPL(soc_codec_dev_wm9705); 415
416static int __init wm9705_init(void)
417{
418 return platform_driver_register(&wm9705_codec_driver);
419}
420module_init(wm9705_init);
421
422static void __exit wm9705_exit(void)
423{
424 platform_driver_unregister(&wm9705_codec_driver);
425}
426module_exit(wm9705_exit);
443 427
444MODULE_DESCRIPTION("ASoC WM9705 driver"); 428MODULE_DESCRIPTION("ASoC WM9705 driver");
445MODULE_AUTHOR("Ian Molton"); 429MODULE_AUTHOR("Ian Molton");