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