aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8400.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/wm8400.c')
-rw-r--r--sound/soc/codecs/wm8400.c181
1 files changed, 49 insertions, 132 deletions
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index 8f294066b0ed..850299786e02 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -65,7 +65,7 @@ static struct regulator_bulk_data power[] = {
65 65
66/* codec private data */ 66/* codec private data */
67struct wm8400_priv { 67struct wm8400_priv {
68 struct snd_soc_codec codec; 68 struct snd_soc_codec *codec;
69 struct wm8400 *wm8400; 69 struct wm8400 *wm8400;
70 u16 fake_register; 70 u16 fake_register;
71 unsigned int sysclk; 71 unsigned int sysclk;
@@ -1163,8 +1163,7 @@ static int wm8400_hw_params(struct snd_pcm_substream *substream,
1163 struct snd_soc_dai *dai) 1163 struct snd_soc_dai *dai)
1164{ 1164{
1165 struct snd_soc_pcm_runtime *rtd = substream->private_data; 1165 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1166 struct snd_soc_device *socdev = rtd->socdev; 1166 struct snd_soc_codec *codec = rtd->codec;
1167 struct snd_soc_codec *codec = socdev->card->codec;
1168 u16 audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1); 1167 u16 audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
1169 1168
1170 audio1 &= ~WM8400_AIF_WL_MASK; 1169 audio1 &= ~WM8400_AIF_WL_MASK;
@@ -1332,10 +1331,9 @@ static struct snd_soc_dai_ops wm8400_dai_ops = {
1332 * 1. ADC/DAC on Primary Interface 1331 * 1. ADC/DAC on Primary Interface
1333 * 2. ADC on Primary Interface/DAC on secondary 1332 * 2. ADC on Primary Interface/DAC on secondary
1334 */ 1333 */
1335struct snd_soc_dai wm8400_dai = { 1334static struct snd_soc_dai_driver wm8400_dai = {
1336/* ADC/DAC on primary */ 1335/* ADC/DAC on primary */
1337 .name = "WM8400 ADC/DAC Primary", 1336 .name = "wm8400-hifi",
1338 .id = 1,
1339 .playback = { 1337 .playback = {
1340 .stream_name = "Playback", 1338 .stream_name = "Playback",
1341 .channels_min = 1, 1339 .channels_min = 1,
@@ -1352,147 +1350,53 @@ struct snd_soc_dai wm8400_dai = {
1352 }, 1350 },
1353 .ops = &wm8400_dai_ops, 1351 .ops = &wm8400_dai_ops,
1354}; 1352};
1355EXPORT_SYMBOL_GPL(wm8400_dai);
1356 1353
1357static int wm8400_suspend(struct platform_device *pdev, pm_message_t state) 1354static int wm8400_suspend(struct snd_soc_codec *codec, pm_message_t state)
1358{ 1355{
1359 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1360 struct snd_soc_codec *codec = socdev->card->codec;
1361
1362 wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF); 1356 wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
1363 1357
1364 return 0; 1358 return 0;
1365} 1359}
1366 1360
1367static int wm8400_resume(struct platform_device *pdev) 1361static int wm8400_resume(struct snd_soc_codec *codec)
1368{ 1362{
1369 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1370 struct snd_soc_codec *codec = socdev->card->codec;
1371
1372 wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1363 wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
1373 1364
1374 return 0; 1365 return 0;
1375} 1366}
1376 1367
1377static struct snd_soc_codec *wm8400_codec;
1378
1379static int wm8400_probe(struct platform_device *pdev)
1380{
1381 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1382 struct snd_soc_codec *codec;
1383 int ret;
1384
1385 if (!wm8400_codec) {
1386 dev_err(&pdev->dev, "wm8400 not yet discovered\n");
1387 return -ENODEV;
1388 }
1389 codec = wm8400_codec;
1390
1391 socdev->card->codec = codec;
1392
1393 /* register pcms */
1394 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
1395 if (ret < 0) {
1396 dev_err(&pdev->dev, "failed to create pcms\n");
1397 goto pcm_err;
1398 }
1399
1400 wm8400_add_controls(codec);
1401 wm8400_add_widgets(codec);
1402
1403pcm_err:
1404 return ret;
1405}
1406
1407/* power down chip */
1408static int wm8400_remove(struct platform_device *pdev)
1409{
1410 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1411
1412 snd_soc_free_pcms(socdev);
1413 snd_soc_dapm_free(socdev);
1414
1415 return 0;
1416}
1417
1418struct snd_soc_codec_device soc_codec_dev_wm8400 = {
1419 .probe = wm8400_probe,
1420 .remove = wm8400_remove,
1421 .suspend = wm8400_suspend,
1422 .resume = wm8400_resume,
1423};
1424
1425static void wm8400_probe_deferred(struct work_struct *work) 1368static void wm8400_probe_deferred(struct work_struct *work)
1426{ 1369{
1427 struct wm8400_priv *priv = container_of(work, struct wm8400_priv, 1370 struct wm8400_priv *priv = container_of(work, struct wm8400_priv,
1428 work); 1371 work);
1429 struct snd_soc_codec *codec = &priv->codec; 1372 struct snd_soc_codec *codec = priv->codec;
1430 int ret;
1431 1373
1432 /* charge output caps */ 1374 /* charge output caps */
1433 wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1375 wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
1434
1435 /* We're done, tell the subsystem. */
1436 ret = snd_soc_register_codec(codec);
1437 if (ret != 0) {
1438 dev_err(priv->wm8400->dev,
1439 "Failed to register codec: %d\n", ret);
1440 goto err;
1441 }
1442
1443 ret = snd_soc_register_dai(&wm8400_dai);
1444 if (ret != 0) {
1445 dev_err(priv->wm8400->dev,
1446 "Failed to register DAI: %d\n", ret);
1447 goto err_codec;
1448 }
1449
1450 return;
1451
1452err_codec:
1453 snd_soc_unregister_codec(codec);
1454err:
1455 wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
1456} 1376}
1457 1377
1458static int wm8400_codec_probe(struct platform_device *dev) 1378static int wm8400_codec_probe(struct snd_soc_codec *codec)
1459{ 1379{
1380 struct wm8400 *wm8400 = dev_get_platdata(codec->dev);
1460 struct wm8400_priv *priv; 1381 struct wm8400_priv *priv;
1461 int ret; 1382 int ret;
1462 u16 reg; 1383 u16 reg;
1463 struct snd_soc_codec *codec;
1464 1384
1465 priv = kzalloc(sizeof(struct wm8400_priv), GFP_KERNEL); 1385 priv = kzalloc(sizeof(struct wm8400_priv), GFP_KERNEL);
1466 if (priv == NULL) 1386 if (priv == NULL)
1467 return -ENOMEM; 1387 return -ENOMEM;
1468 1388
1469 codec = &priv->codec;
1470 snd_soc_codec_set_drvdata(codec, priv); 1389 snd_soc_codec_set_drvdata(codec, priv);
1471 codec->control_data = dev_get_drvdata(&dev->dev); 1390 codec->control_data = priv->wm8400 = wm8400;
1472 priv->wm8400 = dev_get_drvdata(&dev->dev); 1391 priv->codec = codec;
1473 1392
1474 ret = regulator_bulk_get(priv->wm8400->dev, 1393 ret = regulator_bulk_get(wm8400->dev,
1475 ARRAY_SIZE(power), &power[0]); 1394 ARRAY_SIZE(power), &power[0]);
1476 if (ret != 0) { 1395 if (ret != 0) {
1477 dev_err(&dev->dev, "Failed to get regulators: %d\n", ret); 1396 dev_err(codec->dev, "Failed to get regulators: %d\n", ret);
1478 goto err; 1397 goto err;
1479 } 1398 }
1480 1399
1481 codec->dev = &dev->dev;
1482 wm8400_dai.dev = &dev->dev;
1483
1484 codec->name = "WM8400";
1485 codec->owner = THIS_MODULE;
1486 codec->read = wm8400_read;
1487 codec->write = wm8400_write;
1488 codec->bias_level = SND_SOC_BIAS_OFF;
1489 codec->set_bias_level = wm8400_set_bias_level;
1490 codec->dai = &wm8400_dai;
1491 codec->num_dai = 1;
1492 codec->reg_cache_size = WM8400_REGISTER_COUNT;
1493 mutex_init(&codec->mutex);
1494 INIT_LIST_HEAD(&codec->dapm_widgets);
1495 INIT_LIST_HEAD(&codec->dapm_paths);
1496 INIT_WORK(&priv->work, wm8400_probe_deferred); 1400 INIT_WORK(&priv->work, wm8400_probe_deferred);
1497 1401
1498 wm8400_codec_reset(codec); 1402 wm8400_codec_reset(codec);
@@ -1511,65 +1415,78 @@ static int wm8400_codec_probe(struct platform_device *dev)
1511 wm8400_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); 1415 wm8400_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
1512 wm8400_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); 1416 wm8400_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
1513 1417
1514 wm8400_codec = codec;
1515
1516 if (!schedule_work(&priv->work)) { 1418 if (!schedule_work(&priv->work)) {
1517 ret = -EINVAL; 1419 ret = -EINVAL;
1518 goto err_regulator; 1420 goto err_regulator;
1519 } 1421 }
1520 1422 wm8400_add_controls(codec);
1423 wm8400_add_widgets(codec);
1521 return 0; 1424 return 0;
1522 1425
1523err_regulator: 1426err_regulator:
1524 wm8400_codec = NULL;
1525 regulator_bulk_free(ARRAY_SIZE(power), power); 1427 regulator_bulk_free(ARRAY_SIZE(power), power);
1526err: 1428err:
1527 kfree(priv); 1429 kfree(priv);
1528 return ret; 1430 return ret;
1529} 1431}
1530 1432
1531static int __exit wm8400_codec_remove(struct platform_device *dev) 1433static int wm8400_codec_remove(struct snd_soc_codec *codec)
1532{ 1434{
1533 struct wm8400_priv *priv = snd_soc_codec_get_drvdata(wm8400_codec); 1435 struct wm8400_priv *priv = snd_soc_codec_get_drvdata(codec);
1534 u16 reg; 1436 u16 reg;
1535 1437
1536 snd_soc_unregister_dai(&wm8400_dai); 1438 reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
1537 snd_soc_unregister_codec(wm8400_codec); 1439 wm8400_write(codec, WM8400_POWER_MANAGEMENT_1,
1538
1539 reg = wm8400_read(wm8400_codec, WM8400_POWER_MANAGEMENT_1);
1540 wm8400_write(wm8400_codec, WM8400_POWER_MANAGEMENT_1,
1541 reg & (~WM8400_CODEC_ENA)); 1440 reg & (~WM8400_CODEC_ENA));
1542 1441
1543 regulator_bulk_free(ARRAY_SIZE(power), power); 1442 regulator_bulk_free(ARRAY_SIZE(power), power);
1544 kfree(priv); 1443 kfree(priv);
1545 1444
1546 wm8400_codec = NULL; 1445 return 0;
1446}
1447
1448static struct snd_soc_codec_driver soc_codec_dev_wm8400 = {
1449 .probe = wm8400_codec_probe,
1450 .remove = wm8400_codec_remove,
1451 .suspend = wm8400_suspend,
1452 .resume = wm8400_resume,
1453 .read = wm8400_read,
1454 .write = wm8400_write,
1455 .set_bias_level = wm8400_set_bias_level,
1456};
1457
1458static int __devinit wm8400_probe(struct platform_device *pdev)
1459{
1460 return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8400,
1461 &wm8400_dai, 1);
1462}
1547 1463
1464static int __devexit wm8400_remove(struct platform_device *pdev)
1465{
1466 snd_soc_unregister_codec(&pdev->dev);
1548 return 0; 1467 return 0;
1549} 1468}
1550 1469
1551static struct platform_driver wm8400_codec_driver = { 1470static struct platform_driver wm8400_codec_driver = {
1552 .driver = { 1471 .driver = {
1553 .name = "wm8400-codec", 1472 .name = "wm8400-codec",
1554 .owner = THIS_MODULE, 1473 .owner = THIS_MODULE,
1555 }, 1474 },
1556 .probe = wm8400_codec_probe, 1475 .probe = wm8400_probe,
1557 .remove = __exit_p(wm8400_codec_remove), 1476 .remove = __devexit_p(wm8400_remove),
1558}; 1477};
1559 1478
1560static int __init wm8400_codec_init(void) 1479static __init int wm8400_init(void)
1561{ 1480{
1562 return platform_driver_register(&wm8400_codec_driver); 1481 return platform_driver_register(&wm8400_codec_driver);
1563} 1482}
1564module_init(wm8400_codec_init); 1483module_init(wm8400_init);
1565 1484
1566static void __exit wm8400_codec_exit(void) 1485static __exit void wm8400_exit(void)
1567{ 1486{
1568 platform_driver_unregister(&wm8400_codec_driver); 1487 platform_driver_unregister(&wm8400_codec_driver);
1569} 1488}
1570module_exit(wm8400_codec_exit); 1489module_exit(wm8400_exit);
1571
1572EXPORT_SYMBOL_GPL(soc_codec_dev_wm8400);
1573 1490
1574MODULE_DESCRIPTION("ASoC WM8400 driver"); 1491MODULE_DESCRIPTION("ASoC WM8400 driver");
1575MODULE_AUTHOR("Mark Brown"); 1492MODULE_AUTHOR("Mark Brown");