diff options
Diffstat (limited to 'sound/soc/codecs/wm8978.c')
-rw-r--r-- | sound/soc/codecs/wm8978.c | 190 |
1 files changed, 55 insertions, 135 deletions
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index 8a1ad778e7e3..13b979a71a7c 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c | |||
@@ -31,8 +31,6 @@ | |||
31 | 31 | ||
32 | #include "wm8978.h" | 32 | #include "wm8978.h" |
33 | 33 | ||
34 | static struct snd_soc_codec *wm8978_codec; | ||
35 | |||
36 | /* wm8978 register cache. Note that register 0 is not included in the cache. */ | 34 | /* wm8978 register cache. Note that register 0 is not included in the cache. */ |
37 | static const u16 wm8978_reg[WM8978_CACHEREGNUM] = { | 35 | static const u16 wm8978_reg[WM8978_CACHEREGNUM] = { |
38 | 0x0000, 0x0000, 0x0000, 0x0000, /* 0x00...0x03 */ | 36 | 0x0000, 0x0000, 0x0000, 0x0000, /* 0x00...0x03 */ |
@@ -54,7 +52,8 @@ static const u16 wm8978_reg[WM8978_CACHEREGNUM] = { | |||
54 | 52 | ||
55 | /* codec private data */ | 53 | /* codec private data */ |
56 | struct wm8978_priv { | 54 | struct wm8978_priv { |
57 | struct snd_soc_codec codec; | 55 | enum snd_soc_control_type control_type; |
56 | void *control_data; | ||
58 | unsigned int f_pllout; | 57 | unsigned int f_pllout; |
59 | unsigned int f_mclk; | 58 | unsigned int f_mclk; |
60 | unsigned int f_256fs; | 59 | unsigned int f_256fs; |
@@ -374,8 +373,8 @@ struct wm8978_pll_div { | |||
374 | 373 | ||
375 | #define FIXED_PLL_SIZE (1 << 24) | 374 | #define FIXED_PLL_SIZE (1 << 24) |
376 | 375 | ||
377 | static void pll_factors(struct wm8978_pll_div *pll_div, unsigned int target, | 376 | static void pll_factors(struct snd_soc_codec *codec, |
378 | unsigned int source) | 377 | struct wm8978_pll_div *pll_div, unsigned int target, unsigned int source) |
379 | { | 378 | { |
380 | u64 k_part; | 379 | u64 k_part; |
381 | unsigned int k, n_div, n_mod; | 380 | unsigned int k, n_div, n_mod; |
@@ -390,7 +389,7 @@ static void pll_factors(struct wm8978_pll_div *pll_div, unsigned int target, | |||
390 | } | 389 | } |
391 | 390 | ||
392 | if (n_div < 6 || n_div > 12) | 391 | if (n_div < 6 || n_div > 12) |
393 | dev_warn(wm8978_codec->dev, | 392 | dev_warn(codec->dev, |
394 | "WM8978 N value exceeds recommended range! N = %u\n", | 393 | "WM8978 N value exceeds recommended range! N = %u\n", |
395 | n_div); | 394 | n_div); |
396 | 395 | ||
@@ -505,7 +504,7 @@ static int wm8978_configure_pll(struct snd_soc_codec *codec) | |||
505 | dev_dbg(codec->dev, "%s: f_MCLK=%uHz, f_PLLOUT=%uHz\n", __func__, | 504 | dev_dbg(codec->dev, "%s: f_MCLK=%uHz, f_PLLOUT=%uHz\n", __func__, |
506 | wm8978->f_mclk, wm8978->f_pllout); | 505 | wm8978->f_mclk, wm8978->f_pllout); |
507 | 506 | ||
508 | pll_factors(&pll_div, f2, wm8978->f_mclk); | 507 | pll_factors(codec, &pll_div, f2, wm8978->f_mclk); |
509 | 508 | ||
510 | dev_dbg(codec->dev, "%s: calculated PLL N=0x%x, K=0x%x, div2=%d\n", | 509 | dev_dbg(codec->dev, "%s: calculated PLL N=0x%x, K=0x%x, div2=%d\n", |
511 | __func__, pll_div.n, pll_div.k, pll_div.div2); | 510 | __func__, pll_div.n, pll_div.k, pll_div.div2); |
@@ -690,8 +689,7 @@ static int wm8978_hw_params(struct snd_pcm_substream *substream, | |||
690 | struct snd_soc_dai *dai) | 689 | struct snd_soc_dai *dai) |
691 | { | 690 | { |
692 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 691 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
693 | struct snd_soc_device *socdev = rtd->socdev; | 692 | struct snd_soc_codec *codec = rtd->codec; |
694 | struct snd_soc_codec *codec = socdev->card->codec; | ||
695 | struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec); | 693 | struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec); |
696 | /* Word length mask = 0x60 */ | 694 | /* Word length mask = 0x60 */ |
697 | u16 iface_ctl = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x60; | 695 | u16 iface_ctl = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x60; |
@@ -875,9 +873,8 @@ static struct snd_soc_dai_ops wm8978_dai_ops = { | |||
875 | }; | 873 | }; |
876 | 874 | ||
877 | /* Also supports 12kHz */ | 875 | /* Also supports 12kHz */ |
878 | struct snd_soc_dai wm8978_dai = { | 876 | static struct snd_soc_dai_driver wm8978_dai = { |
879 | .name = "WM8978 HiFi", | 877 | .name = "wm8978-hifi", |
880 | .id = 1, | ||
881 | .playback = { | 878 | .playback = { |
882 | .stream_name = "Playback", | 879 | .stream_name = "Playback", |
883 | .channels_min = 1, | 880 | .channels_min = 1, |
@@ -894,13 +891,9 @@ struct snd_soc_dai wm8978_dai = { | |||
894 | }, | 891 | }, |
895 | .ops = &wm8978_dai_ops, | 892 | .ops = &wm8978_dai_ops, |
896 | }; | 893 | }; |
897 | EXPORT_SYMBOL_GPL(wm8978_dai); | ||
898 | 894 | ||
899 | static int wm8978_suspend(struct platform_device *pdev, pm_message_t state) | 895 | static int wm8978_suspend(struct snd_soc_codec *codec, pm_message_t state) |
900 | { | 896 | { |
901 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
902 | struct snd_soc_codec *codec = socdev->card->codec; | ||
903 | |||
904 | wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF); | 897 | wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF); |
905 | /* Also switch PLL off */ | 898 | /* Also switch PLL off */ |
906 | snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, 0); | 899 | snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, 0); |
@@ -908,10 +901,8 @@ static int wm8978_suspend(struct platform_device *pdev, pm_message_t state) | |||
908 | return 0; | 901 | return 0; |
909 | } | 902 | } |
910 | 903 | ||
911 | static int wm8978_resume(struct platform_device *pdev) | 904 | static int wm8978_resume(struct snd_soc_codec *codec) |
912 | { | 905 | { |
913 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
914 | struct snd_soc_codec *codec = socdev->card->codec; | ||
915 | struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec); | 906 | struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec); |
916 | int i; | 907 | int i; |
917 | u16 *cache = codec->reg_cache; | 908 | u16 *cache = codec->reg_cache; |
@@ -933,54 +924,6 @@ static int wm8978_resume(struct platform_device *pdev) | |||
933 | return 0; | 924 | return 0; |
934 | } | 925 | } |
935 | 926 | ||
936 | static int wm8978_probe(struct platform_device *pdev) | ||
937 | { | ||
938 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
939 | struct snd_soc_codec *codec; | ||
940 | int ret = 0; | ||
941 | |||
942 | if (wm8978_codec == NULL) { | ||
943 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
944 | return -ENODEV; | ||
945 | } | ||
946 | |||
947 | socdev->card->codec = wm8978_codec; | ||
948 | codec = wm8978_codec; | ||
949 | |||
950 | /* register pcms */ | ||
951 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
952 | if (ret < 0) { | ||
953 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
954 | goto pcm_err; | ||
955 | } | ||
956 | |||
957 | snd_soc_add_controls(codec, wm8978_snd_controls, | ||
958 | ARRAY_SIZE(wm8978_snd_controls)); | ||
959 | wm8978_add_widgets(codec); | ||
960 | |||
961 | pcm_err: | ||
962 | return ret; | ||
963 | } | ||
964 | |||
965 | /* power down chip */ | ||
966 | static int wm8978_remove(struct platform_device *pdev) | ||
967 | { | ||
968 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
969 | |||
970 | snd_soc_free_pcms(socdev); | ||
971 | snd_soc_dapm_free(socdev); | ||
972 | |||
973 | return 0; | ||
974 | } | ||
975 | |||
976 | struct snd_soc_codec_device soc_codec_dev_wm8978 = { | ||
977 | .probe = wm8978_probe, | ||
978 | .remove = wm8978_remove, | ||
979 | .suspend = wm8978_suspend, | ||
980 | .resume = wm8978_resume, | ||
981 | }; | ||
982 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8978); | ||
983 | |||
984 | /* | 927 | /* |
985 | * These registers contain an "update" bit - bit 8. This means, for example, | 928 | * These registers contain an "update" bit - bit 8. This means, for example, |
986 | * that one can write new DAC digital volume for both channels, but only when | 929 | * that one can write new DAC digital volume for both channels, but only when |
@@ -1000,44 +943,23 @@ static const int update_reg[] = { | |||
1000 | WM8978_ROUT2_SPK_CONTROL, | 943 | WM8978_ROUT2_SPK_CONTROL, |
1001 | }; | 944 | }; |
1002 | 945 | ||
1003 | static __devinit int wm8978_register(struct wm8978_priv *wm8978) | 946 | static int wm8978_probe(struct snd_soc_codec *codec) |
1004 | { | 947 | { |
1005 | int ret, i; | 948 | struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec); |
1006 | struct snd_soc_codec *codec = &wm8978->codec; | 949 | int ret = 0, i; |
1007 | |||
1008 | if (wm8978_codec) { | ||
1009 | dev_err(codec->dev, "Another WM8978 is registered\n"); | ||
1010 | return -EINVAL; | ||
1011 | } | ||
1012 | 950 | ||
1013 | /* | 951 | /* |
1014 | * Set default system clock to PLL, it is more precise, this is also the | 952 | * Set default system clock to PLL, it is more precise, this is also the |
1015 | * default hardware setting | 953 | * default hardware setting |
1016 | */ | 954 | */ |
1017 | wm8978->sysclk = WM8978_PLL; | 955 | wm8978->sysclk = WM8978_PLL; |
1018 | 956 | codec->control_data = wm8978->control_data; | |
1019 | mutex_init(&codec->mutex); | ||
1020 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1021 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1022 | |||
1023 | snd_soc_codec_set_drvdata(codec, wm8978); | ||
1024 | codec->name = "WM8978"; | ||
1025 | codec->owner = THIS_MODULE; | ||
1026 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
1027 | codec->set_bias_level = wm8978_set_bias_level; | ||
1028 | codec->dai = &wm8978_dai; | ||
1029 | codec->num_dai = 1; | ||
1030 | codec->reg_cache_size = WM8978_CACHEREGNUM; | ||
1031 | codec->reg_cache = &wm8978->reg_cache; | ||
1032 | |||
1033 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C); | 957 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C); |
1034 | if (ret < 0) { | 958 | if (ret < 0) { |
1035 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 959 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
1036 | goto err; | 960 | return ret; |
1037 | } | 961 | } |
1038 | 962 | ||
1039 | memcpy(codec->reg_cache, wm8978_reg, sizeof(wm8978_reg)); | ||
1040 | |||
1041 | /* | 963 | /* |
1042 | * Set the update bit in all registers, that have one. This way all | 964 | * Set the update bit in all registers, that have one. This way all |
1043 | * writes to those registers will also cause the update bit to be | 965 | * writes to those registers will also cause the update bit to be |
@@ -1050,74 +972,61 @@ static __devinit int wm8978_register(struct wm8978_priv *wm8978) | |||
1050 | ret = snd_soc_write(codec, WM8978_RESET, 0); | 972 | ret = snd_soc_write(codec, WM8978_RESET, 0); |
1051 | if (ret < 0) { | 973 | if (ret < 0) { |
1052 | dev_err(codec->dev, "Failed to issue reset\n"); | 974 | dev_err(codec->dev, "Failed to issue reset\n"); |
1053 | goto err; | 975 | return ret; |
1054 | } | 976 | } |
1055 | 977 | ||
1056 | wm8978_dai.dev = codec->dev; | ||
1057 | |||
1058 | wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 978 | wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1059 | 979 | ||
1060 | wm8978_codec = codec; | 980 | snd_soc_add_controls(codec, wm8978_snd_controls, |
1061 | 981 | ARRAY_SIZE(wm8978_snd_controls)); | |
1062 | ret = snd_soc_register_codec(codec); | 982 | wm8978_add_widgets(codec); |
1063 | if (ret != 0) { | ||
1064 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
1065 | goto err; | ||
1066 | } | ||
1067 | |||
1068 | ret = snd_soc_register_dai(&wm8978_dai); | ||
1069 | if (ret != 0) { | ||
1070 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
1071 | goto err_codec; | ||
1072 | } | ||
1073 | 983 | ||
1074 | return 0; | 984 | return 0; |
1075 | |||
1076 | err_codec: | ||
1077 | snd_soc_unregister_codec(codec); | ||
1078 | err: | ||
1079 | return ret; | ||
1080 | } | 985 | } |
1081 | 986 | ||
1082 | static __devexit void wm8978_unregister(struct wm8978_priv *wm8978) | 987 | /* power down chip */ |
988 | static int wm8978_remove(struct snd_soc_codec *codec) | ||
1083 | { | 989 | { |
1084 | wm8978_set_bias_level(&wm8978->codec, SND_SOC_BIAS_OFF); | 990 | wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1085 | snd_soc_unregister_dai(&wm8978_dai); | 991 | return 0; |
1086 | snd_soc_unregister_codec(&wm8978->codec); | ||
1087 | wm8978_codec = NULL; | ||
1088 | } | 992 | } |
1089 | 993 | ||
994 | static struct snd_soc_codec_driver soc_codec_dev_wm8978 = { | ||
995 | .probe = wm8978_probe, | ||
996 | .remove = wm8978_remove, | ||
997 | .suspend = wm8978_suspend, | ||
998 | .resume = wm8978_resume, | ||
999 | .set_bias_level = wm8978_set_bias_level, | ||
1000 | .reg_cache_size = ARRAY_SIZE(wm8978_reg), | ||
1001 | .reg_word_size = sizeof(u16), | ||
1002 | .reg_cache_default = wm8978_reg, | ||
1003 | }; | ||
1004 | |||
1005 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1090 | static __devinit int wm8978_i2c_probe(struct i2c_client *i2c, | 1006 | static __devinit int wm8978_i2c_probe(struct i2c_client *i2c, |
1091 | const struct i2c_device_id *id) | 1007 | const struct i2c_device_id *id) |
1092 | { | 1008 | { |
1093 | int ret; | ||
1094 | struct wm8978_priv *wm8978; | 1009 | struct wm8978_priv *wm8978; |
1095 | struct snd_soc_codec *codec; | 1010 | int ret; |
1096 | 1011 | ||
1097 | wm8978 = kzalloc(sizeof(struct wm8978_priv), GFP_KERNEL); | 1012 | wm8978 = kzalloc(sizeof(struct wm8978_priv), GFP_KERNEL); |
1098 | if (wm8978 == NULL) | 1013 | if (wm8978 == NULL) |
1099 | return -ENOMEM; | 1014 | return -ENOMEM; |
1100 | 1015 | ||
1101 | codec = &wm8978->codec; | ||
1102 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1103 | |||
1104 | i2c_set_clientdata(i2c, wm8978); | 1016 | i2c_set_clientdata(i2c, wm8978); |
1105 | codec->control_data = i2c; | 1017 | wm8978->control_data = i2c; |
1106 | |||
1107 | codec->dev = &i2c->dev; | ||
1108 | 1018 | ||
1109 | ret = wm8978_register(wm8978); | 1019 | ret = snd_soc_register_codec(&i2c->dev, |
1020 | &soc_codec_dev_wm8978, &wm8978_dai, 1); | ||
1110 | if (ret < 0) | 1021 | if (ret < 0) |
1111 | kfree(wm8978); | 1022 | kfree(wm8978); |
1112 | |||
1113 | return ret; | 1023 | return ret; |
1114 | } | 1024 | } |
1115 | 1025 | ||
1116 | static __devexit int wm8978_i2c_remove(struct i2c_client *client) | 1026 | static __devexit int wm8978_i2c_remove(struct i2c_client *client) |
1117 | { | 1027 | { |
1118 | struct wm8978_priv *wm8978 = i2c_get_clientdata(client); | 1028 | snd_soc_unregister_codec(&client->dev); |
1119 | wm8978_unregister(wm8978); | 1029 | kfree(i2c_get_clientdata(client)); |
1120 | kfree(wm8978); | ||
1121 | return 0; | 1030 | return 0; |
1122 | } | 1031 | } |
1123 | 1032 | ||
@@ -1129,23 +1038,34 @@ MODULE_DEVICE_TABLE(i2c, wm8978_i2c_id); | |||
1129 | 1038 | ||
1130 | static struct i2c_driver wm8978_i2c_driver = { | 1039 | static struct i2c_driver wm8978_i2c_driver = { |
1131 | .driver = { | 1040 | .driver = { |
1132 | .name = "WM8978", | 1041 | .name = "wm8978", |
1133 | .owner = THIS_MODULE, | 1042 | .owner = THIS_MODULE, |
1134 | }, | 1043 | }, |
1135 | .probe = wm8978_i2c_probe, | 1044 | .probe = wm8978_i2c_probe, |
1136 | .remove = __devexit_p(wm8978_i2c_remove), | 1045 | .remove = __devexit_p(wm8978_i2c_remove), |
1137 | .id_table = wm8978_i2c_id, | 1046 | .id_table = wm8978_i2c_id, |
1138 | }; | 1047 | }; |
1048 | #endif | ||
1139 | 1049 | ||
1140 | static int __init wm8978_modinit(void) | 1050 | static int __init wm8978_modinit(void) |
1141 | { | 1051 | { |
1142 | return i2c_add_driver(&wm8978_i2c_driver); | 1052 | int ret = 0; |
1053 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1054 | ret = i2c_add_driver(&wm8978_i2c_driver); | ||
1055 | if (ret != 0) { | ||
1056 | printk(KERN_ERR "Failed to register WM8978 I2C driver: %d\n", | ||
1057 | ret); | ||
1058 | } | ||
1059 | #endif | ||
1060 | return ret; | ||
1143 | } | 1061 | } |
1144 | module_init(wm8978_modinit); | 1062 | module_init(wm8978_modinit); |
1145 | 1063 | ||
1146 | static void __exit wm8978_exit(void) | 1064 | static void __exit wm8978_exit(void) |
1147 | { | 1065 | { |
1066 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1148 | i2c_del_driver(&wm8978_i2c_driver); | 1067 | i2c_del_driver(&wm8978_i2c_driver); |
1068 | #endif | ||
1149 | } | 1069 | } |
1150 | module_exit(wm8978_exit); | 1070 | module_exit(wm8978_exit); |
1151 | 1071 | ||