aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8940.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/wm8940.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/wm8940.c')
-rw-r--r--sound/soc/codecs/wm8940.c199
1 files changed, 56 insertions, 143 deletions
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index f0c11138e610..d28bf0dfdb1d 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -44,7 +44,8 @@
44struct wm8940_priv { 44struct wm8940_priv {
45 unsigned int sysclk; 45 unsigned int sysclk;
46 u16 reg_cache[WM8940_CACHEREGNUM]; 46 u16 reg_cache[WM8940_CACHEREGNUM];
47 struct snd_soc_codec codec; 47 enum snd_soc_control_type control_type;
48 void *control_data;
48}; 49};
49 50
50static u16 wm8940_reg_defaults[] = { 51static u16 wm8940_reg_defaults[] = {
@@ -365,8 +366,7 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream,
365 struct snd_soc_dai *dai) 366 struct snd_soc_dai *dai)
366{ 367{
367 struct snd_soc_pcm_runtime *rtd = substream->private_data; 368 struct snd_soc_pcm_runtime *rtd = substream->private_data;
368 struct snd_soc_device *socdev = rtd->socdev; 369 struct snd_soc_codec *codec = rtd->codec;
369 struct snd_soc_codec *codec = socdev->card->codec;
370 u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F; 370 u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F;
371 u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1; 371 u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1;
372 u16 companding = snd_soc_read(codec, 372 u16 companding = snd_soc_read(codec,
@@ -636,8 +636,8 @@ static struct snd_soc_dai_ops wm8940_dai_ops = {
636 .set_pll = wm8940_set_dai_pll, 636 .set_pll = wm8940_set_dai_pll,
637}; 637};
638 638
639struct snd_soc_dai wm8940_dai = { 639static struct snd_soc_dai_driver wm8940_dai = {
640 .name = "WM8940", 640 .name = "wm8940-hifi",
641 .playback = { 641 .playback = {
642 .stream_name = "Playback", 642 .stream_name = "Playback",
643 .channels_min = 1, 643 .channels_min = 1,
@@ -655,20 +655,14 @@ struct snd_soc_dai wm8940_dai = {
655 .ops = &wm8940_dai_ops, 655 .ops = &wm8940_dai_ops,
656 .symmetric_rates = 1, 656 .symmetric_rates = 1,
657}; 657};
658EXPORT_SYMBOL_GPL(wm8940_dai);
659 658
660static int wm8940_suspend(struct platform_device *pdev, pm_message_t state) 659static int wm8940_suspend(struct snd_soc_codec *codec, pm_message_t state)
661{ 660{
662 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
663 struct snd_soc_codec *codec = socdev->card->codec;
664
665 return wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF); 661 return wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF);
666} 662}
667 663
668static int wm8940_resume(struct platform_device *pdev) 664static int wm8940_resume(struct snd_soc_codec *codec)
669{ 665{
670 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
671 struct snd_soc_codec *codec = socdev->card->codec;
672 int i; 666 int i;
673 int ret; 667 int ret;
674 u8 data[3]; 668 u8 data[3];
@@ -697,108 +691,26 @@ error_ret:
697 return ret; 691 return ret;
698} 692}
699 693
700static struct snd_soc_codec *wm8940_codec; 694static int wm8940_probe(struct snd_soc_codec *codec)
701
702static int wm8940_probe(struct platform_device *pdev)
703{
704 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
705 struct snd_soc_codec *codec;
706
707 int ret = 0;
708
709 if (wm8940_codec == NULL) {
710 dev_err(&pdev->dev, "Codec device not registered\n");
711 return -ENODEV;
712 }
713
714 socdev->card->codec = wm8940_codec;
715 codec = wm8940_codec;
716
717 mutex_init(&codec->mutex);
718 /* register pcms */
719 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
720 if (ret < 0) {
721 dev_err(codec->dev, "failed to create pcms: %d\n", ret);
722 goto pcm_err;
723 }
724
725 ret = snd_soc_add_controls(codec, wm8940_snd_controls,
726 ARRAY_SIZE(wm8940_snd_controls));
727 if (ret)
728 goto error_free_pcms;
729 ret = wm8940_add_widgets(codec);
730 if (ret)
731 goto error_free_pcms;
732
733 return ret;
734
735error_free_pcms:
736 snd_soc_free_pcms(socdev);
737 snd_soc_dapm_free(socdev);
738pcm_err:
739 return ret;
740}
741
742static int wm8940_remove(struct platform_device *pdev)
743{
744 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
745
746 snd_soc_free_pcms(socdev);
747 snd_soc_dapm_free(socdev);
748
749 return 0;
750}
751
752struct snd_soc_codec_device soc_codec_dev_wm8940 = {
753 .probe = wm8940_probe,
754 .remove = wm8940_remove,
755 .suspend = wm8940_suspend,
756 .resume = wm8940_resume,
757};
758EXPORT_SYMBOL_GPL(soc_codec_dev_wm8940);
759
760static int wm8940_register(struct wm8940_priv *wm8940,
761 enum snd_soc_control_type control)
762{ 695{
763 struct wm8940_setup_data *pdata = wm8940->codec.dev->platform_data; 696 struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);
764 struct snd_soc_codec *codec = &wm8940->codec; 697 struct wm8940_setup_data *pdata = codec->dev->platform_data;
765 int ret; 698 int ret;
766 u16 reg; 699 u16 reg;
767 if (wm8940_codec) {
768 dev_err(codec->dev, "Another WM8940 is registered\n");
769 return -EINVAL;
770 }
771
772 INIT_LIST_HEAD(&codec->dapm_widgets);
773 INIT_LIST_HEAD(&codec->dapm_paths);
774
775 snd_soc_codec_set_drvdata(codec, wm8940);
776 codec->name = "WM8940";
777 codec->owner = THIS_MODULE;
778 codec->bias_level = SND_SOC_BIAS_OFF;
779 codec->set_bias_level = wm8940_set_bias_level;
780 codec->dai = &wm8940_dai;
781 codec->num_dai = 1;
782 codec->reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults);
783 codec->reg_cache = &wm8940->reg_cache;
784 700
785 ret = snd_soc_codec_set_cache_io(codec, 8, 16, control); 701 codec->control_data = wm8940->control_data;
702 ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8940->control_type);
786 if (ret < 0) { 703 if (ret < 0) {
787 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); 704 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
788 return ret; 705 return ret;
789 } 706 }
790 707
791 memcpy(codec->reg_cache, wm8940_reg_defaults,
792 sizeof(wm8940_reg_defaults));
793
794 ret = wm8940_reset(codec); 708 ret = wm8940_reset(codec);
795 if (ret < 0) { 709 if (ret < 0) {
796 dev_err(codec->dev, "Failed to issue reset\n"); 710 dev_err(codec->dev, "Failed to issue reset\n");
797 return ret; 711 return ret;
798 } 712 }
799 713
800 wm8940_dai.dev = codec->dev;
801
802 wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 714 wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
803 715
804 ret = snd_soc_write(codec, WM8940_POWER1, 0x180); 716 ret = snd_soc_write(codec, WM8940_POWER1, 0x180);
@@ -814,64 +726,60 @@ static int wm8940_register(struct wm8940_priv *wm8940,
814 return ret; 726 return ret;
815 } 727 }
816 728
817 729 ret = snd_soc_add_controls(codec, wm8940_snd_controls,
818 wm8940_codec = codec; 730 ARRAY_SIZE(wm8940_snd_controls));
819 731 if (ret)
820 ret = snd_soc_register_codec(codec);
821 if (ret) {
822 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
823 return ret; 732 return ret;
824 } 733 ret = wm8940_add_widgets(codec);
825 734 if (ret)
826 ret = snd_soc_register_dai(&wm8940_dai);
827 if (ret) {
828 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
829 snd_soc_unregister_codec(codec);
830 return ret; 735 return ret;
831 }
832 736
833 return 0; 737 return ret;
738;
834} 739}
835 740
836static void wm8940_unregister(struct wm8940_priv *wm8940) 741static int wm8940_remove(struct snd_soc_codec *codec)
837{ 742{
838 wm8940_set_bias_level(&wm8940->codec, SND_SOC_BIAS_OFF); 743 wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF);
839 snd_soc_unregister_dai(&wm8940_dai); 744 return 0;
840 snd_soc_unregister_codec(&wm8940->codec);
841 kfree(wm8940);
842 wm8940_codec = NULL;
843} 745}
844 746
845static int wm8940_i2c_probe(struct i2c_client *i2c, 747static struct snd_soc_codec_driver soc_codec_dev_wm8940 = {
846 const struct i2c_device_id *id) 748 .probe = wm8940_probe,
749 .remove = wm8940_remove,
750 .suspend = wm8940_suspend,
751 .resume = wm8940_resume,
752 .set_bias_level = wm8940_set_bias_level,
753 .reg_cache_size = sizeof(wm8940_reg_defaults),
754 .reg_word_size = sizeof(u16),
755 .reg_cache_default = wm8940_reg_defaults,
756};
757
758#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
759static __devinit int wm8940_i2c_probe(struct i2c_client *i2c,
760 const struct i2c_device_id *id)
847{ 761{
848 int ret;
849 struct wm8940_priv *wm8940; 762 struct wm8940_priv *wm8940;
850 struct snd_soc_codec *codec; 763 int ret;
851 764
852 wm8940 = kzalloc(sizeof *wm8940, GFP_KERNEL); 765 wm8940 = kzalloc(sizeof(struct wm8940_priv), GFP_KERNEL);
853 if (wm8940 == NULL) 766 if (wm8940 == NULL)
854 return -ENOMEM; 767 return -ENOMEM;
855 768
856 codec = &wm8940->codec;
857 codec->hw_write = (hw_write_t)i2c_master_send;
858 i2c_set_clientdata(i2c, wm8940); 769 i2c_set_clientdata(i2c, wm8940);
859 codec->control_data = i2c; 770 wm8940->control_data = i2c;
860 codec->dev = &i2c->dev;
861 771
862 ret = wm8940_register(wm8940, SND_SOC_I2C); 772 ret = snd_soc_register_codec(&i2c->dev,
773 &soc_codec_dev_wm8940, &wm8940_dai, 1);
863 if (ret < 0) 774 if (ret < 0)
864 kfree(wm8940); 775 kfree(wm8940);
865
866 return ret; 776 return ret;
867} 777}
868 778
869static int __devexit wm8940_i2c_remove(struct i2c_client *client) 779static __devexit int wm8940_i2c_remove(struct i2c_client *client)
870{ 780{
871 struct wm8940_priv *wm8940 = i2c_get_clientdata(client); 781 snd_soc_unregister_codec(&client->dev);
872 782 kfree(i2c_get_clientdata(client));
873 wm8940_unregister(wm8940);
874
875 return 0; 783 return 0;
876} 784}
877 785
@@ -883,29 +791,34 @@ MODULE_DEVICE_TABLE(i2c, wm8940_i2c_id);
883 791
884static struct i2c_driver wm8940_i2c_driver = { 792static struct i2c_driver wm8940_i2c_driver = {
885 .driver = { 793 .driver = {
886 .name = "WM8940 I2C Codec", 794 .name = "wm8940-codec",
887 .owner = THIS_MODULE, 795 .owner = THIS_MODULE,
888 }, 796 },
889 .probe = wm8940_i2c_probe, 797 .probe = wm8940_i2c_probe,
890 .remove = __devexit_p(wm8940_i2c_remove), 798 .remove = __devexit_p(wm8940_i2c_remove),
891 .id_table = wm8940_i2c_id, 799 .id_table = wm8940_i2c_id,
892}; 800};
801#endif
893 802
894static int __init wm8940_modinit(void) 803static int __init wm8940_modinit(void)
895{ 804{
896 int ret; 805 int ret = 0;
897 806#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
898 ret = i2c_add_driver(&wm8940_i2c_driver); 807 ret = i2c_add_driver(&wm8940_i2c_driver);
899 if (ret) 808 if (ret != 0) {
900 printk(KERN_ERR "Failed to register WM8940 I2C driver: %d\n", 809 printk(KERN_ERR "Failed to register wm8940 I2C driver: %d\n",
901 ret); 810 ret);
811 }
812#endif
902 return ret; 813 return ret;
903} 814}
904module_init(wm8940_modinit); 815module_init(wm8940_modinit);
905 816
906static void __exit wm8940_exit(void) 817static void __exit wm8940_exit(void)
907{ 818{
819#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
908 i2c_del_driver(&wm8940_i2c_driver); 820 i2c_del_driver(&wm8940_i2c_driver);
821#endif
909} 822}
910module_exit(wm8940_exit); 823module_exit(wm8940_exit);
911 824