aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8523.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/wm8523.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/wm8523.c')
-rw-r--r--sound/soc/codecs/wm8523.c180
1 files changed, 47 insertions, 133 deletions
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 0ad039b4adf..58d411b6faa 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -30,9 +30,6 @@
30 30
31#include "wm8523.h" 31#include "wm8523.h"
32 32
33static struct snd_soc_codec *wm8523_codec;
34struct snd_soc_codec_device soc_codec_dev_wm8523;
35
36#define WM8523_NUM_SUPPLIES 2 33#define WM8523_NUM_SUPPLIES 2
37static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = { 34static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = {
38 "AVDD", 35 "AVDD",
@@ -43,7 +40,8 @@ static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = {
43 40
44/* codec private data */ 41/* codec private data */
45struct wm8523_priv { 42struct wm8523_priv {
46 struct snd_soc_codec codec; 43 enum snd_soc_control_type control_type;
44 void *control_data;
47 u16 reg_cache[WM8523_REGISTER_COUNT]; 45 u16 reg_cache[WM8523_REGISTER_COUNT];
48 struct regulator_bulk_data supplies[WM8523_NUM_SUPPLIES]; 46 struct regulator_bulk_data supplies[WM8523_NUM_SUPPLIES];
49 unsigned int sysclk; 47 unsigned int sysclk;
@@ -162,8 +160,7 @@ static int wm8523_hw_params(struct snd_pcm_substream *substream,
162 struct snd_soc_dai *dai) 160 struct snd_soc_dai *dai)
163{ 161{
164 struct snd_soc_pcm_runtime *rtd = substream->private_data; 162 struct snd_soc_pcm_runtime *rtd = substream->private_data;
165 struct snd_soc_device *socdev = rtd->socdev; 163 struct snd_soc_codec *codec = rtd->codec;
166 struct snd_soc_codec *codec = socdev->card->codec;
167 struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec); 164 struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
168 int i; 165 int i;
169 u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1); 166 u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1);
@@ -387,8 +384,8 @@ static struct snd_soc_dai_ops wm8523_dai_ops = {
387 .set_fmt = wm8523_set_dai_fmt, 384 .set_fmt = wm8523_set_dai_fmt,
388}; 385};
389 386
390struct snd_soc_dai wm8523_dai = { 387static struct snd_soc_dai_driver wm8523_dai = {
391 .name = "WM8523", 388 .name = "wm8523-hifi",
392 .playback = { 389 .playback = {
393 .stream_name = "Playback", 390 .stream_name = "Playback",
394 .channels_min = 2, /* Mono modes not yet supported */ 391 .channels_min = 2, /* Mono modes not yet supported */
@@ -398,25 +395,17 @@ struct snd_soc_dai wm8523_dai = {
398 }, 395 },
399 .ops = &wm8523_dai_ops, 396 .ops = &wm8523_dai_ops,
400}; 397};
401EXPORT_SYMBOL_GPL(wm8523_dai);
402 398
403#ifdef CONFIG_PM 399#ifdef CONFIG_PM
404static int wm8523_suspend(struct platform_device *pdev, pm_message_t state) 400static int wm8523_suspend(struct snd_soc_codec *codec, pm_message_t state)
405{ 401{
406 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
407 struct snd_soc_codec *codec = socdev->card->codec;
408
409 wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF); 402 wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF);
410 return 0; 403 return 0;
411} 404}
412 405
413static int wm8523_resume(struct platform_device *pdev) 406static int wm8523_resume(struct snd_soc_codec *codec)
414{ 407{
415 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
416 struct snd_soc_codec *codec = socdev->card->codec;
417
418 wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 408 wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
419
420 return 0; 409 return 0;
421} 410}
422#else 411#else
@@ -424,93 +413,21 @@ static int wm8523_resume(struct platform_device *pdev)
424#define wm8523_resume NULL 413#define wm8523_resume NULL
425#endif 414#endif
426 415
427static int wm8523_probe(struct platform_device *pdev) 416static int wm8523_probe(struct snd_soc_codec *codec)
428{
429 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
430 struct snd_soc_codec *codec;
431 int ret = 0;
432
433 if (wm8523_codec == NULL) {
434 dev_err(&pdev->dev, "Codec device not registered\n");
435 return -ENODEV;
436 }
437
438 socdev->card->codec = wm8523_codec;
439 codec = wm8523_codec;
440
441 /* register pcms */
442 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
443 if (ret < 0) {
444 dev_err(codec->dev, "failed to create pcms: %d\n", ret);
445 goto pcm_err;
446 }
447
448 snd_soc_add_controls(codec, wm8523_snd_controls,
449 ARRAY_SIZE(wm8523_snd_controls));
450 wm8523_add_widgets(codec);
451
452 return ret;
453
454pcm_err:
455 return ret;
456}
457
458static int wm8523_remove(struct platform_device *pdev)
459{
460 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
461
462 snd_soc_free_pcms(socdev);
463 snd_soc_dapm_free(socdev);
464
465 return 0;
466}
467
468struct snd_soc_codec_device soc_codec_dev_wm8523 = {
469 .probe = wm8523_probe,
470 .remove = wm8523_remove,
471 .suspend = wm8523_suspend,
472 .resume = wm8523_resume,
473};
474EXPORT_SYMBOL_GPL(soc_codec_dev_wm8523);
475
476static int wm8523_register(struct wm8523_priv *wm8523,
477 enum snd_soc_control_type control)
478{ 417{
479 int ret; 418 struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
480 struct snd_soc_codec *codec = &wm8523->codec; 419 int ret, i;
481 int i;
482
483 if (wm8523_codec) {
484 dev_err(codec->dev, "Another WM8523 is registered\n");
485 ret = -EINVAL;
486 goto err;
487 }
488
489 mutex_init(&codec->mutex);
490 INIT_LIST_HEAD(&codec->dapm_widgets);
491 INIT_LIST_HEAD(&codec->dapm_paths);
492
493 snd_soc_codec_set_drvdata(codec, wm8523);
494 codec->name = "WM8523";
495 codec->owner = THIS_MODULE;
496 codec->bias_level = SND_SOC_BIAS_OFF;
497 codec->set_bias_level = wm8523_set_bias_level;
498 codec->dai = &wm8523_dai;
499 codec->num_dai = 1;
500 codec->reg_cache_size = WM8523_REGISTER_COUNT;
501 codec->reg_cache = &wm8523->reg_cache;
502 codec->volatile_register = wm8523_volatile_register;
503 420
421 codec->hw_write = (hw_write_t)i2c_master_send;
422 codec->control_data = wm8523->control_data;
504 wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0]; 423 wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0];
505 wm8523->rate_constraint.count = 424 wm8523->rate_constraint.count =
506 ARRAY_SIZE(wm8523->rate_constraint_list); 425 ARRAY_SIZE(wm8523->rate_constraint_list);
507 426
508 memcpy(codec->reg_cache, wm8523_reg, sizeof(wm8523_reg)); 427 ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8523->control_type);
509
510 ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
511 if (ret != 0) { 428 if (ret != 0) {
512 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); 429 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
513 goto err; 430 return ret;
514 } 431 }
515 432
516 for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++) 433 for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++)
@@ -520,7 +437,7 @@ static int wm8523_register(struct wm8523_priv *wm8523,
520 wm8523->supplies); 437 wm8523->supplies);
521 if (ret != 0) { 438 if (ret != 0) {
522 dev_err(codec->dev, "Failed to request supplies: %d\n", ret); 439 dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
523 goto err; 440 return ret;
524 } 441 }
525 442
526 ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies), 443 ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies),
@@ -555,8 +472,6 @@ static int wm8523_register(struct wm8523_priv *wm8523,
555 goto err_enable; 472 goto err_enable;
556 } 473 }
557 474
558 wm8523_dai.dev = codec->dev;
559
560 /* Change some default settings - latch VU and enable ZC */ 475 /* Change some default settings - latch VU and enable ZC */
561 wm8523->reg_cache[WM8523_DAC_GAINR] |= WM8523_DACR_VU; 476 wm8523->reg_cache[WM8523_DAC_GAINR] |= WM8523_DACR_VU;
562 wm8523->reg_cache[WM8523_DAC_CTRL3] |= WM8523_ZC; 477 wm8523->reg_cache[WM8523_DAC_CTRL3] |= WM8523_ZC;
@@ -566,69 +481,68 @@ static int wm8523_register(struct wm8523_priv *wm8523,
566 /* Bias level configuration will have done an extra enable */ 481 /* Bias level configuration will have done an extra enable */
567 regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); 482 regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
568 483
569 wm8523_codec = codec; 484 snd_soc_add_controls(codec, wm8523_snd_controls,
570 485 ARRAY_SIZE(wm8523_snd_controls));
571 ret = snd_soc_register_codec(codec); 486 wm8523_add_widgets(codec);
572 if (ret != 0) {
573 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
574 goto err_enable;
575 }
576
577 ret = snd_soc_register_dai(&wm8523_dai);
578 if (ret != 0) {
579 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
580 goto err_codec;
581 }
582 487
583 return 0; 488 return 0;
584 489
585err_codec:
586 snd_soc_unregister_codec(codec);
587err_enable: 490err_enable:
588 regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); 491 regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
589err_get: 492err_get:
590 regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); 493 regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
591err: 494
592 kfree(wm8523);
593 return ret; 495 return ret;
594} 496}
595 497
596static void wm8523_unregister(struct wm8523_priv *wm8523) 498static int wm8523_remove(struct snd_soc_codec *codec)
597{ 499{
598 wm8523_set_bias_level(&wm8523->codec, SND_SOC_BIAS_OFF); 500 struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
501
502 wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF);
599 regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); 503 regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
600 snd_soc_unregister_dai(&wm8523_dai); 504 return 0;
601 snd_soc_unregister_codec(&wm8523->codec);
602 kfree(wm8523);
603 wm8523_codec = NULL;
604} 505}
605 506
507static struct snd_soc_codec_driver soc_codec_dev_wm8523 = {
508 .probe = wm8523_probe,
509 .remove = wm8523_remove,
510 .suspend = wm8523_suspend,
511 .resume = wm8523_resume,
512 .set_bias_level = wm8523_set_bias_level,
513 .reg_cache_size = WM8523_REGISTER_COUNT,
514 .reg_word_size = sizeof(u16),
515 .reg_cache_default = wm8523_reg,
516 .volatile_register = wm8523_volatile_register,
517};
518
606#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 519#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
607static __devinit int wm8523_i2c_probe(struct i2c_client *i2c, 520static __devinit int wm8523_i2c_probe(struct i2c_client *i2c,
608 const struct i2c_device_id *id) 521 const struct i2c_device_id *id)
609{ 522{
610 struct wm8523_priv *wm8523; 523 struct wm8523_priv *wm8523;
611 struct snd_soc_codec *codec; 524 int ret;
612 525
613 wm8523 = kzalloc(sizeof(struct wm8523_priv), GFP_KERNEL); 526 wm8523 = kzalloc(sizeof(struct wm8523_priv), GFP_KERNEL);
614 if (wm8523 == NULL) 527 if (wm8523 == NULL)
615 return -ENOMEM; 528 return -ENOMEM;
616 529
617 codec = &wm8523->codec;
618 codec->hw_write = (hw_write_t)i2c_master_send;
619
620 i2c_set_clientdata(i2c, wm8523); 530 i2c_set_clientdata(i2c, wm8523);
621 codec->control_data = i2c; 531 wm8523->control_data = i2c;
532 wm8523->control_type = SND_SOC_I2C;
622 533
623 codec->dev = &i2c->dev; 534 ret = snd_soc_register_codec(&i2c->dev,
535 &soc_codec_dev_wm8523, &wm8523_dai, 1);
536 if (ret < 0)
537 kfree(wm8523);
538 return ret;
624 539
625 return wm8523_register(wm8523, SND_SOC_I2C);
626} 540}
627 541
628static __devexit int wm8523_i2c_remove(struct i2c_client *client) 542static __devexit int wm8523_i2c_remove(struct i2c_client *client)
629{ 543{
630 struct wm8523_priv *wm8523 = i2c_get_clientdata(client); 544 snd_soc_unregister_codec(&client->dev);
631 wm8523_unregister(wm8523); 545 kfree(i2c_get_clientdata(client));
632 return 0; 546 return 0;
633} 547}
634 548
@@ -640,7 +554,7 @@ MODULE_DEVICE_TABLE(i2c, wm8523_i2c_id);
640 554
641static struct i2c_driver wm8523_i2c_driver = { 555static struct i2c_driver wm8523_i2c_driver = {
642 .driver = { 556 .driver = {
643 .name = "WM8523", 557 .name = "wm8523-codec",
644 .owner = THIS_MODULE, 558 .owner = THIS_MODULE,
645 }, 559 },
646 .probe = wm8523_i2c_probe, 560 .probe = wm8523_i2c_probe,