diff options
Diffstat (limited to 'sound/soc/codecs/wm8940.c')
-rw-r--r-- | sound/soc/codecs/wm8940.c | 199 |
1 files changed, 56 insertions, 143 deletions
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index f0c11138e610..2cb16f895c46 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c | |||
@@ -44,7 +44,8 @@ | |||
44 | struct wm8940_priv { | 44 | struct 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 | ||
50 | static u16 wm8940_reg_defaults[] = { | 51 | static 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 | ||
639 | struct snd_soc_dai wm8940_dai = { | 639 | static 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 | }; |
658 | EXPORT_SYMBOL_GPL(wm8940_dai); | ||
659 | 658 | ||
660 | static int wm8940_suspend(struct platform_device *pdev, pm_message_t state) | 659 | static 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 | ||
668 | static int wm8940_resume(struct platform_device *pdev) | 664 | static 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 | ||
700 | static struct snd_soc_codec *wm8940_codec; | 694 | static int wm8940_probe(struct snd_soc_codec *codec) |
701 | |||
702 | static 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 | |||
735 | error_free_pcms: | ||
736 | snd_soc_free_pcms(socdev); | ||
737 | snd_soc_dapm_free(socdev); | ||
738 | pcm_err: | ||
739 | return ret; | ||
740 | } | ||
741 | |||
742 | static 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 | |||
752 | struct 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 | }; | ||
758 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8940); | ||
759 | |||
760 | static 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 | ||
836 | static void wm8940_unregister(struct wm8940_priv *wm8940) | 741 | static 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 | ||
845 | static int wm8940_i2c_probe(struct i2c_client *i2c, | 747 | static 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 = ARRAY_SIZE(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) | ||
759 | static __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 | ||
869 | static int __devexit wm8940_i2c_remove(struct i2c_client *client) | 779 | static __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 | ||
884 | static struct i2c_driver wm8940_i2c_driver = { | 792 | static 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 | ||
894 | static int __init wm8940_modinit(void) | 803 | static 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 | } |
904 | module_init(wm8940_modinit); | 815 | module_init(wm8940_modinit); |
905 | 816 | ||
906 | static void __exit wm8940_exit(void) | 817 | static 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 | } |
910 | module_exit(wm8940_exit); | 823 | module_exit(wm8940_exit); |
911 | 824 | ||