aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8350.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/wm8350.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/wm8350.c')
-rw-r--r--sound/soc/codecs/wm8350.c231
1 files changed, 84 insertions, 147 deletions
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index 0221ca79b3ae..f4f1fba38eb9 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -1321,20 +1321,14 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
1321 return 0; 1321 return 0;
1322} 1322}
1323 1323
1324static int wm8350_suspend(struct platform_device *pdev, pm_message_t state) 1324static int wm8350_suspend(struct snd_soc_codec *codec, pm_message_t state)
1325{ 1325{
1326 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1327 struct snd_soc_codec *codec = socdev->card->codec;
1328
1329 wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF); 1326 wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF);
1330 return 0; 1327 return 0;
1331} 1328}
1332 1329
1333static int wm8350_resume(struct platform_device *pdev) 1330static int wm8350_resume(struct snd_soc_codec *codec)
1334{ 1331{
1335 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1336 struct snd_soc_codec *codec = socdev->card->codec;
1337
1338 wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1332 wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
1339 1333
1340 return 0; 1334 return 0;
@@ -1489,24 +1483,74 @@ int wm8350_mic_jack_detect(struct snd_soc_codec *codec,
1489} 1483}
1490EXPORT_SYMBOL_GPL(wm8350_mic_jack_detect); 1484EXPORT_SYMBOL_GPL(wm8350_mic_jack_detect);
1491 1485
1492static struct snd_soc_codec *wm8350_codec; 1486#define WM8350_RATES (SNDRV_PCM_RATE_8000_96000)
1487
1488#define WM8350_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
1489 SNDRV_PCM_FMTBIT_S20_3LE |\
1490 SNDRV_PCM_FMTBIT_S24_LE)
1491
1492static struct snd_soc_dai_ops wm8350_dai_ops = {
1493 .hw_params = wm8350_pcm_hw_params,
1494 .digital_mute = wm8350_mute,
1495 .trigger = wm8350_pcm_trigger,
1496 .set_fmt = wm8350_set_dai_fmt,
1497 .set_sysclk = wm8350_set_dai_sysclk,
1498 .set_pll = wm8350_set_fll,
1499 .set_clkdiv = wm8350_set_clkdiv,
1500};
1501
1502static struct snd_soc_dai_driver wm8350_dai = {
1503 .name = "wm8350-hifi",
1504 .playback = {
1505 .stream_name = "Playback",
1506 .channels_min = 1,
1507 .channels_max = 2,
1508 .rates = WM8350_RATES,
1509 .formats = WM8350_FORMATS,
1510 },
1511 .capture = {
1512 .stream_name = "Capture",
1513 .channels_min = 1,
1514 .channels_max = 2,
1515 .rates = WM8350_RATES,
1516 .formats = WM8350_FORMATS,
1517 },
1518 .ops = &wm8350_dai_ops,
1519};
1493 1520
1494static int wm8350_probe(struct platform_device *pdev) 1521static int wm8350_codec_probe(struct snd_soc_codec *codec)
1495{ 1522{
1496 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 1523 struct wm8350 *wm8350 = dev_get_platdata(codec->dev);
1497 struct snd_soc_codec *codec;
1498 struct wm8350 *wm8350;
1499 struct wm8350_data *priv; 1524 struct wm8350_data *priv;
1500 int ret;
1501 struct wm8350_output *out1; 1525 struct wm8350_output *out1;
1502 struct wm8350_output *out2; 1526 struct wm8350_output *out2;
1527 int ret, i;
1503 1528
1504 BUG_ON(!wm8350_codec); 1529 if (wm8350->codec.platform_data == NULL) {
1530 dev_err(codec->dev, "No audio platform data supplied\n");
1531 return -EINVAL;
1532 }
1533
1534 priv = kzalloc(sizeof(struct wm8350_data), GFP_KERNEL);
1535 if (priv == NULL)
1536 return -ENOMEM;
1537 snd_soc_codec_set_drvdata(codec, priv);
1538
1539 for (i = 0; i < ARRAY_SIZE(supply_names); i++)
1540 priv->supplies[i].supply = supply_names[i];
1541
1542 ret = regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies),
1543 priv->supplies);
1544 if (ret != 0)
1545 goto err_priv;
1546
1547 wm8350->codec.codec = codec;
1548 codec->control_data = wm8350;
1505 1549
1506 socdev->card->codec = wm8350_codec; 1550 /* Put the codec into reset if it wasn't already */
1507 codec = socdev->card->codec; 1551 wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
1508 wm8350 = codec->control_data; 1552
1509 priv = snd_soc_codec_get_drvdata(codec); 1553 INIT_DELAYED_WORK(&codec->delayed_work, wm8350_pga_work);
1510 1554
1511 /* Enable the codec */ 1555 /* Enable the codec */
1512 wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); 1556 wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
@@ -1557,11 +1601,6 @@ static int wm8350_probe(struct platform_device *pdev)
1557 wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD, 1601 wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD,
1558 wm8350_mic_handler, 0, "Microphone detect", priv); 1602 wm8350_mic_handler, 0, "Microphone detect", priv);
1559 1603
1560 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
1561 if (ret < 0) {
1562 dev_err(&pdev->dev, "failed to create pcms\n");
1563 return ret;
1564 }
1565 1604
1566 snd_soc_add_controls(codec, wm8350_snd_controls, 1605 snd_soc_add_controls(codec, wm8350_snd_controls,
1567 ARRAY_SIZE(wm8350_snd_controls)); 1606 ARRAY_SIZE(wm8350_snd_controls));
@@ -1570,14 +1609,16 @@ static int wm8350_probe(struct platform_device *pdev)
1570 wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1609 wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
1571 1610
1572 return 0; 1611 return 0;
1612
1613err_priv:
1614 kfree(priv);
1615 return ret;
1573} 1616}
1574 1617
1575static int wm8350_remove(struct platform_device *pdev) 1618static int wm8350_codec_remove(struct snd_soc_codec *codec)
1576{ 1619{
1577 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1578 struct snd_soc_codec *codec = socdev->card->codec;
1579 struct wm8350 *wm8350 = codec->control_data;
1580 struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec); 1620 struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
1621 struct wm8350 *wm8350 = dev_get_platdata(codec->dev);
1581 int ret; 1622 int ret;
1582 1623
1583 wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, 1624 wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
@@ -1607,134 +1648,30 @@ static int wm8350_remove(struct platform_device *pdev)
1607 1648
1608 wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); 1649 wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
1609 1650
1651 regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
1652 kfree(priv);
1610 return 0; 1653 return 0;
1611} 1654}
1612 1655
1613#define WM8350_RATES (SNDRV_PCM_RATE_8000_96000) 1656static struct snd_soc_codec_driver soc_codec_dev_wm8350 = {
1614 1657 .probe = wm8350_codec_probe,
1615#define WM8350_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ 1658 .remove = wm8350_codec_remove,
1616 SNDRV_PCM_FMTBIT_S20_3LE |\
1617 SNDRV_PCM_FMTBIT_S24_LE)
1618
1619static struct snd_soc_dai_ops wm8350_dai_ops = {
1620 .hw_params = wm8350_pcm_hw_params,
1621 .digital_mute = wm8350_mute,
1622 .trigger = wm8350_pcm_trigger,
1623 .set_fmt = wm8350_set_dai_fmt,
1624 .set_sysclk = wm8350_set_dai_sysclk,
1625 .set_pll = wm8350_set_fll,
1626 .set_clkdiv = wm8350_set_clkdiv,
1627};
1628
1629struct snd_soc_dai wm8350_dai = {
1630 .name = "WM8350",
1631 .playback = {
1632 .stream_name = "Playback",
1633 .channels_min = 1,
1634 .channels_max = 2,
1635 .rates = WM8350_RATES,
1636 .formats = WM8350_FORMATS,
1637 },
1638 .capture = {
1639 .stream_name = "Capture",
1640 .channels_min = 1,
1641 .channels_max = 2,
1642 .rates = WM8350_RATES,
1643 .formats = WM8350_FORMATS,
1644 },
1645 .ops = &wm8350_dai_ops,
1646};
1647EXPORT_SYMBOL_GPL(wm8350_dai);
1648
1649struct snd_soc_codec_device soc_codec_dev_wm8350 = {
1650 .probe = wm8350_probe,
1651 .remove = wm8350_remove,
1652 .suspend = wm8350_suspend, 1659 .suspend = wm8350_suspend,
1653 .resume = wm8350_resume, 1660 .resume = wm8350_resume,
1661 .read = wm8350_codec_read,
1662 .write = wm8350_codec_write,
1663 .set_bias_level = wm8350_set_bias_level,
1654}; 1664};
1655EXPORT_SYMBOL_GPL(soc_codec_dev_wm8350);
1656 1665
1657static __devinit int wm8350_codec_probe(struct platform_device *pdev) 1666static int __devinit wm8350_probe(struct platform_device *pdev)
1658{ 1667{
1659 struct wm8350 *wm8350 = platform_get_drvdata(pdev); 1668 return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8350,
1660 struct wm8350_data *priv; 1669 &wm8350_dai, 1);
1661 struct snd_soc_codec *codec;
1662 int ret, i;
1663
1664 if (wm8350->codec.platform_data == NULL) {
1665 dev_err(&pdev->dev, "No audio platform data supplied\n");
1666 return -EINVAL;
1667 }
1668
1669 priv = kzalloc(sizeof(struct wm8350_data), GFP_KERNEL);
1670 if (priv == NULL)
1671 return -ENOMEM;
1672
1673 for (i = 0; i < ARRAY_SIZE(supply_names); i++)
1674 priv->supplies[i].supply = supply_names[i];
1675
1676 ret = regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies),
1677 priv->supplies);
1678 if (ret != 0)
1679 goto err_priv;
1680
1681 codec = &priv->codec;
1682 wm8350->codec.codec = codec;
1683
1684 wm8350_dai.dev = &pdev->dev;
1685
1686 mutex_init(&codec->mutex);
1687 INIT_LIST_HEAD(&codec->dapm_widgets);
1688 INIT_LIST_HEAD(&codec->dapm_paths);
1689 codec->dev = &pdev->dev;
1690 codec->name = "WM8350";
1691 codec->owner = THIS_MODULE;
1692 codec->read = wm8350_codec_read;
1693 codec->write = wm8350_codec_write;
1694 codec->bias_level = SND_SOC_BIAS_OFF;
1695 codec->set_bias_level = wm8350_set_bias_level;
1696 codec->dai = &wm8350_dai;
1697 codec->num_dai = 1;
1698 codec->reg_cache_size = WM8350_MAX_REGISTER;
1699 snd_soc_codec_set_drvdata(codec, priv);
1700 codec->control_data = wm8350;
1701
1702 /* Put the codec into reset if it wasn't already */
1703 wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
1704
1705 INIT_DELAYED_WORK(&codec->delayed_work, wm8350_pga_work);
1706 ret = snd_soc_register_codec(codec);
1707 if (ret != 0)
1708 goto err_supply;
1709
1710 wm8350_codec = codec;
1711
1712 ret = snd_soc_register_dai(&wm8350_dai);
1713 if (ret != 0)
1714 goto err_codec;
1715 return 0;
1716
1717err_codec:
1718 snd_soc_unregister_codec(codec);
1719err_supply:
1720 regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
1721err_priv:
1722 kfree(priv);
1723 wm8350_codec = NULL;
1724 return ret;
1725} 1670}
1726 1671
1727static int __devexit wm8350_codec_remove(struct platform_device *pdev) 1672static int __devexit wm8350_remove(struct platform_device *pdev)
1728{ 1673{
1729 struct wm8350 *wm8350 = platform_get_drvdata(pdev); 1674 snd_soc_unregister_codec(&pdev->dev);
1730 struct snd_soc_codec *codec = wm8350->codec.codec;
1731 struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
1732
1733 snd_soc_unregister_dai(&wm8350_dai);
1734 snd_soc_unregister_codec(codec);
1735 regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
1736 kfree(priv);
1737 wm8350_codec = NULL;
1738 return 0; 1675 return 0;
1739} 1676}
1740 1677
@@ -1743,8 +1680,8 @@ static struct platform_driver wm8350_codec_driver = {
1743 .name = "wm8350-codec", 1680 .name = "wm8350-codec",
1744 .owner = THIS_MODULE, 1681 .owner = THIS_MODULE,
1745 }, 1682 },
1746 .probe = wm8350_codec_probe, 1683 .probe = wm8350_probe,
1747 .remove = __devexit_p(wm8350_codec_remove), 1684 .remove = __devexit_p(wm8350_remove),
1748}; 1685};
1749 1686
1750static __init int wm8350_init(void) 1687static __init int wm8350_init(void)