aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8510.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/wm8510.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/wm8510.c')
-rw-r--r--sound/soc/codecs/wm8510.c290
1 files changed, 98 insertions, 192 deletions
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 0f7bcb61071a..dbfa05d2cb92 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -31,8 +31,6 @@
31 31
32#define WM8510_VERSION "0.6" 32#define WM8510_VERSION "0.6"
33 33
34struct snd_soc_codec_device soc_codec_dev_wm8510;
35
36/* 34/*
37 * wm8510 register cache 35 * wm8510 register cache
38 * We can't read the WM8510 register space when we are 36 * We can't read the WM8510 register space when we are
@@ -61,6 +59,12 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = {
61 59
62#define wm8510_reset(c) snd_soc_write(c, WM8510_RESET, 0) 60#define wm8510_reset(c) snd_soc_write(c, WM8510_RESET, 0)
63 61
62/* codec private data */
63struct wm8510_priv {
64 enum snd_soc_control_type control_type;
65 void *control_data;
66};
67
64static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" }; 68static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" };
65static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; 69static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
66static const char *wm8510_alc[] = { "ALC", "Limiter" }; 70static const char *wm8510_alc[] = { "ALC", "Limiter" };
@@ -403,8 +407,7 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
403 struct snd_soc_dai *dai) 407 struct snd_soc_dai *dai)
404{ 408{
405 struct snd_soc_pcm_runtime *rtd = substream->private_data; 409 struct snd_soc_pcm_runtime *rtd = substream->private_data;
406 struct snd_soc_device *socdev = rtd->socdev; 410 struct snd_soc_codec *codec = rtd->codec;
407 struct snd_soc_codec *codec = socdev->card->codec;
408 u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f; 411 u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f;
409 u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1; 412 u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1;
410 413
@@ -514,8 +517,8 @@ static struct snd_soc_dai_ops wm8510_dai_ops = {
514 .set_pll = wm8510_set_dai_pll, 517 .set_pll = wm8510_set_dai_pll,
515}; 518};
516 519
517struct snd_soc_dai wm8510_dai = { 520static struct snd_soc_dai_driver wm8510_dai = {
518 .name = "WM8510 HiFi", 521 .name = "wm8510-hifi",
519 .playback = { 522 .playback = {
520 .stream_name = "Playback", 523 .stream_name = "Playback",
521 .channels_min = 2, 524 .channels_min = 2,
@@ -531,21 +534,15 @@ struct snd_soc_dai wm8510_dai = {
531 .ops = &wm8510_dai_ops, 534 .ops = &wm8510_dai_ops,
532 .symmetric_rates = 1, 535 .symmetric_rates = 1,
533}; 536};
534EXPORT_SYMBOL_GPL(wm8510_dai);
535 537
536static int wm8510_suspend(struct platform_device *pdev, pm_message_t state) 538static int wm8510_suspend(struct snd_soc_codec *codec, pm_message_t state)
537{ 539{
538 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
539 struct snd_soc_codec *codec = socdev->card->codec;
540
541 wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); 540 wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
542 return 0; 541 return 0;
543} 542}
544 543
545static int wm8510_resume(struct platform_device *pdev) 544static int wm8510_resume(struct snd_soc_codec *codec)
546{ 545{
547 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
548 struct snd_soc_codec *codec = socdev->card->codec;
549 int i; 546 int i;
550 u8 data[2]; 547 u8 data[2];
551 u16 *cache = codec->reg_cache; 548 u16 *cache = codec->reg_cache;
@@ -561,43 +558,22 @@ static int wm8510_resume(struct platform_device *pdev)
561 return 0; 558 return 0;
562} 559}
563 560
564/* 561static int wm8510_probe(struct snd_soc_codec *codec)
565 * initialise the WM8510 driver
566 * register the mixer and dsp interfaces with the kernel
567 */
568static int wm8510_init(struct snd_soc_device *socdev,
569 enum snd_soc_control_type control)
570{ 562{
571 struct snd_soc_codec *codec = socdev->card->codec; 563 struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec);
572 int ret = 0; 564 int ret;
573
574 codec->name = "WM8510";
575 codec->owner = THIS_MODULE;
576 codec->set_bias_level = wm8510_set_bias_level;
577 codec->dai = &wm8510_dai;
578 codec->num_dai = 1;
579 codec->reg_cache_size = ARRAY_SIZE(wm8510_reg);
580 codec->reg_cache = kmemdup(wm8510_reg, sizeof(wm8510_reg), GFP_KERNEL);
581 565
582 if (codec->reg_cache == NULL) 566 pr_info("WM8510 Audio Codec %s", WM8510_VERSION);
583 return -ENOMEM;
584 567
585 ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); 568 codec->control_data = wm8510->control_data;
569 ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8510->control_type);
586 if (ret < 0) { 570 if (ret < 0) {
587 printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n", 571 printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n", ret);
588 ret); 572 return ret;
589 goto err;
590 } 573 }
591 574
592 wm8510_reset(codec); 575 wm8510_reset(codec);
593 576
594 /* register pcms */
595 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
596 if (ret < 0) {
597 printk(KERN_ERR "wm8510: failed to create pcms\n");
598 goto err;
599 }
600
601 /* power on device */ 577 /* power on device */
602 codec->bias_level = SND_SOC_BIAS_OFF; 578 codec->bias_level = SND_SOC_BIAS_OFF;
603 wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 579 wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -606,119 +582,53 @@ static int wm8510_init(struct snd_soc_device *socdev,
606 wm8510_add_widgets(codec); 582 wm8510_add_widgets(codec);
607 583
608 return ret; 584 return ret;
609
610err:
611 kfree(codec->reg_cache);
612 return ret;
613} 585}
614 586
615static struct snd_soc_device *wm8510_socdev; 587/* power down chip */
616 588static int wm8510_remove(struct snd_soc_codec *codec)
617#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
618
619/*
620 * WM8510 2 wire address is 0x1a
621 */
622
623static int wm8510_i2c_probe(struct i2c_client *i2c,
624 const struct i2c_device_id *id)
625{ 589{
626 struct snd_soc_device *socdev = wm8510_socdev; 590 struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec);
627 struct snd_soc_codec *codec = socdev->card->codec;
628 int ret;
629
630 i2c_set_clientdata(i2c, codec);
631 codec->control_data = i2c;
632
633 ret = wm8510_init(socdev, SND_SOC_I2C);
634 if (ret < 0)
635 pr_err("failed to initialise WM8510\n");
636
637 return ret;
638}
639 591
640static int wm8510_i2c_remove(struct i2c_client *client) 592 wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
641{ 593 kfree(wm8510);
642 struct snd_soc_codec *codec = i2c_get_clientdata(client);
643 kfree(codec->reg_cache);
644 return 0; 594 return 0;
645} 595}
646 596
647static const struct i2c_device_id wm8510_i2c_id[] = { 597static struct snd_soc_codec_driver soc_codec_dev_wm8510 = {
648 { "wm8510", 0 }, 598 .probe = wm8510_probe,
649 { } 599 .remove = wm8510_remove,
650}; 600 .suspend = wm8510_suspend,
651MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id); 601 .resume = wm8510_resume,
652 602 .set_bias_level = wm8510_set_bias_level,
653static struct i2c_driver wm8510_i2c_driver = { 603 .reg_cache_size = ARRAY_SIZE(wm8510_reg),
654 .driver = { 604 .reg_word_size = sizeof(u16),
655 .name = "WM8510 I2C Codec", 605 .reg_cache_default =wm8510_reg,
656 .owner = THIS_MODULE,
657 },
658 .probe = wm8510_i2c_probe,
659 .remove = wm8510_i2c_remove,
660 .id_table = wm8510_i2c_id,
661}; 606};
662 607
663static int wm8510_add_i2c_device(struct platform_device *pdev,
664 const struct wm8510_setup_data *setup)
665{
666 struct i2c_board_info info;
667 struct i2c_adapter *adapter;
668 struct i2c_client *client;
669 int ret;
670
671 ret = i2c_add_driver(&wm8510_i2c_driver);
672 if (ret != 0) {
673 dev_err(&pdev->dev, "can't add i2c driver\n");
674 return ret;
675 }
676
677 memset(&info, 0, sizeof(struct i2c_board_info));
678 info.addr = setup->i2c_address;
679 strlcpy(info.type, "wm8510", I2C_NAME_SIZE);
680
681 adapter = i2c_get_adapter(setup->i2c_bus);
682 if (!adapter) {
683 dev_err(&pdev->dev, "can't get i2c adapter %d\n",
684 setup->i2c_bus);
685 goto err_driver;
686 }
687
688 client = i2c_new_device(adapter, &info);
689 i2c_put_adapter(adapter);
690 if (!client) {
691 dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
692 (unsigned int)info.addr);
693 goto err_driver;
694 }
695
696 return 0;
697
698err_driver:
699 i2c_del_driver(&wm8510_i2c_driver);
700 return -ENODEV;
701}
702#endif
703
704#if defined(CONFIG_SPI_MASTER) 608#if defined(CONFIG_SPI_MASTER)
705static int __devinit wm8510_spi_probe(struct spi_device *spi) 609static int __devinit wm8510_spi_probe(struct spi_device *spi)
706{ 610{
707 struct snd_soc_device *socdev = wm8510_socdev; 611 struct wm8510_priv *wm8510;
708 struct snd_soc_codec *codec = socdev->card->codec;
709 int ret; 612 int ret;
710 613
711 codec->control_data = spi; 614 wm8510 = kzalloc(sizeof(struct wm8510_priv), GFP_KERNEL);
615 if (wm8510 == NULL)
616 return -ENOMEM;
617
618 wm8510->control_data = spi;
619 wm8510->control_type = SND_SOC_SPI;
620 spi_set_drvdata(spi, wm8510);
712 621
713 ret = wm8510_init(socdev, SND_SOC_SPI); 622 ret = snd_soc_register_codec(&spi->dev,
623 &soc_codec_dev_wm8510, &wm8510_dai, 1);
714 if (ret < 0) 624 if (ret < 0)
715 dev_err(&spi->dev, "failed to initialise WM8510\n"); 625 kfree(wm8510);
716
717 return ret; 626 return ret;
718} 627}
719 628
720static int __devexit wm8510_spi_remove(struct spi_device *spi) 629static int __devexit wm8510_spi_remove(struct spi_device *spi)
721{ 630{
631 snd_soc_unregister_codec(&spi->dev);
722 return 0; 632 return 0;
723} 633}
724 634
@@ -733,84 +643,80 @@ static struct spi_driver wm8510_spi_driver = {
733}; 643};
734#endif /* CONFIG_SPI_MASTER */ 644#endif /* CONFIG_SPI_MASTER */
735 645
736static int wm8510_probe(struct platform_device *pdev) 646#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
647static __devinit int wm8510_i2c_probe(struct i2c_client *i2c,
648 const struct i2c_device_id *id)
737{ 649{
738 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 650 struct wm8510_priv *wm8510;
739 struct wm8510_setup_data *setup; 651 int ret;
740 struct snd_soc_codec *codec;
741 int ret = 0;
742
743 pr_info("WM8510 Audio Codec %s", WM8510_VERSION);
744 652
745 setup = socdev->codec_data; 653 wm8510 = kzalloc(sizeof(struct wm8510_priv), GFP_KERNEL);
746 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); 654 if (wm8510 == NULL)
747 if (codec == NULL)
748 return -ENOMEM; 655 return -ENOMEM;
749 656
750 socdev->card->codec = codec; 657 i2c_set_clientdata(i2c, wm8510);
751 mutex_init(&codec->mutex); 658 wm8510->control_data = i2c;
752 INIT_LIST_HEAD(&codec->dapm_widgets); 659 wm8510->control_type = SND_SOC_I2C;
753 INIT_LIST_HEAD(&codec->dapm_paths);
754 660
755 wm8510_socdev = socdev; 661 ret = snd_soc_register_codec(&i2c->dev,
756#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 662 &soc_codec_dev_wm8510, &wm8510_dai, 1);
757 if (setup->i2c_address) { 663 if (ret < 0)
758 ret = wm8510_add_i2c_device(pdev, setup); 664 kfree(wm8510);
759 }
760#endif
761#if defined(CONFIG_SPI_MASTER)
762 if (setup->spi) {
763 ret = spi_register_driver(&wm8510_spi_driver);
764 if (ret != 0)
765 printk(KERN_ERR "can't add spi driver");
766 }
767#endif
768
769 if (ret != 0)
770 kfree(codec);
771 return ret; 665 return ret;
772} 666}
773 667
774/* power down chip */ 668static __devexit int wm8510_i2c_remove(struct i2c_client *client)
775static int wm8510_remove(struct platform_device *pdev)
776{ 669{
777 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 670 snd_soc_unregister_codec(&client->dev);
778 struct snd_soc_codec *codec = socdev->card->codec;
779
780 if (codec->control_data)
781 wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
782
783 snd_soc_free_pcms(socdev);
784 snd_soc_dapm_free(socdev);
785#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
786 i2c_unregister_device(codec->control_data);
787 i2c_del_driver(&wm8510_i2c_driver);
788#endif
789#if defined(CONFIG_SPI_MASTER)
790 spi_unregister_driver(&wm8510_spi_driver);
791#endif
792 kfree(codec);
793
794 return 0; 671 return 0;
795} 672}
796 673
797struct snd_soc_codec_device soc_codec_dev_wm8510 = { 674static const struct i2c_device_id wm8510_i2c_id[] = {
798 .probe = wm8510_probe, 675 { "wm8510", 0 },
799 .remove = wm8510_remove, 676 { }
800 .suspend = wm8510_suspend, 677};
801 .resume = wm8510_resume, 678MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id);
679
680static struct i2c_driver wm8510_i2c_driver = {
681 .driver = {
682 .name = "wm8510-codec",
683 .owner = THIS_MODULE,
684 },
685 .probe = wm8510_i2c_probe,
686 .remove = __devexit_p(wm8510_i2c_remove),
687 .id_table = wm8510_i2c_id,
802}; 688};
803EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510); 689#endif
804 690
805static int __init wm8510_modinit(void) 691static int __init wm8510_modinit(void)
806{ 692{
807 return snd_soc_register_dai(&wm8510_dai); 693 int ret = 0;
694#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
695 ret = i2c_add_driver(&wm8510_i2c_driver);
696 if (ret != 0) {
697 printk(KERN_ERR "Failed to register WM8510 I2C driver: %d\n",
698 ret);
699 }
700#endif
701#if defined(CONFIG_SPI_MASTER)
702 ret = spi_register_driver(&wm8510_spi_driver);
703 if (ret != 0) {
704 printk(KERN_ERR "Failed to register WM8510 SPI driver: %d\n",
705 ret);
706 }
707#endif
708 return ret;
808} 709}
809module_init(wm8510_modinit); 710module_init(wm8510_modinit);
810 711
811static void __exit wm8510_exit(void) 712static void __exit wm8510_exit(void)
812{ 713{
813 snd_soc_unregister_dai(&wm8510_dai); 714#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
715 i2c_del_driver(&wm8510_i2c_driver);
716#endif
717#if defined(CONFIG_SPI_MASTER)
718 spi_unregister_driver(&wm8510_spi_driver);
719#endif
814} 720}
815module_exit(wm8510_exit); 721module_exit(wm8510_exit);
816 722