diff options
Diffstat (limited to 'sound/soc/codecs/wm8971.c')
-rw-r--r-- | sound/soc/codecs/wm8971.c | 250 |
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 */ |
40 | struct wm8971_priv { | 40 | struct 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 | ||
576 | struct snd_soc_dai wm8971_dai = { | 577 | static 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 | }; |
592 | EXPORT_SYMBOL_GPL(wm8971_dai); | ||
593 | 593 | ||
594 | static void wm8971_work(struct work_struct *work) | 594 | static 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 | ||
601 | static int wm8971_suspend(struct platform_device *pdev, pm_message_t state) | 601 | static 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 | ||
610 | static int wm8971_resume(struct platform_device *pdev) | 607 | static 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 | ||
642 | static int wm8971_init(struct snd_soc_device *socdev, | 637 | static 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 | |||
708 | err: | ||
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 */ | ||
715 | static struct snd_soc_device *wm8971_socdev; | ||
716 | 694 | ||
717 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) | 695 | /* power down chip */ |
696 | static 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 | |||
705 | static 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 | ||
719 | static int wm8971_i2c_probe(struct i2c_client *i2c, | 716 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
720 | const struct i2c_device_id *id) | 717 | static __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 | ||
737 | static int wm8971_i2c_remove(struct i2c_client *client) | 737 | static __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 | ||
750 | static struct i2c_driver wm8971_i2c_driver = { | 750 | static 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 | |||
760 | static 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 | |||
795 | err_driver: | ||
796 | i2c_del_driver(&wm8971_i2c_driver); | ||
797 | return -ENODEV; | ||
798 | } | ||
799 | |||
800 | #endif | 759 | #endif |
801 | 760 | ||
802 | static int wm8971_probe(struct platform_device *pdev) | 761 | static 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 */ | ||
855 | static 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 | |||
876 | struct 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 | |||
883 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8971); | ||
884 | |||
885 | static int __init wm8971_modinit(void) | ||
886 | { | ||
887 | return snd_soc_register_dai(&wm8971_dai); | ||
888 | } | 772 | } |
889 | module_init(wm8971_modinit); | 773 | module_init(wm8971_modinit); |
890 | 774 | ||
891 | static void __exit wm8971_exit(void) | 775 | static 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 | } |
895 | module_exit(wm8971_exit); | 781 | module_exit(wm8971_exit); |
896 | 782 | ||