diff options
Diffstat (limited to 'sound/soc/codecs/wm8400.c')
-rw-r--r-- | sound/soc/codecs/wm8400.c | 181 |
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 */ |
67 | struct wm8400_priv { | 67 | struct 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 | */ |
1335 | struct snd_soc_dai wm8400_dai = { | 1334 | static 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 | }; |
1355 | EXPORT_SYMBOL_GPL(wm8400_dai); | ||
1356 | 1353 | ||
1357 | static int wm8400_suspend(struct platform_device *pdev, pm_message_t state) | 1354 | static 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 | ||
1367 | static int wm8400_resume(struct platform_device *pdev) | 1361 | static 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 | ||
1377 | static struct snd_soc_codec *wm8400_codec; | ||
1378 | |||
1379 | static 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 | |||
1403 | pcm_err: | ||
1404 | return ret; | ||
1405 | } | ||
1406 | |||
1407 | /* power down chip */ | ||
1408 | static 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 | |||
1418 | struct 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 | |||
1425 | static void wm8400_probe_deferred(struct work_struct *work) | 1368 | static 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 | |||
1452 | err_codec: | ||
1453 | snd_soc_unregister_codec(codec); | ||
1454 | err: | ||
1455 | wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1456 | } | 1376 | } |
1457 | 1377 | ||
1458 | static int wm8400_codec_probe(struct platform_device *dev) | 1378 | static 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 | ||
1523 | err_regulator: | 1426 | err_regulator: |
1524 | wm8400_codec = NULL; | ||
1525 | regulator_bulk_free(ARRAY_SIZE(power), power); | 1427 | regulator_bulk_free(ARRAY_SIZE(power), power); |
1526 | err: | 1428 | err: |
1527 | kfree(priv); | 1429 | kfree(priv); |
1528 | return ret; | 1430 | return ret; |
1529 | } | 1431 | } |
1530 | 1432 | ||
1531 | static int __exit wm8400_codec_remove(struct platform_device *dev) | 1433 | static 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 | |||
1448 | static 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 | |||
1458 | static 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 | ||
1464 | static 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 | ||
1551 | static struct platform_driver wm8400_codec_driver = { | 1470 | static 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 | ||
1560 | static int __init wm8400_codec_init(void) | 1479 | static __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 | } |
1564 | module_init(wm8400_codec_init); | 1483 | module_init(wm8400_init); |
1565 | 1484 | ||
1566 | static void __exit wm8400_codec_exit(void) | 1485 | static __exit void wm8400_exit(void) |
1567 | { | 1486 | { |
1568 | platform_driver_unregister(&wm8400_codec_driver); | 1487 | platform_driver_unregister(&wm8400_codec_driver); |
1569 | } | 1488 | } |
1570 | module_exit(wm8400_codec_exit); | 1489 | module_exit(wm8400_exit); |
1571 | |||
1572 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8400); | ||
1573 | 1490 | ||
1574 | MODULE_DESCRIPTION("ASoC WM8400 driver"); | 1491 | MODULE_DESCRIPTION("ASoC WM8400 driver"); |
1575 | MODULE_AUTHOR("Mark Brown"); | 1492 | MODULE_AUTHOR("Mark Brown"); |