aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2009-03-11 14:31:08 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-03-12 11:43:24 -0400
commit6f7cb44ba1a5195bf719f9ba1d57bd79e13262c1 (patch)
treee4fa9eac36aacabe6bf9b362d787342988264feb /sound/soc
parent2a9f0ba7a976bc2b1bcf9156c1e57ffbc8f8fb64 (diff)
ASoC: Move WM8580 to normal I2C device probe
Refactor the WM8580 device registration to probe via standard I2C device registration, registering the DAIs once the device has probed via I2C. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/codecs/wm8580.c326
-rw-r--r--sound/soc/codecs/wm8580.h5
2 files changed, 158 insertions, 173 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
38struct pll_state {
39 unsigned int in;
40 unsigned int out;
41};
42
43/* codec private data */
44struct 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
185struct pll_state {
186 unsigned int in;
187 unsigned int out;
188};
189
190/* codec private data */
191struct 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};
813EXPORT_SYMBOL_GPL(wm8580_dai); 832EXPORT_SYMBOL_GPL(wm8580_dai);
814 833
815/* 834static struct snd_soc_codec *wm8580_codec;
816 * initialise the WM8580 driver 835
817 * register the mixer and dsp interfaces with the kernel 836static int wm8580_probe(struct platform_device *pdev)
818 */
819static 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
868card_err: 868card_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);
871pcm_err: 871pcm_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 */ 876static int wm8580_remove(struct platform_device *pdev)
878static 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 886struct snd_soc_codec_device soc_codec_dev_wm8580 = {
886 * high = 0x1b 887 .probe = wm8580_probe,
887 */ 888 .remove = wm8580_remove,
889};
890EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580);
891
892static 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
949err_codec:
950 snd_soc_unregister_codec(codec);
951err:
952 kfree(wm8580);
953 return ret;
954}
955
956static 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)
889static int wm8580_i2c_probe(struct i2c_client *i2c, 966static 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
905static int wm8580_i2c_remove(struct i2c_client *client) 987static 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
918static struct i2c_driver wm8580_i2c_driver = { 1000static 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
928static int wm8580_add_i2c_device(struct platform_device *pdev, 1011static 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
963err_driver:
964 i2c_del_driver(&wm8580_i2c_driver);
965 return -ENODEV;
966}
967#endif
968
969static 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 */
1007static 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
1026struct snd_soc_codec_device soc_codec_dev_wm8580 = {
1027 .probe = wm8580_probe,
1028 .remove = wm8580_remove,
1029};
1030EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580);
1031
1032static int __init wm8580_modinit(void)
1033{
1034 return snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
1035}
1036module_init(wm8580_modinit); 1024module_init(wm8580_modinit);
1037 1025
1038static void __exit wm8580_exit(void) 1026static 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}
1042module_exit(wm8580_exit); 1032module_exit(wm8580_exit);
1043 1033
diff --git a/sound/soc/codecs/wm8580.h b/sound/soc/codecs/wm8580.h
index 09e4422f6f2f..0dfb5ddde6a2 100644
--- a/sound/soc/codecs/wm8580.h
+++ b/sound/soc/codecs/wm8580.h
@@ -28,11 +28,6 @@
28#define WM8580_CLKSRC_OSC 4 28#define WM8580_CLKSRC_OSC 4
29#define WM8580_CLKSRC_NONE 5 29#define WM8580_CLKSRC_NONE 5
30 30
31struct wm8580_setup_data {
32 int i2c_bus;
33 unsigned short i2c_address;
34};
35
36#define WM8580_DAI_PAIFRX 0 31#define WM8580_DAI_PAIFRX 0
37#define WM8580_DAI_PAIFTX 1 32#define WM8580_DAI_PAIFTX 1
38 33