aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8955.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/wm8955.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/wm8955.c')
-rw-r--r--sound/soc/codecs/wm8955.c184
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
33static struct snd_soc_codec *wm8955_codec;
34struct snd_soc_codec_device soc_codec_dev_wm8955;
35
36#define WM8955_NUM_SUPPLIES 4 33#define WM8955_NUM_SUPPLIES 4
37static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = { 34static 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 */
45struct wm8955_priv { 42struct 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
59static const u16 wm8955_reg[WM8955_MAX_REGISTER + 1] = { 56static 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
873struct snd_soc_dai wm8955_dai = { 870static 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};
884EXPORT_SYMBOL_GPL(wm8955_dai);
885 881
886#ifdef CONFIG_PM 882#ifdef CONFIG_PM
887static int wm8955_suspend(struct platform_device *pdev, pm_message_t state) 883static 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
897static int wm8955_resume(struct platform_device *pdev) 890static 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
911static int wm8955_probe(struct platform_device *pdev) 901static 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
936pcm_err:
937 return ret;
938}
939
940static 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
950struct 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};
956EXPORT_SYMBOL_GPL(soc_codec_dev_wm8955);
957
958static 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
1062err_codec:
1063 snd_soc_unregister_codec(codec);
1064err_enable: 968err_enable:
1065 regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); 969 regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
1066err_get: 970err_get:
1067 regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); 971 regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
1068err:
1069 kfree(wm8955);
1070 return ret; 972 return ret;
1071} 973}
1072 974
1073static void wm8955_unregister(struct wm8955_priv *wm8955) 975static 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
984static 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)
1084static __devinit int wm8955_i2c_probe(struct i2c_client *i2c, 996static __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
1106static __devexit int wm8955_i2c_remove(struct i2c_client *client) 1016static __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
1119static struct i2c_driver wm8955_i2c_driver = { 1029static 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
1130static int __init wm8955_modinit(void) 1040static 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}
1142module_init(wm8955_modinit); 1052module_init(wm8955_modinit);
1143 1053