aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8978.c
diff options
context:
space:
mode:
authorLiam Girdwood <lrg@slimlogic.co.uk>2010-03-17 16:15:21 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-08-12 09:00:00 -0400
commitf0fba2ad1b6b53d5360125c41953b7afcd6deff0 (patch)
treef6ad50905f8daa616593c978d7ae992e73241180 /sound/soc/codecs/wm8978.c
parentbda7d2a862e6b788bca2d02d38a07966a9c92e48 (diff)
ASoC: multi-component - ASoC Multi-Component Support
This patch extends the ASoC API to allow sound cards to have more than one CODEC and more than one platform DMA controller. This is achieved by dividing some current ASoC structures that contain both driver data and device data into structures that only either contain device data or driver data. i.e. struct snd_soc_codec ---> struct snd_soc_codec (device data) +-> struct snd_soc_codec_driver (driver data) struct snd_soc_platform ---> struct snd_soc_platform (device data) +-> struct snd_soc_platform_driver (driver data) struct snd_soc_dai ---> struct snd_soc_dai (device data) +-> struct snd_soc_dai_driver (driver data) struct snd_soc_device ---> deleted This now allows ASoC to be more tightly aligned with the Linux driver model and also means that every ASoC codec, platform and (platform) DAI is a kernel device. ASoC component private data is now stored as device private data. The ASoC sound card struct snd_soc_card has also been updated to store lists of it's components rather than a pointer to a codec and platform. The PCM runtime struct soc_pcm_runtime now has pointers to all its components. This patch adds DAPM support for ASoC multi-component and removes struct snd_soc_socdev from DAPM core. All DAPM calls are now made on a card, codec or runtime PCM level basis rather than using snd_soc_socdev. Other notable multi-component changes:- * Stream operations now de-reference less structures. * close_delayed work() now runs on a DAI basis rather than looping all DAIs in a card. * PM suspend()/resume() operations can now handle N CODECs and Platforms per sound card. * Added soc_bind_dai_link() to bind the component devices to the sound card. * Added soc_dai_link_probe() and soc_dai_link_remove() to probe and remove DAI link components. * sysfs entries can now be registered per component per card. * snd_soc_new_pcms() functionailty rolled into dai_link_probe(). * snd_soc_register_codec() now does all the codec list and mutex init. This patch changes the probe() and remove() of the CODEC drivers as follows:- o Make CODEC driver a platform driver o Moved all struct snd_soc_codec list, mutex, etc initialiasation to core. o Removed all static codec pointers (drivers now support > 1 codec dev) o snd_soc_register_pcms() now done by core. o snd_soc_register_dai() folded into snd_soc_register_codec(). CS4270 portions: Acked-by: Timur Tabi <timur@freescale.com> Some TLV320aic23 and Cirrus platform fixes. Signed-off-by: Ryan Mallon <ryan@bluewatersys.com> TI CODEC and OMAP fixes Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Signed-off-by: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> Signed-off-by: Jarkko Nikula <jhnikula@gmail.com> Samsung platform and misc fixes :- Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Reviewed-by: Jassi Brar <jassi.brar@samsung.com> Signed-off-by: Seungwhan Youn <sw.youn@samsung.com> MPC8610 and PPC fixes. Signed-off-by: Timur Tabi <timur@freescale.com> i.MX fixes and some core fixes. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> J4740 platform fixes:- Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> CC: Tony Lindgren <tony@atomide.com> CC: Nicolas Ferre <nicolas.ferre@atmel.com> CC: Kevin Hilman <khilman@deeprootsystems.com> CC: Sascha Hauer <s.hauer@pengutronix.de> CC: Atsushi Nemoto <anemo@mba.ocn.ne.jp> CC: Kuninori Morimoto <morimoto.kuninori@renesas.com> CC: Daniel Gloeckner <dg@emlix.com> CC: Manuel Lauss <mano@roarinelk.homelinux.net> CC: Mike Frysinger <vapier.adi@gmail.com> CC: Arnaud Patard <apatard@mandriva.com> CC: Wan ZongShun <mcuos.com@gmail.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc/codecs/wm8978.c')
-rw-r--r--sound/soc/codecs/wm8978.c190
1 files changed, 55 insertions, 135 deletions
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index 8a1ad778e7e3..676a4306cc87 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
34static 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. */
37static const u16 wm8978_reg[WM8978_CACHEREGNUM] = { 35static 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 */
56struct wm8978_priv { 54struct 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
377static void pll_factors(struct wm8978_pll_div *pll_div, unsigned int target, 376static 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 */
878struct snd_soc_dai wm8978_dai = { 876static 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};
897EXPORT_SYMBOL_GPL(wm8978_dai);
898 894
899static int wm8978_suspend(struct platform_device *pdev, pm_message_t state) 895static 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
911static int wm8978_resume(struct platform_device *pdev) 904static 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
936static 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
961pcm_err:
962 return ret;
963}
964
965/* power down chip */
966static 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
976struct 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};
982EXPORT_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
1003static __devinit int wm8978_register(struct wm8978_priv *wm8978) 946static 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
1076err_codec:
1077 snd_soc_unregister_codec(codec);
1078err:
1079 return ret;
1080} 985}
1081 986
1082static __devexit void wm8978_unregister(struct wm8978_priv *wm8978) 987/* power down chip */
988static 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
994static 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)
1090static __devinit int wm8978_i2c_probe(struct i2c_client *i2c, 1006static __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
1116static __devexit int wm8978_i2c_remove(struct i2c_client *client) 1026static __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
1130static struct i2c_driver wm8978_i2c_driver = { 1039static struct i2c_driver wm8978_i2c_driver = {
1131 .driver = { 1040 .driver = {
1132 .name = "WM8978", 1041 .name = "WM8978-codec",
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
1140static int __init wm8978_modinit(void) 1050static 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}
1144module_init(wm8978_modinit); 1062module_init(wm8978_modinit);
1145 1063
1146static void __exit wm8978_exit(void) 1064static 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}
1150module_exit(wm8978_exit); 1070module_exit(wm8978_exit);
1151 1071