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.c247
1 files changed, 63 insertions, 184 deletions
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index a99620f335d2..63f6dbf5d070 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -30,14 +30,13 @@
30 30
31#include "wm8971.h" 31#include "wm8971.h"
32 32
33#define WM8971_VERSION "0.9"
34
35#define WM8971_REG_COUNT 43 33#define WM8971_REG_COUNT 43
36 34
37static struct workqueue_struct *wm8971_workq = NULL; 35static struct workqueue_struct *wm8971_workq = NULL;
38 36
39/* codec private data */ 37/* codec private data */
40struct wm8971_priv { 38struct wm8971_priv {
39 enum snd_soc_control_type control_type;
41 unsigned int sysclk; 40 unsigned int sysclk;
42}; 41};
43 42
@@ -492,8 +491,7 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
492 struct snd_soc_dai *dai) 491 struct snd_soc_dai *dai)
493{ 492{
494 struct snd_soc_pcm_runtime *rtd = substream->private_data; 493 struct snd_soc_pcm_runtime *rtd = substream->private_data;
495 struct snd_soc_device *socdev = rtd->socdev; 494 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); 495 struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
498 u16 iface = snd_soc_read(codec, WM8971_IFACE) & 0x1f3; 496 u16 iface = snd_soc_read(codec, WM8971_IFACE) & 0x1f3;
499 u16 srate = snd_soc_read(codec, WM8971_SRATE) & 0x1c0; 497 u16 srate = snd_soc_read(codec, WM8971_SRATE) & 0x1c0;
@@ -573,8 +571,8 @@ static struct snd_soc_dai_ops wm8971_dai_ops = {
573 .set_sysclk = wm8971_set_dai_sysclk, 571 .set_sysclk = wm8971_set_dai_sysclk,
574}; 572};
575 573
576struct snd_soc_dai wm8971_dai = { 574static struct snd_soc_dai_driver wm8971_dai = {
577 .name = "WM8971", 575 .name = "wm8971-hifi",
578 .playback = { 576 .playback = {
579 .stream_name = "Playback", 577 .stream_name = "Playback",
580 .channels_min = 1, 578 .channels_min = 1,
@@ -589,7 +587,6 @@ struct snd_soc_dai wm8971_dai = {
589 .formats = WM8971_FORMATS,}, 587 .formats = WM8971_FORMATS,},
590 .ops = &wm8971_dai_ops, 588 .ops = &wm8971_dai_ops,
591}; 589};
592EXPORT_SYMBOL_GPL(wm8971_dai);
593 590
594static void wm8971_work(struct work_struct *work) 591static void wm8971_work(struct work_struct *work)
595{ 592{
@@ -598,19 +595,14 @@ static void wm8971_work(struct work_struct *work)
598 wm8971_set_bias_level(codec, codec->bias_level); 595 wm8971_set_bias_level(codec, codec->bias_level);
599} 596}
600 597
601static int wm8971_suspend(struct platform_device *pdev, pm_message_t state) 598static int wm8971_suspend(struct snd_soc_codec *codec, pm_message_t state)
602{ 599{
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); 600 wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
607 return 0; 601 return 0;
608} 602}
609 603
610static int wm8971_resume(struct platform_device *pdev) 604static int wm8971_resume(struct snd_soc_codec *codec)
611{ 605{
612 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
613 struct snd_soc_codec *codec = socdev->card->codec;
614 int i; 606 int i;
615 u8 data[2]; 607 u8 data[2];
616 u16 *cache = codec->reg_cache; 608 u16 *cache = codec->reg_cache;
@@ -639,37 +631,24 @@ static int wm8971_resume(struct platform_device *pdev)
639 return 0; 631 return 0;
640} 632}
641 633
642static int wm8971_init(struct snd_soc_device *socdev, 634static int wm8971_probe(struct snd_soc_codec *codec)
643 enum snd_soc_control_type control)
644{ 635{
645 struct snd_soc_codec *codec = socdev->card->codec; 636 struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
646 int reg, ret = 0; 637 int ret = 0;
647 638 u16 reg;
648 codec->name = "WM8971";
649 codec->owner = THIS_MODULE;
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 639
659 ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); 640 ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8971->control_type);
660 if (ret < 0) { 641 if (ret < 0) {
661 printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret); 642 printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret);
662 goto err; 643 return ret;
663 } 644 }
664 645
665 wm8971_reset(codec); 646 INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work);
647 wm8971_workq = create_workqueue("wm8971");
648 if (wm8971_workq == NULL)
649 return -ENOMEM;
666 650
667 /* register pcms */ 651 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 652
674 /* charge output caps - set vmid to 5k for quick power up */ 653 /* charge output caps - set vmid to 5k for quick power up */
675 reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e; 654 reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
@@ -704,40 +683,54 @@ static int wm8971_init(struct snd_soc_device *socdev,
704 wm8971_add_widgets(codec); 683 wm8971_add_widgets(codec);
705 684
706 return ret; 685 return ret;
707
708err:
709 kfree(codec->reg_cache);
710 return ret;
711} 686}
712 687
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 688
717#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) 689/* power down chip */
690static int wm8971_remove(struct snd_soc_codec *codec)
691{
692 wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
693
694 if (wm8971_workq)
695 destroy_workqueue(wm8971_workq);
696 return 0;
697}
718 698
719static int wm8971_i2c_probe(struct i2c_client *i2c, 699static struct snd_soc_codec_driver soc_codec_dev_wm8971 = {
720 const struct i2c_device_id *id) 700 .probe = wm8971_probe,
701 .remove = wm8971_remove,
702 .suspend = wm8971_suspend,
703 .resume = wm8971_resume,
704 .set_bias_level = wm8971_set_bias_level,
705 .reg_cache_size = ARRAY_SIZE(wm8971_reg),
706 .reg_word_size = sizeof(u16),
707 .reg_cache_default = wm8971_reg,
708};
709
710#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
711static __devinit int wm8971_i2c_probe(struct i2c_client *i2c,
712 const struct i2c_device_id *id)
721{ 713{
722 struct snd_soc_device *socdev = wm8971_socdev; 714 struct wm8971_priv *wm8971;
723 struct snd_soc_codec *codec = socdev->card->codec;
724 int ret; 715 int ret;
725 716
726 i2c_set_clientdata(i2c, codec); 717 wm8971 = kzalloc(sizeof(struct wm8971_priv), GFP_KERNEL);
718 if (wm8971 == NULL)
719 return -ENOMEM;
727 720
728 codec->control_data = i2c; 721 i2c_set_clientdata(i2c, wm8971);
729 722
730 ret = wm8971_init(socdev, SND_SOC_I2C); 723 ret = snd_soc_register_codec(&i2c->dev,
724 &soc_codec_dev_wm8971, &wm8971_dai, 1);
731 if (ret < 0) 725 if (ret < 0)
732 pr_err("failed to initialise WM8971\n"); 726 kfree(wm8971);
733
734 return ret; 727 return ret;
735} 728}
736 729
737static int wm8971_i2c_remove(struct i2c_client *client) 730static __devexit int wm8971_i2c_remove(struct i2c_client *client)
738{ 731{
739 struct snd_soc_codec *codec = i2c_get_clientdata(client); 732 snd_soc_unregister_codec(&client->dev);
740 kfree(codec->reg_cache); 733 kfree(i2c_get_clientdata(client));
741 return 0; 734 return 0;
742} 735}
743 736
@@ -749,148 +742,34 @@ MODULE_DEVICE_TABLE(i2c, wm8971_i2c_id);
749 742
750static struct i2c_driver wm8971_i2c_driver = { 743static struct i2c_driver wm8971_i2c_driver = {
751 .driver = { 744 .driver = {
752 .name = "WM8971 I2C Codec", 745 .name = "wm8971-codec",
753 .owner = THIS_MODULE, 746 .owner = THIS_MODULE,
754 }, 747 },
755 .probe = wm8971_i2c_probe, 748 .probe = wm8971_i2c_probe,
756 .remove = wm8971_i2c_remove, 749 .remove = __devexit_p(wm8971_i2c_remove),
757 .id_table = wm8971_i2c_id, 750 .id_table = wm8971_i2c_id,
758}; 751};
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 752#endif
801 753
802static int wm8971_probe(struct platform_device *pdev) 754static int __init wm8971_modinit(void)
803{ 755{
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; 756 int ret = 0;
809 757#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
810 pr_info("WM8971 Audio Codec %s", WM8971_VERSION); 758 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) { 759 if (ret != 0) {
846 destroy_workqueue(wm8971_workq); 760 printk(KERN_ERR "Failed to register WM8971 I2C driver: %d\n",
847 kfree(snd_soc_codec_get_drvdata(codec)); 761 ret);
848 kfree(codec);
849 } 762 }
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 763#endif
870 kfree(snd_soc_codec_get_drvdata(codec)); 764 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} 765}
889module_init(wm8971_modinit); 766module_init(wm8971_modinit);
890 767
891static void __exit wm8971_exit(void) 768static void __exit wm8971_exit(void)
892{ 769{
893 snd_soc_unregister_dai(&wm8971_dai); 770#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
771 i2c_del_driver(&wm8971_i2c_driver);
772#endif
894} 773}
895module_exit(wm8971_exit); 774module_exit(wm8971_exit);
896 775