aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8990.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/wm8990.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/wm8990.c')
-rw-r--r--sound/soc/codecs/wm8990.c226
1 files changed, 54 insertions, 172 deletions
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index dd8d909788c1..b25243382966 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -32,6 +32,8 @@
32 32
33/* codec private data */ 33/* codec private data */
34struct wm8990_priv { 34struct wm8990_priv {
35 enum snd_soc_control_type control_type;
36 void *control_data;
35 unsigned int sysclk; 37 unsigned int sysclk;
36 unsigned int pcmclk; 38 unsigned int pcmclk;
37}; 39};
@@ -1114,8 +1116,7 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream,
1114 struct snd_soc_dai *dai) 1116 struct snd_soc_dai *dai)
1115{ 1117{
1116 struct snd_soc_pcm_runtime *rtd = substream->private_data; 1118 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1117 struct snd_soc_device *socdev = rtd->socdev; 1119 struct snd_soc_codec *codec = rtd->codec;
1118 struct snd_soc_codec *codec = socdev->card->codec;
1119 u16 audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1); 1120 u16 audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1);
1120 1121
1121 audio1 &= ~WM8990_AIF_WL_MASK; 1122 audio1 &= ~WM8990_AIF_WL_MASK;
@@ -1293,10 +1294,9 @@ static struct snd_soc_dai_ops wm8990_dai_ops = {
1293 .set_sysclk = wm8990_set_dai_sysclk, 1294 .set_sysclk = wm8990_set_dai_sysclk,
1294}; 1295};
1295 1296
1296struct snd_soc_dai wm8990_dai = { 1297static struct snd_soc_dai_driver wm8990_dai = {
1297/* ADC/DAC on primary */ 1298/* ADC/DAC on primary */
1298 .name = "WM8990 ADC/DAC Primary", 1299 .name = "wm8990-hifi",
1299 .id = 1,
1300 .playback = { 1300 .playback = {
1301 .stream_name = "Playback", 1301 .stream_name = "Playback",
1302 .channels_min = 1, 1302 .channels_min = 1,
@@ -1311,21 +1311,15 @@ struct snd_soc_dai wm8990_dai = {
1311 .formats = WM8990_FORMATS,}, 1311 .formats = WM8990_FORMATS,},
1312 .ops = &wm8990_dai_ops, 1312 .ops = &wm8990_dai_ops,
1313}; 1313};
1314EXPORT_SYMBOL_GPL(wm8990_dai);
1315 1314
1316static int wm8990_suspend(struct platform_device *pdev, pm_message_t state) 1315static int wm8990_suspend(struct snd_soc_codec *codec, pm_message_t state)
1317{ 1316{
1318 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1319 struct snd_soc_codec *codec = socdev->card->codec;
1320
1321 wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); 1317 wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
1322 return 0; 1318 return 0;
1323} 1319}
1324 1320
1325static int wm8990_resume(struct platform_device *pdev) 1321static int wm8990_resume(struct snd_soc_codec *codec)
1326{ 1322{
1327 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1328 struct snd_soc_codec *codec = socdev->card->codec;
1329 int i; 1323 int i;
1330 u8 data[2]; 1324 u8 data[2];
1331 u16 *cache = codec->reg_cache; 1325 u16 *cache = codec->reg_cache;
@@ -1347,38 +1341,21 @@ static int wm8990_resume(struct platform_device *pdev)
1347 * initialise the WM8990 driver 1341 * initialise the WM8990 driver
1348 * register the mixer and dsp interfaces with the kernel 1342 * register the mixer and dsp interfaces with the kernel
1349 */ 1343 */
1350static int wm8990_init(struct snd_soc_device *socdev) 1344static int wm8990_probe(struct snd_soc_codec *codec)
1351{ 1345{
1352 struct snd_soc_codec *codec = socdev->card->codec; 1346 struct wm8990_priv *wm8990 = snd_soc_codec_get_drvdata(codec);
1347 int ret;
1353 u16 reg; 1348 u16 reg;
1354 int ret = 0;
1355
1356 codec->name = "WM8990";
1357 codec->owner = THIS_MODULE;
1358 codec->set_bias_level = wm8990_set_bias_level;
1359 codec->dai = &wm8990_dai;
1360 codec->num_dai = 2;
1361 codec->reg_cache_size = ARRAY_SIZE(wm8990_reg);
1362 codec->reg_cache = kmemdup(wm8990_reg, sizeof(wm8990_reg), GFP_KERNEL);
1363
1364 if (codec->reg_cache == NULL)
1365 return -ENOMEM;
1366 1349
1350 codec->control_data = wm8990->control_data;
1367 ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); 1351 ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
1368 if (ret < 0) { 1352 if (ret < 0) {
1369 printk(KERN_ERR "wm8990: failed to set cache I/O: %d\n", ret); 1353 printk(KERN_ERR "wm8990: failed to set cache I/O: %d\n", ret);
1370 goto pcm_err; 1354 return ret;
1371 } 1355 }
1372 1356
1373 wm8990_reset(codec); 1357 wm8990_reset(codec);
1374 1358
1375 /* register pcms */
1376 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
1377 if (ret < 0) {
1378 printk(KERN_ERR "wm8990: failed to create pcms\n");
1379 goto pcm_err;
1380 }
1381
1382 /* charge output caps */ 1359 /* charge output caps */
1383 codec->bias_level = SND_SOC_BIAS_OFF; 1360 codec->bias_level = SND_SOC_BIAS_OFF;
1384 wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1361 wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -1400,47 +1377,52 @@ static int wm8990_init(struct snd_soc_device *socdev)
1400 ARRAY_SIZE(wm8990_snd_controls)); 1377 ARRAY_SIZE(wm8990_snd_controls));
1401 wm8990_add_widgets(codec); 1378 wm8990_add_widgets(codec);
1402 1379
1403 return ret; 1380 return 0;
1381}
1404 1382
1405pcm_err: 1383/* power down chip */
1406 kfree(codec->reg_cache); 1384static int wm8990_remove(struct snd_soc_codec *codec)
1407 return ret; 1385{
1386 wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
1387 return 0;
1408} 1388}
1409 1389
1410/* If the i2c layer weren't so broken, we could pass this kind of data 1390static struct snd_soc_codec_driver soc_codec_dev_wm8990 = {
1411 around */ 1391 .probe = wm8990_probe,
1412static struct snd_soc_device *wm8990_socdev; 1392 .remove = wm8990_remove,
1393 .suspend = wm8990_suspend,
1394 .resume = wm8990_resume,
1395 .set_bias_level = wm8990_set_bias_level,
1396 .reg_cache_size = ARRAY_SIZE(wm8990_reg),
1397 .reg_word_size = sizeof(u16),
1398 .reg_cache_default = wm8990_reg,
1399};
1413 1400
1414#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 1401#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1415 1402static __devinit int wm8990_i2c_probe(struct i2c_client *i2c,
1416/* 1403 const struct i2c_device_id *id)
1417 * WM891 2 wire address is determined by GPIO5
1418 * state during powerup.
1419 * low = 0x34
1420 * high = 0x36
1421 */
1422
1423static int wm8990_i2c_probe(struct i2c_client *i2c,
1424 const struct i2c_device_id *id)
1425{ 1404{
1426 struct snd_soc_device *socdev = wm8990_socdev; 1405 struct wm8990_priv *wm8990;
1427 struct snd_soc_codec *codec = socdev->card->codec;
1428 int ret; 1406 int ret;
1429 1407
1430 i2c_set_clientdata(i2c, codec); 1408 wm8990 = kzalloc(sizeof(struct wm8990_priv), GFP_KERNEL);
1431 codec->control_data = i2c; 1409 if (wm8990 == NULL)
1410 return -ENOMEM;
1432 1411
1433 ret = wm8990_init(socdev); 1412 i2c_set_clientdata(i2c, wm8990);
1434 if (ret < 0) 1413 wm8990->control_data = i2c;
1435 pr_err("failed to initialise WM8990\n");
1436 1414
1415 ret = snd_soc_register_codec(&i2c->dev,
1416 &soc_codec_dev_wm8990, &wm8990_dai, 1);
1417 if (ret < 0)
1418 kfree(wm8990);
1437 return ret; 1419 return ret;
1438} 1420}
1439 1421
1440static int wm8990_i2c_remove(struct i2c_client *client) 1422static __devexit int wm8990_i2c_remove(struct i2c_client *client)
1441{ 1423{
1442 struct snd_soc_codec *codec = i2c_get_clientdata(client); 1424 snd_soc_unregister_codec(&client->dev);
1443 kfree(codec->reg_cache); 1425 kfree(i2c_get_clientdata(client));
1444 return 0; 1426 return 0;
1445} 1427}
1446 1428
@@ -1452,134 +1434,34 @@ MODULE_DEVICE_TABLE(i2c, wm8990_i2c_id);
1452 1434
1453static struct i2c_driver wm8990_i2c_driver = { 1435static struct i2c_driver wm8990_i2c_driver = {
1454 .driver = { 1436 .driver = {
1455 .name = "WM8990 I2C Codec", 1437 .name = "wm8990-codec",
1456 .owner = THIS_MODULE, 1438 .owner = THIS_MODULE,
1457 }, 1439 },
1458 .probe = wm8990_i2c_probe, 1440 .probe = wm8990_i2c_probe,
1459 .remove = wm8990_i2c_remove, 1441 .remove = __devexit_p(wm8990_i2c_remove),
1460 .id_table = wm8990_i2c_id, 1442 .id_table = wm8990_i2c_id,
1461}; 1443};
1462
1463static int wm8990_add_i2c_device(struct platform_device *pdev,
1464 const struct wm8990_setup_data *setup)
1465{
1466 struct i2c_board_info info;
1467 struct i2c_adapter *adapter;
1468 struct i2c_client *client;
1469 int ret;
1470
1471 ret = i2c_add_driver(&wm8990_i2c_driver);
1472 if (ret != 0) {
1473 dev_err(&pdev->dev, "can't add i2c driver\n");
1474 return ret;
1475 }
1476
1477 memset(&info, 0, sizeof(struct i2c_board_info));
1478 info.addr = setup->i2c_address;
1479 strlcpy(info.type, "wm8990", I2C_NAME_SIZE);
1480
1481 adapter = i2c_get_adapter(setup->i2c_bus);
1482 if (!adapter) {
1483 dev_err(&pdev->dev, "can't get i2c adapter %d\n",
1484 setup->i2c_bus);
1485 goto err_driver;
1486 }
1487
1488 client = i2c_new_device(adapter, &info);
1489 i2c_put_adapter(adapter);
1490 if (!client) {
1491 dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
1492 (unsigned int)info.addr);
1493 goto err_driver;
1494 }
1495
1496 return 0;
1497
1498err_driver:
1499 i2c_del_driver(&wm8990_i2c_driver);
1500 return -ENODEV;
1501}
1502#endif 1444#endif
1503 1445
1504static int wm8990_probe(struct platform_device *pdev) 1446static int __init wm8990_modinit(void)
1505{ 1447{
1506 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 1448 int ret = 0;
1507 struct wm8990_setup_data *setup;
1508 struct snd_soc_codec *codec;
1509 struct wm8990_priv *wm8990;
1510 int ret;
1511
1512 setup = socdev->codec_data;
1513 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
1514 if (codec == NULL)
1515 return -ENOMEM;
1516
1517 wm8990 = kzalloc(sizeof(struct wm8990_priv), GFP_KERNEL);
1518 if (wm8990 == NULL) {
1519 kfree(codec);
1520 return -ENOMEM;
1521 }
1522
1523 snd_soc_codec_set_drvdata(codec, wm8990);
1524 socdev->card->codec = codec;
1525 mutex_init(&codec->mutex);
1526 INIT_LIST_HEAD(&codec->dapm_widgets);
1527 INIT_LIST_HEAD(&codec->dapm_paths);
1528 wm8990_socdev = socdev;
1529
1530 ret = -ENODEV;
1531
1532#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 1449#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1533 if (setup->i2c_address) { 1450 ret = i2c_add_driver(&wm8990_i2c_driver);
1534 codec->hw_write = (hw_write_t)i2c_master_send;
1535 ret = wm8990_add_i2c_device(pdev, setup);
1536 }
1537#endif
1538
1539 if (ret != 0) { 1451 if (ret != 0) {
1540 kfree(snd_soc_codec_get_drvdata(codec)); 1452 printk(KERN_ERR "Failed to register wm8990 I2C driver: %d\n",
1541 kfree(codec); 1453 ret);
1542 } 1454 }
1455#endif
1543 return ret; 1456 return ret;
1544} 1457}
1458module_init(wm8990_modinit);
1545 1459
1546/* power down chip */ 1460static void __exit wm8990_exit(void)
1547static int wm8990_remove(struct platform_device *pdev)
1548{ 1461{
1549 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1550 struct snd_soc_codec *codec = socdev->card->codec;
1551
1552 if (codec->control_data)
1553 wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
1554 snd_soc_free_pcms(socdev);
1555 snd_soc_dapm_free(socdev);
1556#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 1462#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1557 i2c_unregister_device(codec->control_data);
1558 i2c_del_driver(&wm8990_i2c_driver); 1463 i2c_del_driver(&wm8990_i2c_driver);
1559#endif 1464#endif
1560 kfree(snd_soc_codec_get_drvdata(codec));
1561 kfree(codec);
1562
1563 return 0;
1564}
1565
1566struct snd_soc_codec_device soc_codec_dev_wm8990 = {
1567 .probe = wm8990_probe,
1568 .remove = wm8990_remove,
1569 .suspend = wm8990_suspend,
1570 .resume = wm8990_resume,
1571};
1572EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990);
1573
1574static int __init wm8990_modinit(void)
1575{
1576 return snd_soc_register_dai(&wm8990_dai);
1577}
1578module_init(wm8990_modinit);
1579
1580static void __exit wm8990_exit(void)
1581{
1582 snd_soc_unregister_dai(&wm8990_dai);
1583} 1465}
1584module_exit(wm8990_exit); 1466module_exit(wm8990_exit);
1585 1467