aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8971.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/wm8971.c')
-rw-r--r--sound/soc/codecs/wm8971.c250
1 files changed, 68 insertions, 182 deletions
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index a99620f335d2..ad2692afbb31 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -38,6 +38,8 @@ static struct workqueue_struct *wm8971_workq = NULL;
38 38
39/* codec private data */ 39/* codec private data */
40struct wm8971_priv { 40struct wm8971_priv {
41 enum snd_soc_control_type control_type;
42 void *control_data;
41 unsigned int sysclk; 43 unsigned int sysclk;
42}; 44};
43 45
@@ -492,8 +494,7 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
492 struct snd_soc_dai *dai) 494 struct snd_soc_dai *dai)
493{ 495{
494 struct snd_soc_pcm_runtime *rtd = substream->private_data; 496 struct snd_soc_pcm_runtime *rtd = substream->private_data;
495 struct snd_soc_device *socdev = rtd->socdev; 497 struct snd_soc_codec *codec = rtd->codec;
496 struct snd_soc_codec *codec = socdev->card->codec;
497 struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec); 498 struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
498 u16 iface = snd_soc_read(codec, WM8971_IFACE) & 0x1f3; 499 u16 iface = snd_soc_read(codec, WM8971_IFACE) & 0x1f3;
499 u16 srate = snd_soc_read(codec, WM8971_SRATE) & 0x1c0; 500 u16 srate = snd_soc_read(codec, WM8971_SRATE) & 0x1c0;
@@ -573,8 +574,8 @@ static struct snd_soc_dai_ops wm8971_dai_ops = {
573 .set_sysclk = wm8971_set_dai_sysclk, 574 .set_sysclk = wm8971_set_dai_sysclk,
574}; 575};
575 576
576struct snd_soc_dai wm8971_dai = { 577static struct snd_soc_dai_driver wm8971_dai = {
577 .name = "WM8971", 578 .name = "wm8971-hifi",
578 .playback = { 579 .playback = {
579 .stream_name = "Playback", 580 .stream_name = "Playback",
580 .channels_min = 1, 581 .channels_min = 1,
@@ -589,7 +590,6 @@ struct snd_soc_dai wm8971_dai = {
589 .formats = WM8971_FORMATS,}, 590 .formats = WM8971_FORMATS,},
590 .ops = &wm8971_dai_ops, 591 .ops = &wm8971_dai_ops,
591}; 592};
592EXPORT_SYMBOL_GPL(wm8971_dai);
593 593
594static void wm8971_work(struct work_struct *work) 594static void wm8971_work(struct work_struct *work)
595{ 595{
@@ -598,19 +598,14 @@ static void wm8971_work(struct work_struct *work)
598 wm8971_set_bias_level(codec, codec->bias_level); 598 wm8971_set_bias_level(codec, codec->bias_level);
599} 599}
600 600
601static int wm8971_suspend(struct platform_device *pdev, pm_message_t state) 601static int wm8971_suspend(struct snd_soc_codec *codec, pm_message_t state)
602{ 602{
603 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
604 struct snd_soc_codec *codec = socdev->card->codec;
605
606 wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF); 603 wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
607 return 0; 604 return 0;
608} 605}
609 606
610static int wm8971_resume(struct platform_device *pdev) 607static int wm8971_resume(struct snd_soc_codec *codec)
611{ 608{
612 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
613 struct snd_soc_codec *codec = socdev->card->codec;
614 int i; 609 int i;
615 u8 data[2]; 610 u8 data[2];
616 u16 *cache = codec->reg_cache; 611 u16 *cache = codec->reg_cache;
@@ -639,37 +634,27 @@ static int wm8971_resume(struct platform_device *pdev)
639 return 0; 634 return 0;
640} 635}
641 636
642static int wm8971_init(struct snd_soc_device *socdev, 637static int wm8971_probe(struct snd_soc_codec *codec)
643 enum snd_soc_control_type control)
644{ 638{
645 struct snd_soc_codec *codec = socdev->card->codec; 639 struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
646 int reg, ret = 0; 640 int ret = 0;
647 641 u16 reg;
648 codec->name = "WM8971"; 642
649 codec->owner = THIS_MODULE; 643 pr_info("WM8971 Audio Codec %s", WM8971_VERSION);
650 codec->set_bias_level = wm8971_set_bias_level;
651 codec->dai = &wm8971_dai;
652 codec->reg_cache_size = ARRAY_SIZE(wm8971_reg);
653 codec->num_dai = 1;
654 codec->reg_cache = kmemdup(wm8971_reg, sizeof(wm8971_reg), GFP_KERNEL);
655
656 if (codec->reg_cache == NULL)
657 return -ENOMEM;
658 644
659 ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); 645 codec->control_data = wm8971->control_data;
646 ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8971->control_type);
660 if (ret < 0) { 647 if (ret < 0) {
661 printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret); 648 printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret);
662 goto err; 649 return ret;
663 } 650 }
664 651
665 wm8971_reset(codec); 652 INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work);
653 wm8971_workq = create_workqueue("wm8971");
654 if (wm8971_workq == NULL)
655 return -ENOMEM;
666 656
667 /* register pcms */ 657 wm8971_reset(codec);
668 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
669 if (ret < 0) {
670 printk(KERN_ERR "wm8971: failed to create pcms\n");
671 goto err;
672 }
673 658
674 /* charge output caps - set vmid to 5k for quick power up */ 659 /* charge output caps - set vmid to 5k for quick power up */
675 reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e; 660 reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
@@ -704,40 +689,55 @@ static int wm8971_init(struct snd_soc_device *socdev,
704 wm8971_add_widgets(codec); 689 wm8971_add_widgets(codec);
705 690
706 return ret; 691 return ret;
707
708err:
709 kfree(codec->reg_cache);
710 return ret;
711} 692}
712 693
713/* If the i2c layer weren't so broken, we could pass this kind of data
714 around */
715static struct snd_soc_device *wm8971_socdev;
716 694
717#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) 695/* power down chip */
696static int wm8971_remove(struct snd_soc_codec *codec)
697{
698 wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
699
700 if (wm8971_workq)
701 destroy_workqueue(wm8971_workq);
702 return 0;
703}
704
705static struct snd_soc_codec_driver soc_codec_dev_wm8971 = {
706 .probe = wm8971_probe,
707 .remove = wm8971_remove,
708 .suspend = wm8971_suspend,
709 .resume = wm8971_resume,
710 .set_bias_level = wm8971_set_bias_level,
711 .reg_cache_size = ARRAY_SIZE(wm8971_reg),
712 .reg_word_size = sizeof(u16),
713 .reg_cache_default = wm8971_reg,
714};
718 715
719static int wm8971_i2c_probe(struct i2c_client *i2c, 716#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
720 const struct i2c_device_id *id) 717static __devinit int wm8971_i2c_probe(struct i2c_client *i2c,
718 const struct i2c_device_id *id)
721{ 719{
722 struct snd_soc_device *socdev = wm8971_socdev; 720 struct wm8971_priv *wm8971;
723 struct snd_soc_codec *codec = socdev->card->codec;
724 int ret; 721 int ret;
725 722
726 i2c_set_clientdata(i2c, codec); 723 wm8971 = kzalloc(sizeof(struct wm8971_priv), GFP_KERNEL);
724 if (wm8971 == NULL)
725 return -ENOMEM;
727 726
728 codec->control_data = i2c; 727 i2c_set_clientdata(i2c, wm8971);
728 wm8971->control_data = i2c;
729 729
730 ret = wm8971_init(socdev, SND_SOC_I2C); 730 ret = snd_soc_register_codec(&i2c->dev,
731 &soc_codec_dev_wm8971, &wm8971_dai, 1);
731 if (ret < 0) 732 if (ret < 0)
732 pr_err("failed to initialise WM8971\n"); 733 kfree(wm8971);
733
734 return ret; 734 return ret;
735} 735}
736 736
737static int wm8971_i2c_remove(struct i2c_client *client) 737static __devexit int wm8971_i2c_remove(struct i2c_client *client)
738{ 738{
739 struct snd_soc_codec *codec = i2c_get_clientdata(client); 739 snd_soc_unregister_codec(&client->dev);
740 kfree(codec->reg_cache); 740 kfree(i2c_get_clientdata(client));
741 return 0; 741 return 0;
742} 742}
743 743
@@ -749,148 +749,34 @@ MODULE_DEVICE_TABLE(i2c, wm8971_i2c_id);
749 749
750static struct i2c_driver wm8971_i2c_driver = { 750static struct i2c_driver wm8971_i2c_driver = {
751 .driver = { 751 .driver = {
752 .name = "WM8971 I2C Codec", 752 .name = "wm8971-codec",
753 .owner = THIS_MODULE, 753 .owner = THIS_MODULE,
754 }, 754 },
755 .probe = wm8971_i2c_probe, 755 .probe = wm8971_i2c_probe,
756 .remove = wm8971_i2c_remove, 756 .remove = __devexit_p(wm8971_i2c_remove),
757 .id_table = wm8971_i2c_id, 757 .id_table = wm8971_i2c_id,
758}; 758};
759
760static int wm8971_add_i2c_device(struct platform_device *pdev,
761 const struct wm8971_setup_data *setup)
762{
763 struct i2c_board_info info;
764 struct i2c_adapter *adapter;
765 struct i2c_client *client;
766 int ret;
767
768 ret = i2c_add_driver(&wm8971_i2c_driver);
769 if (ret != 0) {
770 dev_err(&pdev->dev, "can't add i2c driver\n");
771 return ret;
772 }
773
774 memset(&info, 0, sizeof(struct i2c_board_info));
775 info.addr = setup->i2c_address;
776 strlcpy(info.type, "wm8971", I2C_NAME_SIZE);
777
778 adapter = i2c_get_adapter(setup->i2c_bus);
779 if (!adapter) {
780 dev_err(&pdev->dev, "can't get i2c adapter %d\n",
781 setup->i2c_bus);
782 goto err_driver;
783 }
784
785 client = i2c_new_device(adapter, &info);
786 i2c_put_adapter(adapter);
787 if (!client) {
788 dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
789 (unsigned int)info.addr);
790 goto err_driver;
791 }
792
793 return 0;
794
795err_driver:
796 i2c_del_driver(&wm8971_i2c_driver);
797 return -ENODEV;
798}
799
800#endif 759#endif
801 760
802static int wm8971_probe(struct platform_device *pdev) 761static int __init wm8971_modinit(void)
803{ 762{
804 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
805 struct wm8971_setup_data *setup;
806 struct snd_soc_codec *codec;
807 struct wm8971_priv *wm8971;
808 int ret = 0; 763 int ret = 0;
809 764#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
810 pr_info("WM8971 Audio Codec %s", WM8971_VERSION); 765 ret = i2c_add_driver(&wm8971_i2c_driver);
811
812 setup = socdev->codec_data;
813 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
814 if (codec == NULL)
815 return -ENOMEM;
816
817 wm8971 = kzalloc(sizeof(struct wm8971_priv), GFP_KERNEL);
818 if (wm8971 == NULL) {
819 kfree(codec);
820 return -ENOMEM;
821 }
822
823 snd_soc_codec_set_drvdata(codec, wm8971);
824 socdev->card->codec = codec;
825 mutex_init(&codec->mutex);
826 INIT_LIST_HEAD(&codec->dapm_widgets);
827 INIT_LIST_HEAD(&codec->dapm_paths);
828 wm8971_socdev = socdev;
829
830 INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work);
831 wm8971_workq = create_workqueue("wm8971");
832 if (wm8971_workq == NULL) {
833 kfree(snd_soc_codec_get_drvdata(codec));
834 kfree(codec);
835 return -ENOMEM;
836 }
837
838#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
839 if (setup->i2c_address) {
840 ret = wm8971_add_i2c_device(pdev, setup);
841 }
842#endif
843 /* Add other interfaces here */
844
845 if (ret != 0) { 766 if (ret != 0) {
846 destroy_workqueue(wm8971_workq); 767 printk(KERN_ERR "Failed to register WM8971 I2C driver: %d\n",
847 kfree(snd_soc_codec_get_drvdata(codec)); 768 ret);
848 kfree(codec);
849 } 769 }
850
851 return ret;
852}
853
854/* power down chip */
855static int wm8971_remove(struct platform_device *pdev)
856{
857 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
858 struct snd_soc_codec *codec = socdev->card->codec;
859
860 if (codec->control_data)
861 wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
862 if (wm8971_workq)
863 destroy_workqueue(wm8971_workq);
864 snd_soc_free_pcms(socdev);
865 snd_soc_dapm_free(socdev);
866#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
867 i2c_unregister_device(codec->control_data);
868 i2c_del_driver(&wm8971_i2c_driver);
869#endif 770#endif
870 kfree(snd_soc_codec_get_drvdata(codec)); 771 return ret;
871 kfree(codec);
872
873 return 0;
874}
875
876struct snd_soc_codec_device soc_codec_dev_wm8971 = {
877 .probe = wm8971_probe,
878 .remove = wm8971_remove,
879 .suspend = wm8971_suspend,
880 .resume = wm8971_resume,
881};
882
883EXPORT_SYMBOL_GPL(soc_codec_dev_wm8971);
884
885static int __init wm8971_modinit(void)
886{
887 return snd_soc_register_dai(&wm8971_dai);
888} 772}
889module_init(wm8971_modinit); 773module_init(wm8971_modinit);
890 774
891static void __exit wm8971_exit(void) 775static void __exit wm8971_exit(void)
892{ 776{
893 snd_soc_unregister_dai(&wm8971_dai); 777#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
778 i2c_del_driver(&wm8971_i2c_driver);
779#endif
894} 780}
895module_exit(wm8971_exit); 781module_exit(wm8971_exit);
896 782