diff options
Diffstat (limited to 'sound/soc/codecs/wm8580.c')
-rw-r--r-- | sound/soc/codecs/wm8580.c | 326 |
1 files changed, 158 insertions, 168 deletions
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 27f9e231bf69..442ea6f160fc 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm8580.c -- WM8580 ALSA Soc Audio driver | 2 | * wm8580.c -- WM8580 ALSA Soc Audio driver |
3 | * | 3 | * |
4 | * Copyright 2008 Wolfson Microelectronics PLC. | 4 | * Copyright 2008, 2009 Wolfson Microelectronics PLC. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License as published by the | 7 | * under the terms of the GNU General Public License as published by the |
@@ -35,17 +35,6 @@ | |||
35 | 35 | ||
36 | #include "wm8580.h" | 36 | #include "wm8580.h" |
37 | 37 | ||
38 | struct pll_state { | ||
39 | unsigned int in; | ||
40 | unsigned int out; | ||
41 | }; | ||
42 | |||
43 | /* codec private data */ | ||
44 | struct wm8580_priv { | ||
45 | struct pll_state a; | ||
46 | struct pll_state b; | ||
47 | }; | ||
48 | |||
49 | /* WM8580 register space */ | 38 | /* WM8580 register space */ |
50 | #define WM8580_PLLA1 0x00 | 39 | #define WM8580_PLLA1 0x00 |
51 | #define WM8580_PLLA2 0x01 | 40 | #define WM8580_PLLA2 0x01 |
@@ -100,6 +89,8 @@ struct wm8580_priv { | |||
100 | #define WM8580_READBACK 0x34 | 89 | #define WM8580_READBACK 0x34 |
101 | #define WM8580_RESET 0x35 | 90 | #define WM8580_RESET 0x35 |
102 | 91 | ||
92 | #define WM8580_MAX_REGISTER 0x35 | ||
93 | |||
103 | /* PLLB4 (register 7h) */ | 94 | /* PLLB4 (register 7h) */ |
104 | #define WM8580_PLLB4_MCLKOUTSRC_MASK 0x60 | 95 | #define WM8580_PLLB4_MCLKOUTSRC_MASK 0x60 |
105 | #define WM8580_PLLB4_MCLKOUTSRC_PLLA 0x20 | 96 | #define WM8580_PLLB4_MCLKOUTSRC_PLLA 0x20 |
@@ -191,6 +182,20 @@ static const u16 wm8580_reg[] = { | |||
191 | 0x0000, 0x0000 /*R53*/ | 182 | 0x0000, 0x0000 /*R53*/ |
192 | }; | 183 | }; |
193 | 184 | ||
185 | struct pll_state { | ||
186 | unsigned int in; | ||
187 | unsigned int out; | ||
188 | }; | ||
189 | |||
190 | /* codec private data */ | ||
191 | struct wm8580_priv { | ||
192 | struct snd_soc_codec codec; | ||
193 | u16 reg_cache[WM8580_MAX_REGISTER + 1]; | ||
194 | struct pll_state a; | ||
195 | struct pll_state b; | ||
196 | }; | ||
197 | |||
198 | |||
194 | /* | 199 | /* |
195 | * read wm8580 register cache | 200 | * read wm8580 register cache |
196 | */ | 201 | */ |
@@ -755,8 +760,22 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec, | |||
755 | switch (level) { | 760 | switch (level) { |
756 | case SND_SOC_BIAS_ON: | 761 | case SND_SOC_BIAS_ON: |
757 | case SND_SOC_BIAS_PREPARE: | 762 | case SND_SOC_BIAS_PREPARE: |
763 | break; | ||
764 | |||
758 | case SND_SOC_BIAS_STANDBY: | 765 | case SND_SOC_BIAS_STANDBY: |
766 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
767 | /* Power up and get individual control of the DACs */ | ||
768 | reg = wm8580_read(codec, WM8580_PWRDN1); | ||
769 | reg &= ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD); | ||
770 | wm8580_write(codec, WM8580_PWRDN1, reg); | ||
771 | |||
772 | /* Make VMID high impedence */ | ||
773 | reg = wm8580_read(codec, WM8580_ADC_CONTROL1); | ||
774 | reg &= ~0x100; | ||
775 | wm8580_write(codec, WM8580_ADC_CONTROL1, reg); | ||
776 | } | ||
759 | break; | 777 | break; |
778 | |||
760 | case SND_SOC_BIAS_OFF: | 779 | case SND_SOC_BIAS_OFF: |
761 | reg = wm8580_read(codec, WM8580_PWRDN1); | 780 | reg = wm8580_read(codec, WM8580_PWRDN1); |
762 | wm8580_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN); | 781 | wm8580_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN); |
@@ -812,100 +831,163 @@ struct snd_soc_dai wm8580_dai[] = { | |||
812 | }; | 831 | }; |
813 | EXPORT_SYMBOL_GPL(wm8580_dai); | 832 | EXPORT_SYMBOL_GPL(wm8580_dai); |
814 | 833 | ||
815 | /* | 834 | static struct snd_soc_codec *wm8580_codec; |
816 | * initialise the WM8580 driver | 835 | |
817 | * register the mixer and dsp interfaces with the kernel | 836 | static int wm8580_probe(struct platform_device *pdev) |
818 | */ | ||
819 | static int wm8580_init(struct snd_soc_device *socdev) | ||
820 | { | 837 | { |
821 | struct snd_soc_codec *codec = socdev->card->codec; | 838 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
839 | struct snd_soc_codec *codec; | ||
822 | int ret = 0; | 840 | int ret = 0; |
823 | 841 | ||
824 | codec->name = "WM8580"; | 842 | if (wm8580_codec == NULL) { |
825 | codec->owner = THIS_MODULE; | 843 | dev_err(&pdev->dev, "Codec device not registered\n"); |
826 | codec->read = wm8580_read_reg_cache; | 844 | return -ENODEV; |
827 | codec->write = wm8580_write; | 845 | } |
828 | codec->set_bias_level = wm8580_set_bias_level; | ||
829 | codec->dai = wm8580_dai; | ||
830 | codec->num_dai = ARRAY_SIZE(wm8580_dai); | ||
831 | codec->reg_cache_size = ARRAY_SIZE(wm8580_reg); | ||
832 | codec->reg_cache = kmemdup(wm8580_reg, sizeof(wm8580_reg), | ||
833 | GFP_KERNEL); | ||
834 | |||
835 | if (codec->reg_cache == NULL) | ||
836 | return -ENOMEM; | ||
837 | |||
838 | /* Get the codec into a known state */ | ||
839 | wm8580_write(codec, WM8580_RESET, 0); | ||
840 | |||
841 | /* Power up and get individual control of the DACs */ | ||
842 | wm8580_write(codec, WM8580_PWRDN1, wm8580_read(codec, WM8580_PWRDN1) & | ||
843 | ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD)); | ||
844 | 846 | ||
845 | /* Make VMID high impedence */ | 847 | socdev->card->codec = wm8580_codec; |
846 | wm8580_write(codec, WM8580_ADC_CONTROL1, | 848 | codec = wm8580_codec; |
847 | wm8580_read(codec, WM8580_ADC_CONTROL1) & ~0x100); | ||
848 | 849 | ||
849 | /* register pcms */ | 850 | /* register pcms */ |
850 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, | 851 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
851 | SNDRV_DEFAULT_STR1); | ||
852 | if (ret < 0) { | 852 | if (ret < 0) { |
853 | printk(KERN_ERR "wm8580: failed to create pcms\n"); | 853 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); |
854 | goto pcm_err; | 854 | goto pcm_err; |
855 | } | 855 | } |
856 | 856 | ||
857 | snd_soc_add_controls(codec, wm8580_snd_controls, | 857 | snd_soc_add_controls(codec, wm8580_snd_controls, |
858 | ARRAY_SIZE(wm8580_snd_controls)); | 858 | ARRAY_SIZE(wm8580_snd_controls)); |
859 | wm8580_add_widgets(codec); | 859 | wm8580_add_widgets(codec); |
860 | |||
861 | ret = snd_soc_init_card(socdev); | 860 | ret = snd_soc_init_card(socdev); |
862 | if (ret < 0) { | 861 | if (ret < 0) { |
863 | printk(KERN_ERR "wm8580: failed to register card\n"); | 862 | dev_err(codec->dev, "failed to register card: %d\n", ret); |
864 | goto card_err; | 863 | goto card_err; |
865 | } | 864 | } |
865 | |||
866 | return ret; | 866 | return ret; |
867 | 867 | ||
868 | card_err: | 868 | card_err: |
869 | snd_soc_free_pcms(socdev); | 869 | snd_soc_free_pcms(socdev); |
870 | snd_soc_dapm_free(socdev); | 870 | snd_soc_dapm_free(socdev); |
871 | pcm_err: | 871 | pcm_err: |
872 | kfree(codec->reg_cache); | ||
873 | return ret; | 872 | return ret; |
874 | } | 873 | } |
875 | 874 | ||
876 | /* If the i2c layer weren't so broken, we could pass this kind of data | 875 | /* power down chip */ |
877 | around */ | 876 | static int wm8580_remove(struct platform_device *pdev) |
878 | static struct snd_soc_device *wm8580_socdev; | 877 | { |
878 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
879 | 879 | ||
880 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 880 | snd_soc_free_pcms(socdev); |
881 | snd_soc_dapm_free(socdev); | ||
881 | 882 | ||
882 | /* | 883 | return 0; |
883 | * WM8580 2 wire address is determined by GPIO5 | 884 | } |
884 | * state during powerup. | 885 | |
885 | * low = 0x1a | 886 | struct snd_soc_codec_device soc_codec_dev_wm8580 = { |
886 | * high = 0x1b | 887 | .probe = wm8580_probe, |
887 | */ | 888 | .remove = wm8580_remove, |
889 | }; | ||
890 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580); | ||
891 | |||
892 | static int wm8580_register(struct wm8580_priv *wm8580) | ||
893 | { | ||
894 | int ret, i; | ||
895 | struct snd_soc_codec *codec = &wm8580->codec; | ||
896 | |||
897 | if (wm8580_codec) { | ||
898 | dev_err(codec->dev, "Another WM8580 is registered\n"); | ||
899 | ret = -EINVAL; | ||
900 | goto err; | ||
901 | } | ||
902 | |||
903 | mutex_init(&codec->mutex); | ||
904 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
905 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
906 | |||
907 | codec->private_data = wm8580; | ||
908 | codec->name = "WM8580"; | ||
909 | codec->owner = THIS_MODULE; | ||
910 | codec->read = wm8580_read_reg_cache; | ||
911 | codec->write = wm8580_write; | ||
912 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
913 | codec->set_bias_level = wm8580_set_bias_level; | ||
914 | codec->dai = wm8580_dai; | ||
915 | codec->num_dai = ARRAY_SIZE(wm8580_dai); | ||
916 | codec->reg_cache_size = ARRAY_SIZE(wm8580->reg_cache); | ||
917 | codec->reg_cache = &wm8580->reg_cache; | ||
918 | |||
919 | memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg)); | ||
920 | |||
921 | /* Get the codec into a known state */ | ||
922 | ret = wm8580_write(codec, WM8580_RESET, 0); | ||
923 | if (ret != 0) { | ||
924 | dev_err(codec->dev, "Failed to reset codec: %d\n", ret); | ||
925 | goto err; | ||
926 | } | ||
927 | |||
928 | for (i = 0; i < ARRAY_SIZE(wm8580_dai); i++) | ||
929 | wm8580_dai[i].dev = codec->dev; | ||
930 | |||
931 | wm8580_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
888 | 932 | ||
933 | wm8580_codec = codec; | ||
934 | |||
935 | ret = snd_soc_register_codec(codec); | ||
936 | if (ret != 0) { | ||
937 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
938 | goto err; | ||
939 | } | ||
940 | |||
941 | ret = snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); | ||
942 | if (ret != 0) { | ||
943 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
944 | goto err_codec; | ||
945 | } | ||
946 | |||
947 | return 0; | ||
948 | |||
949 | err_codec: | ||
950 | snd_soc_unregister_codec(codec); | ||
951 | err: | ||
952 | kfree(wm8580); | ||
953 | return ret; | ||
954 | } | ||
955 | |||
956 | static void wm8580_unregister(struct wm8580_priv *wm8580) | ||
957 | { | ||
958 | wm8580_set_bias_level(&wm8580->codec, SND_SOC_BIAS_OFF); | ||
959 | snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); | ||
960 | snd_soc_unregister_codec(&wm8580->codec); | ||
961 | kfree(wm8580); | ||
962 | wm8580_codec = NULL; | ||
963 | } | ||
964 | |||
965 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
889 | static int wm8580_i2c_probe(struct i2c_client *i2c, | 966 | static int wm8580_i2c_probe(struct i2c_client *i2c, |
890 | const struct i2c_device_id *id) | 967 | const struct i2c_device_id *id) |
891 | { | 968 | { |
892 | struct snd_soc_device *socdev = wm8580_socdev; | 969 | struct wm8580_priv *wm8580; |
893 | struct snd_soc_codec *codec = socdev->card->codec; | 970 | struct snd_soc_codec *codec; |
894 | int ret; | 971 | |
972 | wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL); | ||
973 | if (wm8580 == NULL) | ||
974 | return -ENOMEM; | ||
975 | |||
976 | codec = &wm8580->codec; | ||
977 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
895 | 978 | ||
896 | i2c_set_clientdata(i2c, codec); | 979 | i2c_set_clientdata(i2c, wm8580); |
897 | codec->control_data = i2c; | 980 | codec->control_data = i2c; |
898 | 981 | ||
899 | ret = wm8580_init(socdev); | 982 | codec->dev = &i2c->dev; |
900 | if (ret < 0) | 983 | |
901 | dev_err(&i2c->dev, "failed to initialise WM8580\n"); | 984 | return wm8580_register(wm8580); |
902 | return ret; | ||
903 | } | 985 | } |
904 | 986 | ||
905 | static int wm8580_i2c_remove(struct i2c_client *client) | 987 | static int wm8580_i2c_remove(struct i2c_client *client) |
906 | { | 988 | { |
907 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 989 | struct wm8580_priv *wm8580 = i2c_get_clientdata(client); |
908 | kfree(codec->reg_cache); | 990 | wm8580_unregister(wm8580); |
909 | return 0; | 991 | return 0; |
910 | } | 992 | } |
911 | 993 | ||
@@ -917,127 +999,35 @@ MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id); | |||
917 | 999 | ||
918 | static struct i2c_driver wm8580_i2c_driver = { | 1000 | static struct i2c_driver wm8580_i2c_driver = { |
919 | .driver = { | 1001 | .driver = { |
920 | .name = "WM8580 I2C Codec", | 1002 | .name = "wm8580", |
921 | .owner = THIS_MODULE, | 1003 | .owner = THIS_MODULE, |
922 | }, | 1004 | }, |
923 | .probe = wm8580_i2c_probe, | 1005 | .probe = wm8580_i2c_probe, |
924 | .remove = wm8580_i2c_remove, | 1006 | .remove = wm8580_i2c_remove, |
925 | .id_table = wm8580_i2c_id, | 1007 | .id_table = wm8580_i2c_id, |
926 | }; | 1008 | }; |
1009 | #endif | ||
927 | 1010 | ||
928 | static int wm8580_add_i2c_device(struct platform_device *pdev, | 1011 | static int __init wm8580_modinit(void) |
929 | const struct wm8580_setup_data *setup) | ||
930 | { | 1012 | { |
931 | struct i2c_board_info info; | ||
932 | struct i2c_adapter *adapter; | ||
933 | struct i2c_client *client; | ||
934 | int ret; | 1013 | int ret; |
935 | 1014 | ||
1015 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
936 | ret = i2c_add_driver(&wm8580_i2c_driver); | 1016 | ret = i2c_add_driver(&wm8580_i2c_driver); |
937 | if (ret != 0) { | 1017 | if (ret != 0) { |
938 | dev_err(&pdev->dev, "can't add i2c driver\n"); | 1018 | pr_err("Failed to register WM8580 I2C driver: %d\n", ret); |
939 | return ret; | ||
940 | } | ||
941 | |||
942 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
943 | info.addr = setup->i2c_address; | ||
944 | strlcpy(info.type, "wm8580", I2C_NAME_SIZE); | ||
945 | |||
946 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
947 | if (!adapter) { | ||
948 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
949 | setup->i2c_bus); | ||
950 | goto err_driver; | ||
951 | } | ||
952 | |||
953 | client = i2c_new_device(adapter, &info); | ||
954 | i2c_put_adapter(adapter); | ||
955 | if (!client) { | ||
956 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
957 | (unsigned int)info.addr); | ||
958 | goto err_driver; | ||
959 | } | ||
960 | |||
961 | return 0; | ||
962 | |||
963 | err_driver: | ||
964 | i2c_del_driver(&wm8580_i2c_driver); | ||
965 | return -ENODEV; | ||
966 | } | ||
967 | #endif | ||
968 | |||
969 | static int wm8580_probe(struct platform_device *pdev) | ||
970 | { | ||
971 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
972 | struct wm8580_setup_data *setup; | ||
973 | struct snd_soc_codec *codec; | ||
974 | struct wm8580_priv *wm8580; | ||
975 | int ret = 0; | ||
976 | |||
977 | setup = socdev->codec_data; | ||
978 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
979 | if (codec == NULL) | ||
980 | return -ENOMEM; | ||
981 | |||
982 | wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL); | ||
983 | if (wm8580 == NULL) { | ||
984 | kfree(codec); | ||
985 | return -ENOMEM; | ||
986 | } | 1019 | } |
987 | |||
988 | codec->private_data = wm8580; | ||
989 | socdev->card->codec = codec; | ||
990 | mutex_init(&codec->mutex); | ||
991 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
992 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
993 | wm8580_socdev = socdev; | ||
994 | |||
995 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
996 | if (setup->i2c_address) { | ||
997 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
998 | ret = wm8580_add_i2c_device(pdev, setup); | ||
999 | } | ||
1000 | #else | ||
1001 | /* Add other interfaces here */ | ||
1002 | #endif | ||
1003 | return ret; | ||
1004 | } | ||
1005 | |||
1006 | /* power down chip */ | ||
1007 | static int wm8580_remove(struct platform_device *pdev) | ||
1008 | { | ||
1009 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1010 | struct snd_soc_codec *codec = socdev->card->codec; | ||
1011 | |||
1012 | if (codec->control_data) | ||
1013 | wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1014 | snd_soc_free_pcms(socdev); | ||
1015 | snd_soc_dapm_free(socdev); | ||
1016 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1017 | i2c_unregister_device(codec->control_data); | ||
1018 | i2c_del_driver(&wm8580_i2c_driver); | ||
1019 | #endif | 1020 | #endif |
1020 | kfree(codec->private_data); | ||
1021 | kfree(codec); | ||
1022 | 1021 | ||
1023 | return 0; | 1022 | return 0; |
1024 | } | 1023 | } |
1025 | |||
1026 | struct snd_soc_codec_device soc_codec_dev_wm8580 = { | ||
1027 | .probe = wm8580_probe, | ||
1028 | .remove = wm8580_remove, | ||
1029 | }; | ||
1030 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580); | ||
1031 | |||
1032 | static int __init wm8580_modinit(void) | ||
1033 | { | ||
1034 | return snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); | ||
1035 | } | ||
1036 | module_init(wm8580_modinit); | 1024 | module_init(wm8580_modinit); |
1037 | 1025 | ||
1038 | static void __exit wm8580_exit(void) | 1026 | static void __exit wm8580_exit(void) |
1039 | { | 1027 | { |
1040 | snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); | 1028 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1029 | i2c_del_driver(&wm8580_i2c_driver); | ||
1030 | #endif | ||
1041 | } | 1031 | } |
1042 | module_exit(wm8580_exit); | 1032 | module_exit(wm8580_exit); |
1043 | 1033 | ||