aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8900.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/wm8900.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/wm8900.c')
-rw-r--r--sound/soc/codecs/wm8900.c251
1 files changed, 122 insertions, 129 deletions
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index 5da17a704e5a..33c3b57f3f66 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -23,6 +23,7 @@
23#include <linux/delay.h> 23#include <linux/delay.h>
24#include <linux/pm.h> 24#include <linux/pm.h>
25#include <linux/i2c.h> 25#include <linux/i2c.h>
26#include <linux/spi/spi.h>
26#include <linux/platform_device.h> 27#include <linux/platform_device.h>
27#include <linux/slab.h> 28#include <linux/slab.h>
28#include <sound/core.h> 29#include <sound/core.h>
@@ -137,11 +138,9 @@
137 138
138#define WM8900_LRC_MASK 0xfc00 139#define WM8900_LRC_MASK 0xfc00
139 140
140struct snd_soc_codec_device soc_codec_dev_wm8900;
141
142struct wm8900_priv { 141struct wm8900_priv {
143 struct snd_soc_codec codec; 142 enum snd_soc_control_type control_type;
144 143 void *control_data;
145 u16 reg_cache[WM8900_MAXREG]; 144 u16 reg_cache[WM8900_MAXREG];
146 145
147 u32 fll_in; /* FLL input frequency */ 146 u32 fll_in; /* FLL input frequency */
@@ -627,8 +626,7 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream,
627 struct snd_soc_dai *dai) 626 struct snd_soc_dai *dai)
628{ 627{
629 struct snd_soc_pcm_runtime *rtd = substream->private_data; 628 struct snd_soc_pcm_runtime *rtd = substream->private_data;
630 struct snd_soc_device *socdev = rtd->socdev; 629 struct snd_soc_codec *codec = rtd->codec;
631 struct snd_soc_codec *codec = socdev->card->codec;
632 u16 reg; 630 u16 reg;
633 631
634 reg = snd_soc_read(codec, WM8900_REG_AUDIO1) & ~0x60; 632 reg = snd_soc_read(codec, WM8900_REG_AUDIO1) & ~0x60;
@@ -1015,8 +1013,8 @@ static struct snd_soc_dai_ops wm8900_dai_ops = {
1015 .digital_mute = wm8900_digital_mute, 1013 .digital_mute = wm8900_digital_mute,
1016}; 1014};
1017 1015
1018struct snd_soc_dai wm8900_dai = { 1016static struct snd_soc_dai_driver wm8900_dai = {
1019 .name = "WM8900 HiFi", 1017 .name = "wm8900-hifi",
1020 .playback = { 1018 .playback = {
1021 .stream_name = "HiFi Playback", 1019 .stream_name = "HiFi Playback",
1022 .channels_min = 1, 1020 .channels_min = 1,
@@ -1033,7 +1031,6 @@ struct snd_soc_dai wm8900_dai = {
1033 }, 1031 },
1034 .ops = &wm8900_dai_ops, 1032 .ops = &wm8900_dai_ops,
1035}; 1033};
1036EXPORT_SYMBOL_GPL(wm8900_dai);
1037 1034
1038static int wm8900_set_bias_level(struct snd_soc_codec *codec, 1035static int wm8900_set_bias_level(struct snd_soc_codec *codec,
1039 enum snd_soc_bias_level level) 1036 enum snd_soc_bias_level level)
@@ -1128,10 +1125,8 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec,
1128 return 0; 1125 return 0;
1129} 1126}
1130 1127
1131static int wm8900_suspend(struct platform_device *pdev, pm_message_t state) 1128static int wm8900_suspend(struct snd_soc_codec *codec, pm_message_t state)
1132{ 1129{
1133 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1134 struct snd_soc_codec *codec = socdev->card->codec;
1135 struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec); 1130 struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
1136 int fll_out = wm8900->fll_out; 1131 int fll_out = wm8900->fll_out;
1137 int fll_in = wm8900->fll_in; 1132 int fll_in = wm8900->fll_in;
@@ -1140,7 +1135,7 @@ static int wm8900_suspend(struct platform_device *pdev, pm_message_t state)
1140 /* Stop the FLL in an orderly fashion */ 1135 /* Stop the FLL in an orderly fashion */
1141 ret = wm8900_set_fll(codec, 0, 0, 0); 1136 ret = wm8900_set_fll(codec, 0, 0, 0);
1142 if (ret != 0) { 1137 if (ret != 0) {
1143 dev_err(&pdev->dev, "Failed to stop FLL\n"); 1138 dev_err(codec->dev, "Failed to stop FLL\n");
1144 return ret; 1139 return ret;
1145 } 1140 }
1146 1141
@@ -1152,10 +1147,8 @@ static int wm8900_suspend(struct platform_device *pdev, pm_message_t state)
1152 return 0; 1147 return 0;
1153} 1148}
1154 1149
1155static int wm8900_resume(struct platform_device *pdev) 1150static int wm8900_resume(struct snd_soc_codec *codec)
1156{ 1151{
1157 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1158 struct snd_soc_codec *codec = socdev->card->codec;
1159 struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec); 1152 struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
1160 u16 *cache; 1153 u16 *cache;
1161 int i, ret; 1154 int i, ret;
@@ -1176,7 +1169,7 @@ static int wm8900_resume(struct platform_device *pdev)
1176 1169
1177 ret = wm8900_set_fll(codec, 0, fll_in, fll_out); 1170 ret = wm8900_set_fll(codec, 0, fll_in, fll_out);
1178 if (ret != 0) { 1171 if (ret != 0) {
1179 dev_err(&pdev->dev, "Failed to restart FLL\n"); 1172 dev_err(codec->dev, "Failed to restart FLL\n");
1180 return ret; 1173 return ret;
1181 } 1174 }
1182 } 1175 }
@@ -1186,60 +1179,33 @@ static int wm8900_resume(struct platform_device *pdev)
1186 snd_soc_write(codec, i, cache[i]); 1179 snd_soc_write(codec, i, cache[i]);
1187 kfree(cache); 1180 kfree(cache);
1188 } else 1181 } else
1189 dev_err(&pdev->dev, "Unable to allocate register cache\n"); 1182 dev_err(codec->dev, "Unable to allocate register cache\n");
1190 1183
1191 return 0; 1184 return 0;
1192} 1185}
1193 1186
1194static struct snd_soc_codec *wm8900_codec; 1187static int wm8900_probe(struct snd_soc_codec *codec)
1195
1196static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
1197 const struct i2c_device_id *id)
1198{ 1188{
1199 struct wm8900_priv *wm8900; 1189 struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
1200 struct snd_soc_codec *codec; 1190 int ret = 0, reg;
1201 unsigned int reg;
1202 int ret;
1203
1204 wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
1205 if (wm8900 == NULL)
1206 return -ENOMEM;
1207 1191
1208 codec = &wm8900->codec; 1192 codec->control_data = wm8900->control_data;
1209 snd_soc_codec_set_drvdata(codec, wm8900); 1193 ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8900->control_type);
1210 codec->reg_cache = &wm8900->reg_cache[0];
1211 codec->reg_cache_size = WM8900_MAXREG;
1212
1213 mutex_init(&codec->mutex);
1214 INIT_LIST_HEAD(&codec->dapm_widgets);
1215 INIT_LIST_HEAD(&codec->dapm_paths);
1216
1217 codec->name = "WM8900";
1218 codec->owner = THIS_MODULE;
1219 codec->dai = &wm8900_dai;
1220 codec->num_dai = 1;
1221 codec->control_data = i2c;
1222 codec->set_bias_level = wm8900_set_bias_level;
1223 codec->volatile_register = wm8900_volatile_register;
1224 codec->dev = &i2c->dev;
1225
1226 ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
1227 if (ret != 0) { 1194 if (ret != 0) {
1228 dev_err(&i2c->dev, "Failed to set cache I/O: %d\n", ret); 1195 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
1229 goto err; 1196 return ret;
1230 } 1197 }
1231 1198
1232 reg = snd_soc_read(codec, WM8900_REG_ID); 1199 reg = snd_soc_read(codec, WM8900_REG_ID);
1233 if (reg != 0x8900) { 1200 if (reg != 0x8900) {
1234 dev_err(&i2c->dev, "Device is not a WM8900 - ID %x\n", reg); 1201 dev_err(codec->dev, "Device is not a WM8900 - ID %x\n", reg);
1235 ret = -ENODEV; 1202 return -ENODEV;
1236 goto err;
1237 } 1203 }
1238 1204
1239 /* Read back from the chip */ 1205 /* Read back from the chip */
1240 reg = snd_soc_read(codec, WM8900_REG_POWER1); 1206 reg = snd_soc_read(codec, WM8900_REG_POWER1);
1241 reg = (reg >> 12) & 0xf; 1207 reg = (reg >> 12) & 0xf;
1242 dev_info(&i2c->dev, "WM8900 revision %d\n", reg); 1208 dev_info(codec->dev, "WM8900 revision %d\n", reg);
1243 1209
1244 wm8900_reset(codec); 1210 wm8900_reset(codec);
1245 1211
@@ -1271,43 +1237,97 @@ static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
1271 /* Set the DAC and mixer output bias */ 1237 /* Set the DAC and mixer output bias */
1272 snd_soc_write(codec, WM8900_REG_OUTBIASCTL, 0x81); 1238 snd_soc_write(codec, WM8900_REG_OUTBIASCTL, 0x81);
1273 1239
1274 wm8900_dai.dev = &i2c->dev; 1240 snd_soc_add_controls(codec, wm8900_snd_controls,
1241 ARRAY_SIZE(wm8900_snd_controls));
1242 wm8900_add_widgets(codec);
1275 1243
1276 wm8900_codec = codec; 1244 return 0;
1245}
1277 1246
1278 ret = snd_soc_register_codec(codec); 1247/* power down chip */
1279 if (ret != 0) { 1248static int wm8900_remove(struct snd_soc_codec *codec)
1280 dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); 1249{
1281 goto err; 1250 wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF);
1282 } 1251 return 0;
1252}
1283 1253
1284 ret = snd_soc_register_dai(&wm8900_dai); 1254static struct snd_soc_codec_driver soc_codec_dev_wm8900 = {
1285 if (ret != 0) { 1255 .probe = wm8900_probe,
1286 dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret); 1256 .remove = wm8900_remove,
1287 goto err_codec; 1257 .suspend = wm8900_suspend,
1288 } 1258 .resume = wm8900_resume,
1259 .set_bias_level = wm8900_set_bias_level,
1260 .volatile_register = wm8900_volatile_register,
1261 .reg_cache_size = sizeof(wm8900_reg_defaults),
1262 .reg_word_size = sizeof(u16),
1263 .reg_cache_default = wm8900_reg_defaults,
1264};
1289 1265
1290 return ret; 1266#if defined(CONFIG_SPI_MASTER)
1267static int __devinit wm8900_spi_probe(struct spi_device *spi)
1268{
1269 struct wm8900_priv *wm8900;
1270 int ret;
1271
1272 wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
1273 if (wm8900 == NULL)
1274 return -ENOMEM;
1291 1275
1292err_codec: 1276 wm8900->control_data = spi;
1293 snd_soc_unregister_codec(codec); 1277 wm8900->control_type = SND_SOC_SPI;
1294err: 1278 spi_set_drvdata(spi, wm8900);
1295 kfree(wm8900); 1279
1296 wm8900_codec = NULL; 1280 ret = snd_soc_register_codec(&spi->dev,
1281 &soc_codec_dev_wm8900, &wm8900_dai, 1);
1282 if (ret < 0)
1283 kfree(wm8900);
1297 return ret; 1284 return ret;
1298} 1285}
1299 1286
1300static __devexit int wm8900_i2c_remove(struct i2c_client *client) 1287static int __devexit wm8900_spi_remove(struct spi_device *spi)
1301{ 1288{
1302 snd_soc_unregister_dai(&wm8900_dai); 1289 snd_soc_unregister_codec(&spi->dev);
1303 snd_soc_unregister_codec(wm8900_codec); 1290 kfree(spi_get_drvdata(spi));
1291 return 0;
1292}
1304 1293
1305 wm8900_set_bias_level(wm8900_codec, SND_SOC_BIAS_OFF); 1294static struct spi_driver wm8900_spi_driver = {
1295 .driver = {
1296 .name = "wm8900-codec",
1297 .bus = &spi_bus_type,
1298 .owner = THIS_MODULE,
1299 },
1300 .probe = wm8900_spi_probe,
1301 .remove = __devexit_p(wm8900_spi_remove),
1302};
1303#endif /* CONFIG_SPI_MASTER */
1304
1305#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1306static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
1307 const struct i2c_device_id *id)
1308{
1309 struct wm8900_priv *wm8900;
1310 int ret;
1311
1312 wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
1313 if (wm8900 == NULL)
1314 return -ENOMEM;
1315
1316 i2c_set_clientdata(i2c, wm8900);
1317 wm8900->control_data = i2c;
1318 wm8900->control_type = SND_SOC_I2C;
1306 1319
1307 wm8900_dai.dev = NULL; 1320 ret = snd_soc_register_codec(&i2c->dev,
1308 kfree(snd_soc_codec_get_drvdata(wm8900_codec)); 1321 &soc_codec_dev_wm8900, &wm8900_dai, 1);
1309 wm8900_codec = NULL; 1322 if (ret < 0)
1323 kfree(wm8900);
1324 return ret;
1325}
1310 1326
1327static __devexit int wm8900_i2c_remove(struct i2c_client *client)
1328{
1329 snd_soc_unregister_codec(&client->dev);
1330 kfree(i2c_get_clientdata(client));
1311 return 0; 1331 return 0;
1312} 1332}
1313 1333
@@ -1319,71 +1339,44 @@ MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id);
1319 1339
1320static struct i2c_driver wm8900_i2c_driver = { 1340static struct i2c_driver wm8900_i2c_driver = {
1321 .driver = { 1341 .driver = {
1322 .name = "WM8900", 1342 .name = "wm8900-codec",
1323 .owner = THIS_MODULE, 1343 .owner = THIS_MODULE,
1324 }, 1344 },
1325 .probe = wm8900_i2c_probe, 1345 .probe = wm8900_i2c_probe,
1326 .remove = __devexit_p(wm8900_i2c_remove), 1346 .remove = __devexit_p(wm8900_i2c_remove),
1327 .id_table = wm8900_i2c_id, 1347 .id_table = wm8900_i2c_id,
1328}; 1348};
1349#endif
1329 1350
1330static int wm8900_probe(struct platform_device *pdev) 1351static int __init wm8900_modinit(void)
1331{ 1352{
1332 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1333 struct snd_soc_codec *codec;
1334 int ret = 0; 1353 int ret = 0;
1335 1354#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1336 if (!wm8900_codec) { 1355 ret = i2c_add_driver(&wm8900_i2c_driver);
1337 dev_err(&pdev->dev, "I2C client not yet instantiated\n"); 1356 if (ret != 0) {
1338 return -ENODEV; 1357 printk(KERN_ERR "Failed to register wm8900 I2C driver: %d\n",
1358 ret);
1339 } 1359 }
1340 1360#endif
1341 codec = wm8900_codec; 1361#if defined(CONFIG_SPI_MASTER)
1342 socdev->card->codec = codec; 1362 ret = spi_register_driver(&wm8900_spi_driver);
1343 1363 if (ret != 0) {
1344 /* Register pcms */ 1364 printk(KERN_ERR "Failed to register wm8900 SPI driver: %d\n",
1345 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); 1365 ret);
1346 if (ret < 0) {
1347 dev_err(&pdev->dev, "Failed to register new PCMs\n");
1348 goto pcm_err;
1349 } 1366 }
1350 1367#endif
1351 snd_soc_add_controls(codec, wm8900_snd_controls,
1352 ARRAY_SIZE(wm8900_snd_controls));
1353 wm8900_add_widgets(codec);
1354
1355pcm_err:
1356 return ret; 1368 return ret;
1357} 1369}
1358
1359/* power down chip */
1360static int wm8900_remove(struct platform_device *pdev)
1361{
1362 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1363
1364 snd_soc_free_pcms(socdev);
1365 snd_soc_dapm_free(socdev);
1366
1367 return 0;
1368}
1369
1370struct snd_soc_codec_device soc_codec_dev_wm8900 = {
1371 .probe = wm8900_probe,
1372 .remove = wm8900_remove,
1373 .suspend = wm8900_suspend,
1374 .resume = wm8900_resume,
1375};
1376EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900);
1377
1378static int __init wm8900_modinit(void)
1379{
1380 return i2c_add_driver(&wm8900_i2c_driver);
1381}
1382module_init(wm8900_modinit); 1370module_init(wm8900_modinit);
1383 1371
1384static void __exit wm8900_exit(void) 1372static void __exit wm8900_exit(void)
1385{ 1373{
1374#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1386 i2c_del_driver(&wm8900_i2c_driver); 1375 i2c_del_driver(&wm8900_i2c_driver);
1376#endif
1377#if defined(CONFIG_SPI_MASTER)
1378 spi_unregister_driver(&wm8900_spi_driver);
1379#endif
1387} 1380}
1388module_exit(wm8900_exit); 1381module_exit(wm8900_exit);
1389 1382