diff options
Diffstat (limited to 'sound/soc/codecs/wm8750.c')
-rw-r--r-- | sound/soc/codecs/wm8750.c | 269 |
1 files changed, 84 insertions, 185 deletions
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index e2c05e3e323a..89863a5bc830 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
@@ -52,7 +52,8 @@ static const u16 wm8750_reg[] = { | |||
52 | /* codec private data */ | 52 | /* codec private data */ |
53 | struct wm8750_priv { | 53 | struct wm8750_priv { |
54 | unsigned int sysclk; | 54 | unsigned int sysclk; |
55 | struct snd_soc_codec codec; | 55 | enum snd_soc_control_type control_type; |
56 | void *control_data; | ||
56 | u16 reg_cache[ARRAY_SIZE(wm8750_reg)]; | 57 | u16 reg_cache[ARRAY_SIZE(wm8750_reg)]; |
57 | }; | 58 | }; |
58 | 59 | ||
@@ -560,8 +561,7 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, | |||
560 | struct snd_soc_dai *dai) | 561 | struct snd_soc_dai *dai) |
561 | { | 562 | { |
562 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 563 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
563 | struct snd_soc_device *socdev = rtd->socdev; | 564 | struct snd_soc_codec *codec = rtd->codec; |
564 | struct snd_soc_codec *codec = socdev->card->codec; | ||
565 | struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec); | 565 | struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec); |
566 | u16 iface = snd_soc_read(codec, WM8750_IFACE) & 0x1f3; | 566 | u16 iface = snd_soc_read(codec, WM8750_IFACE) & 0x1f3; |
567 | u16 srate = snd_soc_read(codec, WM8750_SRATE) & 0x1c0; | 567 | u16 srate = snd_soc_read(codec, WM8750_SRATE) & 0x1c0; |
@@ -649,8 +649,8 @@ static struct snd_soc_dai_ops wm8750_dai_ops = { | |||
649 | .set_sysclk = wm8750_set_dai_sysclk, | 649 | .set_sysclk = wm8750_set_dai_sysclk, |
650 | }; | 650 | }; |
651 | 651 | ||
652 | struct snd_soc_dai wm8750_dai = { | 652 | static struct snd_soc_dai_driver wm8750_dai = { |
653 | .name = "WM8750", | 653 | .name = "wm8750-hifi", |
654 | .playback = { | 654 | .playback = { |
655 | .stream_name = "Playback", | 655 | .stream_name = "Playback", |
656 | .channels_min = 1, | 656 | .channels_min = 1, |
@@ -665,21 +665,15 @@ struct snd_soc_dai wm8750_dai = { | |||
665 | .formats = WM8750_FORMATS,}, | 665 | .formats = WM8750_FORMATS,}, |
666 | .ops = &wm8750_dai_ops, | 666 | .ops = &wm8750_dai_ops, |
667 | }; | 667 | }; |
668 | EXPORT_SYMBOL_GPL(wm8750_dai); | ||
669 | 668 | ||
670 | static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) | 669 | static int wm8750_suspend(struct snd_soc_codec *codec, pm_message_t state) |
671 | { | 670 | { |
672 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
673 | struct snd_soc_codec *codec = socdev->card->codec; | ||
674 | |||
675 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); | 671 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); |
676 | return 0; | 672 | return 0; |
677 | } | 673 | } |
678 | 674 | ||
679 | static int wm8750_resume(struct platform_device *pdev) | 675 | static int wm8750_resume(struct snd_soc_codec *codec) |
680 | { | 676 | { |
681 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
682 | struct snd_soc_codec *codec = socdev->card->codec; | ||
683 | int i; | 677 | int i; |
684 | u8 data[2]; | 678 | u8 data[2]; |
685 | u16 *cache = codec->reg_cache; | 679 | u16 *cache = codec->reg_cache; |
@@ -698,100 +692,22 @@ static int wm8750_resume(struct platform_device *pdev) | |||
698 | return 0; | 692 | return 0; |
699 | } | 693 | } |
700 | 694 | ||
701 | static struct snd_soc_codec *wm8750_codec; | 695 | static int wm8750_probe(struct snd_soc_codec *codec) |
702 | |||
703 | static int wm8750_probe(struct platform_device *pdev) | ||
704 | { | 696 | { |
705 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 697 | struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec); |
706 | struct snd_soc_codec *codec; | 698 | int reg, ret; |
707 | int ret = 0; | ||
708 | |||
709 | if (!wm8750_codec) { | ||
710 | dev_err(&pdev->dev, "WM8750 codec not yet registered\n"); | ||
711 | return -EINVAL; | ||
712 | } | ||
713 | |||
714 | socdev->card->codec = wm8750_codec; | ||
715 | codec = wm8750_codec; | ||
716 | |||
717 | /* register pcms */ | ||
718 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
719 | if (ret < 0) { | ||
720 | printk(KERN_ERR "wm8750: failed to create pcms\n"); | ||
721 | goto err; | ||
722 | } | ||
723 | |||
724 | snd_soc_add_controls(codec, wm8750_snd_controls, | ||
725 | ARRAY_SIZE(wm8750_snd_controls)); | ||
726 | wm8750_add_widgets(codec); | ||
727 | |||
728 | return 0; | ||
729 | |||
730 | err: | ||
731 | return ret; | ||
732 | } | ||
733 | |||
734 | /* power down chip */ | ||
735 | static int wm8750_remove(struct platform_device *pdev) | ||
736 | { | ||
737 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
738 | |||
739 | snd_soc_free_pcms(socdev); | ||
740 | snd_soc_dapm_free(socdev); | ||
741 | |||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | struct snd_soc_codec_device soc_codec_dev_wm8750 = { | ||
746 | .probe = wm8750_probe, | ||
747 | .remove = wm8750_remove, | ||
748 | .suspend = wm8750_suspend, | ||
749 | .resume = wm8750_resume, | ||
750 | }; | ||
751 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750); | ||
752 | |||
753 | /* | ||
754 | * initialise the WM8750 driver | ||
755 | * register the mixer and dsp interfaces with the kernel | ||
756 | */ | ||
757 | static int wm8750_register(struct wm8750_priv *wm8750, | ||
758 | enum snd_soc_control_type control) | ||
759 | { | ||
760 | struct snd_soc_codec *codec = &wm8750->codec; | ||
761 | int reg, ret = 0; | ||
762 | |||
763 | if (wm8750_codec) { | ||
764 | dev_err(codec->dev, "Multiple WM8750 devices not supported\n"); | ||
765 | ret = -EINVAL; | ||
766 | goto err; | ||
767 | } | ||
768 | |||
769 | mutex_init(&codec->mutex); | ||
770 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
771 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
772 | |||
773 | codec->name = "WM8750"; | ||
774 | codec->owner = THIS_MODULE; | ||
775 | codec->bias_level = SND_SOC_BIAS_STANDBY; | ||
776 | codec->set_bias_level = wm8750_set_bias_level; | ||
777 | codec->dai = &wm8750_dai; | ||
778 | codec->num_dai = 1; | ||
779 | codec->reg_cache_size = ARRAY_SIZE(wm8750->reg_cache) + 1; | ||
780 | codec->reg_cache = &wm8750->reg_cache; | ||
781 | snd_soc_codec_set_drvdata(codec, wm8750); | ||
782 | |||
783 | memcpy(codec->reg_cache, wm8750_reg, sizeof(wm8750->reg_cache)); | ||
784 | 699 | ||
785 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); | 700 | codec->control_data = wm8750->control_data; |
701 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8750->control_type); | ||
786 | if (ret < 0) { | 702 | if (ret < 0) { |
787 | printk(KERN_ERR "wm8750: failed to set cache I/O: %d\n", ret); | 703 | printk(KERN_ERR "wm8750: failed to set cache I/O: %d\n", ret); |
788 | goto err; | 704 | return ret; |
789 | } | 705 | } |
790 | 706 | ||
791 | ret = wm8750_reset(codec); | 707 | ret = wm8750_reset(codec); |
792 | if (ret < 0) { | 708 | if (ret < 0) { |
793 | printk(KERN_ERR "wm8750: failed to reset: %d\n", ret); | 709 | printk(KERN_ERR "wm8750: failed to reset: %d\n", ret); |
794 | goto err; | 710 | return ret; |
795 | } | 711 | } |
796 | 712 | ||
797 | /* charge output caps */ | 713 | /* charge output caps */ |
@@ -815,150 +731,133 @@ static int wm8750_register(struct wm8750_priv *wm8750, | |||
815 | reg = snd_soc_read(codec, WM8750_RINVOL); | 731 | reg = snd_soc_read(codec, WM8750_RINVOL); |
816 | snd_soc_write(codec, WM8750_RINVOL, reg | 0x0100); | 732 | snd_soc_write(codec, WM8750_RINVOL, reg | 0x0100); |
817 | 733 | ||
818 | wm8750_codec = codec; | 734 | snd_soc_add_controls(codec, wm8750_snd_controls, |
819 | 735 | ARRAY_SIZE(wm8750_snd_controls)); | |
820 | ret = snd_soc_register_codec(codec); | 736 | wm8750_add_widgets(codec); |
821 | if (ret != 0) { | ||
822 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
823 | goto err; | ||
824 | } | ||
825 | |||
826 | ret = snd_soc_register_dais(&wm8750_dai, 1); | ||
827 | if (ret != 0) { | ||
828 | dev_err(codec->dev, "Failed to register DAIs: %d\n", ret); | ||
829 | goto err_codec; | ||
830 | } | ||
831 | |||
832 | return 0; | ||
833 | |||
834 | err_codec: | ||
835 | snd_soc_unregister_codec(codec); | ||
836 | err: | ||
837 | kfree(wm8750); | ||
838 | return ret; | 737 | return ret; |
839 | } | 738 | } |
840 | 739 | ||
841 | static void wm8750_unregister(struct wm8750_priv *wm8750) | 740 | static int wm8750_remove(struct snd_soc_codec *codec) |
842 | { | 741 | { |
843 | wm8750_set_bias_level(&wm8750->codec, SND_SOC_BIAS_OFF); | 742 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); |
844 | snd_soc_unregister_dais(&wm8750_dai, 1); | 743 | return 0; |
845 | snd_soc_unregister_codec(&wm8750->codec); | ||
846 | kfree(wm8750); | ||
847 | wm8750_codec = NULL; | ||
848 | } | 744 | } |
849 | 745 | ||
850 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 746 | static struct snd_soc_codec_driver soc_codec_dev_wm8750 = { |
851 | 747 | .probe = wm8750_probe, | |
852 | /* | 748 | .remove = wm8750_remove, |
853 | * WM8750 2 wire address is determined by GPIO5 | 749 | .suspend = wm8750_suspend, |
854 | * state during powerup. | 750 | .resume = wm8750_resume, |
855 | * low = 0x1a | 751 | .set_bias_level = wm8750_set_bias_level, |
856 | * high = 0x1b | 752 | .reg_cache_size = sizeof(wm8750_reg), |
857 | */ | 753 | .reg_word_size = sizeof(u16), |
754 | .reg_cache_default = wm8750_reg, | ||
755 | }; | ||
858 | 756 | ||
859 | static int wm8750_i2c_probe(struct i2c_client *i2c, | 757 | #if defined(CONFIG_SPI_MASTER) |
860 | const struct i2c_device_id *id) | 758 | static int __devinit wm8750_spi_probe(struct spi_device *spi) |
861 | { | 759 | { |
862 | struct snd_soc_codec *codec; | ||
863 | struct wm8750_priv *wm8750; | 760 | struct wm8750_priv *wm8750; |
761 | int ret; | ||
864 | 762 | ||
865 | wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL); | 763 | wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL); |
866 | if (wm8750 == NULL) | 764 | if (wm8750 == NULL) |
867 | return -ENOMEM; | 765 | return -ENOMEM; |
868 | 766 | ||
869 | codec = &wm8750->codec; | 767 | wm8750->control_data = spi; |
870 | codec->control_data = i2c; | 768 | wm8750->control_type = SND_SOC_SPI; |
871 | i2c_set_clientdata(i2c, wm8750); | 769 | spi_set_drvdata(spi, wm8750); |
872 | |||
873 | codec->dev = &i2c->dev; | ||
874 | 770 | ||
875 | return wm8750_register(wm8750, SND_SOC_I2C); | 771 | ret = snd_soc_register_codec(&spi->dev, |
772 | &soc_codec_dev_wm8750, &wm8750_dai, 1); | ||
773 | if (ret < 0) | ||
774 | kfree(wm8750); | ||
775 | return ret; | ||
876 | } | 776 | } |
877 | 777 | ||
878 | static int wm8750_i2c_remove(struct i2c_client *client) | 778 | static int __devexit wm8750_spi_remove(struct spi_device *spi) |
879 | { | 779 | { |
880 | struct wm8750_priv *wm8750 = i2c_get_clientdata(client); | 780 | snd_soc_unregister_codec(&spi->dev); |
881 | wm8750_unregister(wm8750); | 781 | kfree(spi_get_drvdata(spi)); |
882 | return 0; | 782 | return 0; |
883 | } | 783 | } |
884 | 784 | ||
885 | static const struct i2c_device_id wm8750_i2c_id[] = { | 785 | static struct spi_driver wm8750_spi_driver = { |
886 | { "wm8750", 0 }, | ||
887 | { "wm8987", 0 }, /* WM8987 is register compatible with WM8750 */ | ||
888 | { } | ||
889 | }; | ||
890 | MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id); | ||
891 | |||
892 | static struct i2c_driver wm8750_i2c_driver = { | ||
893 | .driver = { | 786 | .driver = { |
894 | .name = "WM8750 I2C Codec", | 787 | .name = "wm8750-codec", |
895 | .owner = THIS_MODULE, | 788 | .bus = &spi_bus_type, |
789 | .owner = THIS_MODULE, | ||
896 | }, | 790 | }, |
897 | .probe = wm8750_i2c_probe, | 791 | .probe = wm8750_spi_probe, |
898 | .remove = wm8750_i2c_remove, | 792 | .remove = __devexit_p(wm8750_spi_remove), |
899 | .id_table = wm8750_i2c_id, | ||
900 | }; | 793 | }; |
901 | #endif | 794 | #endif /* CONFIG_SPI_MASTER */ |
902 | 795 | ||
903 | #if defined(CONFIG_SPI_MASTER) | 796 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
904 | static int __devinit wm8750_spi_probe(struct spi_device *spi) | 797 | static __devinit int wm8750_i2c_probe(struct i2c_client *i2c, |
798 | const struct i2c_device_id *id) | ||
905 | { | 799 | { |
906 | struct snd_soc_codec *codec; | ||
907 | struct wm8750_priv *wm8750; | 800 | struct wm8750_priv *wm8750; |
801 | int ret; | ||
908 | 802 | ||
909 | wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL); | 803 | wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL); |
910 | if (wm8750 == NULL) | 804 | if (wm8750 == NULL) |
911 | return -ENOMEM; | 805 | return -ENOMEM; |
912 | 806 | ||
913 | codec = &wm8750->codec; | 807 | i2c_set_clientdata(i2c, wm8750); |
914 | codec->control_data = spi; | 808 | wm8750->control_data = i2c; |
915 | codec->dev = &spi->dev; | 809 | wm8750->control_type = SND_SOC_I2C; |
916 | |||
917 | dev_set_drvdata(&spi->dev, wm8750); | ||
918 | 810 | ||
919 | return wm8750_register(wm8750, SND_SOC_SPI); | 811 | ret = snd_soc_register_codec(&i2c->dev, |
812 | &soc_codec_dev_wm8750, &wm8750_dai, 1); | ||
813 | if (ret < 0) | ||
814 | kfree(wm8750); | ||
815 | return ret; | ||
920 | } | 816 | } |
921 | 817 | ||
922 | static int __devexit wm8750_spi_remove(struct spi_device *spi) | 818 | static __devexit int wm8750_i2c_remove(struct i2c_client *client) |
923 | { | 819 | { |
924 | struct wm8750_priv *wm8750 = dev_get_drvdata(&spi->dev); | 820 | snd_soc_unregister_codec(&client->dev); |
925 | wm8750_unregister(wm8750); | 821 | kfree(i2c_get_clientdata(client)); |
926 | return 0; | 822 | return 0; |
927 | } | 823 | } |
928 | 824 | ||
929 | static const struct spi_device_id wm8750_spi_id[] = { | 825 | static const struct i2c_device_id wm8750_i2c_id[] = { |
930 | { "wm8750", 0 }, | 826 | { "wm8750", 0 }, |
931 | { "wm8987", 0 }, | 827 | { "wm8987", 0 }, |
932 | { } | 828 | { } |
933 | }; | 829 | }; |
934 | MODULE_DEVICE_TABLE(spi, wm8750_spi_id); | 830 | MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id); |
935 | 831 | ||
936 | static struct spi_driver wm8750_spi_driver = { | 832 | static struct i2c_driver wm8750_i2c_driver = { |
937 | .driver = { | 833 | .driver = { |
938 | .name = "WM8750 SPI Codec", | 834 | .name = "wm8750-codec", |
939 | .bus = &spi_bus_type, | 835 | .owner = THIS_MODULE, |
940 | .owner = THIS_MODULE, | ||
941 | }, | 836 | }, |
942 | .probe = wm8750_spi_probe, | 837 | .probe = wm8750_i2c_probe, |
943 | .remove = __devexit_p(wm8750_spi_remove), | 838 | .remove = __devexit_p(wm8750_i2c_remove), |
944 | .id_table = wm8750_spi_id, | 839 | .id_table = wm8750_i2c_id, |
945 | }; | 840 | }; |
946 | #endif | 841 | #endif |
947 | 842 | ||
948 | static int __init wm8750_modinit(void) | 843 | static int __init wm8750_modinit(void) |
949 | { | 844 | { |
950 | int ret; | 845 | int ret = 0; |
951 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 846 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
952 | ret = i2c_add_driver(&wm8750_i2c_driver); | 847 | ret = i2c_add_driver(&wm8750_i2c_driver); |
953 | if (ret != 0) | 848 | if (ret != 0) { |
954 | pr_err("Failed to register WM8750 I2C driver: %d\n", ret); | 849 | printk(KERN_ERR "Failed to register wm8750 I2C driver: %d\n", |
850 | ret); | ||
851 | } | ||
955 | #endif | 852 | #endif |
956 | #if defined(CONFIG_SPI_MASTER) | 853 | #if defined(CONFIG_SPI_MASTER) |
957 | ret = spi_register_driver(&wm8750_spi_driver); | 854 | ret = spi_register_driver(&wm8750_spi_driver); |
958 | if (ret != 0) | 855 | if (ret != 0) { |
959 | pr_err("Failed to register WM8750 SPI driver: %d\n", ret); | 856 | printk(KERN_ERR "Failed to register wm8750 SPI driver: %d\n", |
857 | ret); | ||
858 | } | ||
960 | #endif | 859 | #endif |
961 | return 0; | 860 | return ret; |
962 | } | 861 | } |
963 | module_init(wm8750_modinit); | 862 | module_init(wm8750_modinit); |
964 | 863 | ||