diff options
Diffstat (limited to 'sound/soc/codecs/wm8955.c')
-rw-r--r-- | sound/soc/codecs/wm8955.c | 181 |
1 files changed, 44 insertions, 137 deletions
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 5f025593d84d..f89ad6c9a80b 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c | |||
@@ -30,9 +30,6 @@ | |||
30 | 30 | ||
31 | #include "wm8955.h" | 31 | #include "wm8955.h" |
32 | 32 | ||
33 | static struct snd_soc_codec *wm8955_codec; | ||
34 | struct snd_soc_codec_device soc_codec_dev_wm8955; | ||
35 | |||
36 | #define WM8955_NUM_SUPPLIES 4 | 33 | #define WM8955_NUM_SUPPLIES 4 |
37 | static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = { | 34 | static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = { |
38 | "DCVDD", | 35 | "DCVDD", |
@@ -43,7 +40,8 @@ static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = { | |||
43 | 40 | ||
44 | /* codec private data */ | 41 | /* codec private data */ |
45 | struct wm8955_priv { | 42 | struct wm8955_priv { |
46 | struct snd_soc_codec codec; | 43 | enum snd_soc_control_type control_type; |
44 | |||
47 | u16 reg_cache[WM8955_MAX_REGISTER + 1]; | 45 | u16 reg_cache[WM8955_MAX_REGISTER + 1]; |
48 | 46 | ||
49 | unsigned int mclk_rate; | 47 | unsigned int mclk_rate; |
@@ -52,8 +50,6 @@ struct wm8955_priv { | |||
52 | int fs; | 50 | int fs; |
53 | 51 | ||
54 | struct regulator_bulk_data supplies[WM8955_NUM_SUPPLIES]; | 52 | struct regulator_bulk_data supplies[WM8955_NUM_SUPPLIES]; |
55 | |||
56 | struct wm8955_pdata *pdata; | ||
57 | }; | 53 | }; |
58 | 54 | ||
59 | static const u16 wm8955_reg[WM8955_MAX_REGISTER + 1] = { | 55 | static const u16 wm8955_reg[WM8955_MAX_REGISTER + 1] = { |
@@ -870,8 +866,8 @@ static struct snd_soc_dai_ops wm8955_dai_ops = { | |||
870 | .digital_mute = wm8955_digital_mute, | 866 | .digital_mute = wm8955_digital_mute, |
871 | }; | 867 | }; |
872 | 868 | ||
873 | struct snd_soc_dai wm8955_dai = { | 869 | static struct snd_soc_dai_driver wm8955_dai = { |
874 | .name = "WM8955", | 870 | .name = "wm8955-hifi", |
875 | .playback = { | 871 | .playback = { |
876 | .stream_name = "Playback", | 872 | .stream_name = "Playback", |
877 | .channels_min = 2, | 873 | .channels_min = 2, |
@@ -881,24 +877,17 @@ struct snd_soc_dai wm8955_dai = { | |||
881 | }, | 877 | }, |
882 | .ops = &wm8955_dai_ops, | 878 | .ops = &wm8955_dai_ops, |
883 | }; | 879 | }; |
884 | EXPORT_SYMBOL_GPL(wm8955_dai); | ||
885 | 880 | ||
886 | #ifdef CONFIG_PM | 881 | #ifdef CONFIG_PM |
887 | static int wm8955_suspend(struct platform_device *pdev, pm_message_t state) | 882 | static int wm8955_suspend(struct snd_soc_codec *codec, pm_message_t state) |
888 | { | 883 | { |
889 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
890 | struct snd_soc_codec *codec = socdev->card->codec; | ||
891 | |||
892 | wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF); | 884 | wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF); |
893 | 885 | ||
894 | return 0; | 886 | return 0; |
895 | } | 887 | } |
896 | 888 | ||
897 | static int wm8955_resume(struct platform_device *pdev) | 889 | static int wm8955_resume(struct snd_soc_codec *codec) |
898 | { | 890 | { |
899 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
900 | struct snd_soc_codec *codec = socdev->card->codec; | ||
901 | |||
902 | wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 891 | wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
903 | 892 | ||
904 | return 0; | 893 | return 0; |
@@ -908,86 +897,16 @@ static int wm8955_resume(struct platform_device *pdev) | |||
908 | #define wm8955_resume NULL | 897 | #define wm8955_resume NULL |
909 | #endif | 898 | #endif |
910 | 899 | ||
911 | static int wm8955_probe(struct platform_device *pdev) | 900 | static int wm8955_probe(struct snd_soc_codec *codec) |
912 | { | ||
913 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
914 | struct snd_soc_codec *codec; | ||
915 | int ret = 0; | ||
916 | |||
917 | if (wm8955_codec == NULL) { | ||
918 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
919 | return -ENODEV; | ||
920 | } | ||
921 | |||
922 | socdev->card->codec = wm8955_codec; | ||
923 | codec = wm8955_codec; | ||
924 | |||
925 | /* register pcms */ | ||
926 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
927 | if (ret < 0) { | ||
928 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
929 | goto pcm_err; | ||
930 | } | ||
931 | |||
932 | wm8955_add_widgets(codec); | ||
933 | |||
934 | return ret; | ||
935 | |||
936 | pcm_err: | ||
937 | return ret; | ||
938 | } | ||
939 | |||
940 | static int wm8955_remove(struct platform_device *pdev) | ||
941 | { | 901 | { |
942 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 902 | struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); |
943 | 903 | struct wm8955_pdata *pdata = dev_get_platdata(codec->dev); | |
944 | snd_soc_free_pcms(socdev); | 904 | int ret, i; |
945 | snd_soc_dapm_free(socdev); | ||
946 | |||
947 | return 0; | ||
948 | } | ||
949 | |||
950 | struct snd_soc_codec_device soc_codec_dev_wm8955 = { | ||
951 | .probe = wm8955_probe, | ||
952 | .remove = wm8955_remove, | ||
953 | .suspend = wm8955_suspend, | ||
954 | .resume = wm8955_resume, | ||
955 | }; | ||
956 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8955); | ||
957 | |||
958 | static int wm8955_register(struct wm8955_priv *wm8955, | ||
959 | enum snd_soc_control_type control) | ||
960 | { | ||
961 | int ret; | ||
962 | struct snd_soc_codec *codec = &wm8955->codec; | ||
963 | int i; | ||
964 | |||
965 | if (wm8955_codec) { | ||
966 | dev_err(codec->dev, "Another WM8955 is registered\n"); | ||
967 | ret = -EINVAL; | ||
968 | goto err; | ||
969 | } | ||
970 | |||
971 | mutex_init(&codec->mutex); | ||
972 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
973 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
974 | |||
975 | snd_soc_codec_set_drvdata(codec, wm8955); | ||
976 | codec->name = "WM8955"; | ||
977 | codec->owner = THIS_MODULE; | ||
978 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
979 | codec->set_bias_level = wm8955_set_bias_level; | ||
980 | codec->dai = &wm8955_dai; | ||
981 | codec->num_dai = 1; | ||
982 | codec->reg_cache_size = WM8955_MAX_REGISTER; | ||
983 | codec->reg_cache = &wm8955->reg_cache; | ||
984 | |||
985 | memcpy(codec->reg_cache, wm8955_reg, sizeof(wm8955_reg)); | ||
986 | 905 | ||
987 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); | 906 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8955->control_type); |
988 | if (ret != 0) { | 907 | if (ret != 0) { |
989 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 908 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
990 | goto err; | 909 | return ret; |
991 | } | 910 | } |
992 | 911 | ||
993 | for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++) | 912 | for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++) |
@@ -997,7 +916,7 @@ static int wm8955_register(struct wm8955_priv *wm8955, | |||
997 | wm8955->supplies); | 916 | wm8955->supplies); |
998 | if (ret != 0) { | 917 | if (ret != 0) { |
999 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | 918 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); |
1000 | goto err; | 919 | return ret; |
1001 | } | 920 | } |
1002 | 921 | ||
1003 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies), | 922 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies), |
@@ -1013,8 +932,6 @@ static int wm8955_register(struct wm8955_priv *wm8955, | |||
1013 | goto err_enable; | 932 | goto err_enable; |
1014 | } | 933 | } |
1015 | 934 | ||
1016 | wm8955_dai.dev = codec->dev; | ||
1017 | |||
1018 | /* Change some default settings - latch VU and enable ZC */ | 935 | /* Change some default settings - latch VU and enable ZC */ |
1019 | wm8955->reg_cache[WM8955_LEFT_DAC_VOLUME] |= WM8955_LDVU; | 936 | wm8955->reg_cache[WM8955_LEFT_DAC_VOLUME] |= WM8955_LDVU; |
1020 | wm8955->reg_cache[WM8955_RIGHT_DAC_VOLUME] |= WM8955_RDVU; | 937 | wm8955->reg_cache[WM8955_RIGHT_DAC_VOLUME] |= WM8955_RDVU; |
@@ -1028,12 +945,12 @@ static int wm8955_register(struct wm8955_priv *wm8955, | |||
1028 | wm8955->reg_cache[WM8955_BASS_CONTROL] |= WM8955_BB; | 945 | wm8955->reg_cache[WM8955_BASS_CONTROL] |= WM8955_BB; |
1029 | 946 | ||
1030 | /* Set platform data values */ | 947 | /* Set platform data values */ |
1031 | if (wm8955->pdata) { | 948 | if (pdata) { |
1032 | if (wm8955->pdata->out2_speaker) | 949 | if (pdata->out2_speaker) |
1033 | wm8955->reg_cache[WM8955_ADDITIONAL_CONTROL_2] | 950 | wm8955->reg_cache[WM8955_ADDITIONAL_CONTROL_2] |
1034 | |= WM8955_ROUT2INV; | 951 | |= WM8955_ROUT2INV; |
1035 | 952 | ||
1036 | if (wm8955->pdata->monoin_diff) | 953 | if (pdata->monoin_diff) |
1037 | wm8955->reg_cache[WM8955_MONO_OUT_MIX_1] | 954 | wm8955->reg_cache[WM8955_MONO_OUT_MIX_1] |
1038 | |= WM8955_DMEN; | 955 | |= WM8955_DMEN; |
1039 | } | 956 | } |
@@ -1043,70 +960,60 @@ static int wm8955_register(struct wm8955_priv *wm8955, | |||
1043 | /* Bias level configuration will have done an extra enable */ | 960 | /* Bias level configuration will have done an extra enable */ |
1044 | regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); | 961 | regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); |
1045 | 962 | ||
1046 | wm8955_codec = codec; | 963 | wm8955_add_widgets(codec); |
1047 | |||
1048 | ret = snd_soc_register_codec(codec); | ||
1049 | if (ret != 0) { | ||
1050 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
1051 | goto err_enable; | ||
1052 | } | ||
1053 | |||
1054 | ret = snd_soc_register_dai(&wm8955_dai); | ||
1055 | if (ret != 0) { | ||
1056 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
1057 | goto err_codec; | ||
1058 | } | ||
1059 | |||
1060 | return 0; | 964 | return 0; |
1061 | 965 | ||
1062 | err_codec: | ||
1063 | snd_soc_unregister_codec(codec); | ||
1064 | err_enable: | 966 | err_enable: |
1065 | regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); | 967 | regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); |
1066 | err_get: | 968 | err_get: |
1067 | regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); | 969 | regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); |
1068 | err: | ||
1069 | kfree(wm8955); | ||
1070 | return ret; | 970 | return ret; |
1071 | } | 971 | } |
1072 | 972 | ||
1073 | static void wm8955_unregister(struct wm8955_priv *wm8955) | 973 | static int wm8955_remove(struct snd_soc_codec *codec) |
1074 | { | 974 | { |
1075 | wm8955_set_bias_level(&wm8955->codec, SND_SOC_BIAS_OFF); | 975 | struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); |
976 | |||
977 | wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1076 | regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); | 978 | regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); |
1077 | snd_soc_unregister_dai(&wm8955_dai); | 979 | return 0; |
1078 | snd_soc_unregister_codec(&wm8955->codec); | ||
1079 | kfree(wm8955); | ||
1080 | wm8955_codec = NULL; | ||
1081 | } | 980 | } |
1082 | 981 | ||
982 | static struct snd_soc_codec_driver soc_codec_dev_wm8955 = { | ||
983 | .probe = wm8955_probe, | ||
984 | .remove = wm8955_remove, | ||
985 | .suspend = wm8955_suspend, | ||
986 | .resume = wm8955_resume, | ||
987 | .set_bias_level = wm8955_set_bias_level, | ||
988 | .reg_cache_size = ARRAY_SIZE(wm8955_reg), | ||
989 | .reg_word_size = sizeof(u16), | ||
990 | .reg_cache_default = wm8955_reg, | ||
991 | }; | ||
992 | |||
1083 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 993 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1084 | static __devinit int wm8955_i2c_probe(struct i2c_client *i2c, | 994 | static __devinit int wm8955_i2c_probe(struct i2c_client *i2c, |
1085 | const struct i2c_device_id *id) | 995 | const struct i2c_device_id *id) |
1086 | { | 996 | { |
1087 | struct wm8955_priv *wm8955; | 997 | struct wm8955_priv *wm8955; |
1088 | struct snd_soc_codec *codec; | 998 | int ret; |
1089 | 999 | ||
1090 | wm8955 = kzalloc(sizeof(struct wm8955_priv), GFP_KERNEL); | 1000 | wm8955 = kzalloc(sizeof(struct wm8955_priv), GFP_KERNEL); |
1091 | if (wm8955 == NULL) | 1001 | if (wm8955 == NULL) |
1092 | return -ENOMEM; | 1002 | return -ENOMEM; |
1093 | 1003 | ||
1094 | codec = &wm8955->codec; | ||
1095 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1096 | |||
1097 | i2c_set_clientdata(i2c, wm8955); | 1004 | i2c_set_clientdata(i2c, wm8955); |
1098 | codec->control_data = i2c; | ||
1099 | wm8955->pdata = i2c->dev.platform_data; | ||
1100 | |||
1101 | codec->dev = &i2c->dev; | ||
1102 | 1005 | ||
1103 | return wm8955_register(wm8955, SND_SOC_I2C); | 1006 | ret = snd_soc_register_codec(&i2c->dev, |
1007 | &soc_codec_dev_wm8955, &wm8955_dai, 1); | ||
1008 | if (ret < 0) | ||
1009 | kfree(wm8955); | ||
1010 | return ret; | ||
1104 | } | 1011 | } |
1105 | 1012 | ||
1106 | static __devexit int wm8955_i2c_remove(struct i2c_client *client) | 1013 | static __devexit int wm8955_i2c_remove(struct i2c_client *client) |
1107 | { | 1014 | { |
1108 | struct wm8955_priv *wm8955 = i2c_get_clientdata(client); | 1015 | snd_soc_unregister_codec(&client->dev); |
1109 | wm8955_unregister(wm8955); | 1016 | kfree(i2c_get_clientdata(client)); |
1110 | return 0; | 1017 | return 0; |
1111 | } | 1018 | } |
1112 | 1019 | ||
@@ -1118,7 +1025,7 @@ MODULE_DEVICE_TABLE(i2c, wm8955_i2c_id); | |||
1118 | 1025 | ||
1119 | static struct i2c_driver wm8955_i2c_driver = { | 1026 | static struct i2c_driver wm8955_i2c_driver = { |
1120 | .driver = { | 1027 | .driver = { |
1121 | .name = "wm8955", | 1028 | .name = "wm8955-codec", |
1122 | .owner = THIS_MODULE, | 1029 | .owner = THIS_MODULE, |
1123 | }, | 1030 | }, |
1124 | .probe = wm8955_i2c_probe, | 1031 | .probe = wm8955_i2c_probe, |
@@ -1129,7 +1036,7 @@ static struct i2c_driver wm8955_i2c_driver = { | |||
1129 | 1036 | ||
1130 | static int __init wm8955_modinit(void) | 1037 | static int __init wm8955_modinit(void) |
1131 | { | 1038 | { |
1132 | int ret; | 1039 | int ret = 0; |
1133 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1040 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1134 | ret = i2c_add_driver(&wm8955_i2c_driver); | 1041 | ret = i2c_add_driver(&wm8955_i2c_driver); |
1135 | if (ret != 0) { | 1042 | if (ret != 0) { |
@@ -1137,7 +1044,7 @@ static int __init wm8955_modinit(void) | |||
1137 | ret); | 1044 | ret); |
1138 | } | 1045 | } |
1139 | #endif | 1046 | #endif |
1140 | return 0; | 1047 | return ret; |
1141 | } | 1048 | } |
1142 | module_init(wm8955_modinit); | 1049 | module_init(wm8955_modinit); |
1143 | 1050 | ||