diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2008-12-10 13:36:42 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2008-12-10 14:47:44 -0500 |
commit | d58d5d5567ea9483346f57c83a94ce05992cd47c (patch) | |
tree | 068237c7f8fa0a2290bac0d0e80125677cc1697e /sound/soc | |
parent | 78e19a39d3985e2a06354493a70a200c0d432de5 (diff) |
ASoC: Convert WM8903 driver to register at I2C probe time
The driver now registers the codec and DAI when probed as an I2C device.
Also convert the driver to use a single dynamic allocation to simplify
error handling.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/codecs/wm8903.c | 230 | ||||
-rw-r--r-- | sound/soc/codecs/wm8903.h | 5 |
2 files changed, 97 insertions, 138 deletions
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index b1f5cf77a876..c80968fe326e 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c | |||
@@ -33,19 +33,6 @@ | |||
33 | 33 | ||
34 | #include "wm8903.h" | 34 | #include "wm8903.h" |
35 | 35 | ||
36 | struct wm8903_priv { | ||
37 | int sysclk; | ||
38 | |||
39 | /* Reference counts */ | ||
40 | int charge_pump_users; | ||
41 | int class_w_users; | ||
42 | int playback_active; | ||
43 | int capture_active; | ||
44 | |||
45 | struct snd_pcm_substream *master_substream; | ||
46 | struct snd_pcm_substream *slave_substream; | ||
47 | }; | ||
48 | |||
49 | /* Register defaults at reset */ | 36 | /* Register defaults at reset */ |
50 | static u16 wm8903_reg_defaults[] = { | 37 | static u16 wm8903_reg_defaults[] = { |
51 | 0x8903, /* R0 - SW Reset and ID */ | 38 | 0x8903, /* R0 - SW Reset and ID */ |
@@ -223,6 +210,23 @@ static u16 wm8903_reg_defaults[] = { | |||
223 | 0x0000, /* R172 - Analogue Output Bias 0 */ | 210 | 0x0000, /* R172 - Analogue Output Bias 0 */ |
224 | }; | 211 | }; |
225 | 212 | ||
213 | struct wm8903_priv { | ||
214 | struct snd_soc_codec codec; | ||
215 | u16 reg_cache[ARRAY_SIZE(wm8903_reg_defaults)]; | ||
216 | |||
217 | int sysclk; | ||
218 | |||
219 | /* Reference counts */ | ||
220 | int charge_pump_users; | ||
221 | int class_w_users; | ||
222 | int playback_active; | ||
223 | int capture_active; | ||
224 | |||
225 | struct snd_pcm_substream *master_substream; | ||
226 | struct snd_pcm_substream *slave_substream; | ||
227 | }; | ||
228 | |||
229 | |||
226 | static unsigned int wm8903_read_reg_cache(struct snd_soc_codec *codec, | 230 | static unsigned int wm8903_read_reg_cache(struct snd_soc_codec *codec, |
227 | unsigned int reg) | 231 | unsigned int reg) |
228 | { | 232 | { |
@@ -360,6 +364,8 @@ static void wm8903_sync_reg_cache(struct snd_soc_codec *codec, u16 *cache) | |||
360 | static void wm8903_reset(struct snd_soc_codec *codec) | 364 | static void wm8903_reset(struct snd_soc_codec *codec) |
361 | { | 365 | { |
362 | wm8903_write(codec, WM8903_SW_RESET_AND_ID, 0); | 366 | wm8903_write(codec, WM8903_SW_RESET_AND_ID, 0); |
367 | memcpy(codec->reg_cache, wm8903_reg_defaults, | ||
368 | sizeof(wm8903_reg_defaults)); | ||
363 | } | 369 | } |
364 | 370 | ||
365 | #define WM8903_OUTPUT_SHORT 0x8 | 371 | #define WM8903_OUTPUT_SHORT 0x8 |
@@ -1563,39 +1569,48 @@ static int wm8903_resume(struct platform_device *pdev) | |||
1563 | return 0; | 1569 | return 0; |
1564 | } | 1570 | } |
1565 | 1571 | ||
1566 | /* | 1572 | static struct snd_soc_codec *wm8903_codec; |
1567 | * initialise the WM8903 driver | 1573 | |
1568 | * register the mixer and dsp interfaces with the kernel | 1574 | static int wm8903_i2c_probe(struct i2c_client *i2c, |
1569 | */ | 1575 | const struct i2c_device_id *id) |
1570 | static int wm8903_init(struct snd_soc_device *socdev) | ||
1571 | { | 1576 | { |
1572 | struct snd_soc_codec *codec = socdev->codec; | 1577 | struct wm8903_priv *wm8903; |
1573 | struct i2c_client *i2c = codec->control_data; | 1578 | struct snd_soc_codec *codec; |
1574 | int ret = 0; | 1579 | int ret; |
1575 | u16 val; | 1580 | u16 val; |
1576 | 1581 | ||
1577 | val = wm8903_hw_read(codec, WM8903_SW_RESET_AND_ID); | 1582 | wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL); |
1578 | if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) { | 1583 | if (wm8903 == NULL) |
1579 | dev_err(&i2c->dev, | 1584 | return -ENOMEM; |
1580 | "Device with ID register %x is not a WM8903\n", val); | ||
1581 | return -ENODEV; | ||
1582 | } | ||
1583 | 1585 | ||
1586 | codec = &wm8903->codec; | ||
1587 | |||
1588 | mutex_init(&codec->mutex); | ||
1589 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1590 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1591 | |||
1592 | codec->dev = &i2c->dev; | ||
1584 | codec->name = "WM8903"; | 1593 | codec->name = "WM8903"; |
1585 | codec->owner = THIS_MODULE; | 1594 | codec->owner = THIS_MODULE; |
1586 | codec->read = wm8903_read; | 1595 | codec->read = wm8903_read; |
1587 | codec->write = wm8903_write; | 1596 | codec->write = wm8903_write; |
1597 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1588 | codec->bias_level = SND_SOC_BIAS_OFF; | 1598 | codec->bias_level = SND_SOC_BIAS_OFF; |
1589 | codec->set_bias_level = wm8903_set_bias_level; | 1599 | codec->set_bias_level = wm8903_set_bias_level; |
1590 | codec->dai = &wm8903_dai; | 1600 | codec->dai = &wm8903_dai; |
1591 | codec->num_dai = 1; | 1601 | codec->num_dai = 1; |
1592 | codec->reg_cache_size = ARRAY_SIZE(wm8903_reg_defaults); | 1602 | codec->reg_cache_size = ARRAY_SIZE(wm8903->reg_cache); |
1593 | codec->reg_cache = kmemdup(wm8903_reg_defaults, | 1603 | codec->reg_cache = &wm8903->reg_cache[0]; |
1594 | sizeof(wm8903_reg_defaults), | 1604 | codec->private_data = wm8903; |
1595 | GFP_KERNEL); | 1605 | |
1596 | if (codec->reg_cache == NULL) { | 1606 | i2c_set_clientdata(i2c, codec); |
1597 | dev_err(&i2c->dev, "Failed to allocate register cache\n"); | 1607 | codec->control_data = i2c; |
1598 | return -ENOMEM; | 1608 | |
1609 | val = wm8903_hw_read(codec, WM8903_SW_RESET_AND_ID); | ||
1610 | if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) { | ||
1611 | dev_err(&i2c->dev, | ||
1612 | "Device with ID register %x is not a WM8903\n", val); | ||
1613 | return -ENODEV; | ||
1599 | } | 1614 | } |
1600 | 1615 | ||
1601 | val = wm8903_read(codec, WM8903_REVISION_NUMBER); | 1616 | val = wm8903_read(codec, WM8903_REVISION_NUMBER); |
@@ -1604,13 +1619,6 @@ static int wm8903_init(struct snd_soc_device *socdev) | |||
1604 | 1619 | ||
1605 | wm8903_reset(codec); | 1620 | wm8903_reset(codec); |
1606 | 1621 | ||
1607 | /* register pcms */ | ||
1608 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
1609 | if (ret < 0) { | ||
1610 | dev_err(&i2c->dev, "failed to create pcms\n"); | ||
1611 | goto pcm_err; | ||
1612 | } | ||
1613 | |||
1614 | /* SYSCLK is required for pretty much anything */ | 1622 | /* SYSCLK is required for pretty much anything */ |
1615 | wm8903_write(codec, WM8903_CLOCK_RATES_2, WM8903_CLK_SYS_ENA); | 1623 | wm8903_write(codec, WM8903_CLOCK_RATES_2, WM8903_CLK_SYS_ENA); |
1616 | 1624 | ||
@@ -1648,47 +1656,45 @@ static int wm8903_init(struct snd_soc_device *socdev) | |||
1648 | val |= WM8903_DAC_MUTEMODE; | 1656 | val |= WM8903_DAC_MUTEMODE; |
1649 | wm8903_write(codec, WM8903_DAC_DIGITAL_1, val); | 1657 | wm8903_write(codec, WM8903_DAC_DIGITAL_1, val); |
1650 | 1658 | ||
1651 | wm8903_add_controls(codec); | 1659 | wm8903_dai.dev = &i2c->dev; |
1652 | wm8903_add_widgets(codec); | 1660 | wm8903_codec = codec; |
1653 | ret = snd_soc_init_card(socdev); | 1661 | |
1654 | if (ret < 0) { | 1662 | ret = snd_soc_register_codec(codec); |
1655 | dev_err(&i2c->dev, "wm8903: failed to register card\n"); | 1663 | if (ret != 0) { |
1656 | goto card_err; | 1664 | dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); |
1665 | goto err; | ||
1666 | } | ||
1667 | |||
1668 | ret = snd_soc_register_dai(&wm8903_dai); | ||
1669 | if (ret != 0) { | ||
1670 | dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret); | ||
1671 | goto err_codec; | ||
1657 | } | 1672 | } |
1658 | 1673 | ||
1659 | return ret; | 1674 | return ret; |
1660 | 1675 | ||
1661 | card_err: | 1676 | err_codec: |
1662 | snd_soc_free_pcms(socdev); | 1677 | snd_soc_unregister_codec(codec); |
1663 | snd_soc_dapm_free(socdev); | 1678 | err: |
1664 | pcm_err: | 1679 | wm8903_codec = NULL; |
1665 | kfree(codec->reg_cache); | 1680 | kfree(wm8903); |
1666 | return ret; | 1681 | return ret; |
1667 | } | 1682 | } |
1668 | 1683 | ||
1669 | static struct snd_soc_device *wm8903_socdev; | 1684 | static int wm8903_i2c_remove(struct i2c_client *client) |
1670 | |||
1671 | static int wm8903_i2c_probe(struct i2c_client *i2c, | ||
1672 | const struct i2c_device_id *id) | ||
1673 | { | 1685 | { |
1674 | struct snd_soc_device *socdev = wm8903_socdev; | 1686 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
1675 | struct snd_soc_codec *codec = socdev->codec; | ||
1676 | int ret; | ||
1677 | 1687 | ||
1678 | i2c_set_clientdata(i2c, codec); | 1688 | snd_soc_unregister_dai(&wm8903_dai); |
1679 | codec->control_data = i2c; | 1689 | snd_soc_unregister_codec(codec); |
1680 | 1690 | ||
1681 | ret = wm8903_init(socdev); | 1691 | wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1682 | if (ret < 0) | ||
1683 | dev_err(&i2c->dev, "Device initialisation failed\n"); | ||
1684 | 1692 | ||
1685 | return ret; | 1693 | kfree(codec->private_data); |
1686 | } | 1694 | |
1695 | wm8903_codec = NULL; | ||
1696 | wm8903_dai.dev = NULL; | ||
1687 | 1697 | ||
1688 | static int wm8903_i2c_remove(struct i2c_client *client) | ||
1689 | { | ||
1690 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
1691 | kfree(codec->reg_cache); | ||
1692 | return 0; | 1698 | return 0; |
1693 | } | 1699 | } |
1694 | 1700 | ||
@@ -1712,75 +1718,37 @@ static struct i2c_driver wm8903_i2c_driver = { | |||
1712 | static int wm8903_probe(struct platform_device *pdev) | 1718 | static int wm8903_probe(struct platform_device *pdev) |
1713 | { | 1719 | { |
1714 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1720 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1715 | struct wm8903_setup_data *setup; | ||
1716 | struct snd_soc_codec *codec; | ||
1717 | struct wm8903_priv *wm8903; | ||
1718 | struct i2c_board_info board_info; | ||
1719 | struct i2c_adapter *adapter; | ||
1720 | struct i2c_client *i2c_client; | ||
1721 | int ret = 0; | 1721 | int ret = 0; |
1722 | 1722 | ||
1723 | setup = socdev->codec_data; | 1723 | if (!wm8903_codec) { |
1724 | 1724 | dev_err(&pdev->dev, "I2C device not yet probed\n"); | |
1725 | if (!setup->i2c_address) { | 1725 | goto err; |
1726 | dev_err(&pdev->dev, "No codec address provided\n"); | ||
1727 | return -ENODEV; | ||
1728 | } | 1726 | } |
1729 | 1727 | ||
1730 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 1728 | socdev->codec = wm8903_codec; |
1731 | if (codec == NULL) | ||
1732 | return -ENOMEM; | ||
1733 | 1729 | ||
1734 | wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL); | 1730 | /* register pcms */ |
1735 | if (wm8903 == NULL) { | 1731 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
1736 | ret = -ENOMEM; | 1732 | if (ret < 0) { |
1737 | goto err_codec; | 1733 | dev_err(&pdev->dev, "failed to create pcms\n"); |
1734 | goto err; | ||
1738 | } | 1735 | } |
1739 | 1736 | ||
1740 | codec->private_data = wm8903; | 1737 | wm8903_add_controls(socdev->codec); |
1741 | socdev->codec = codec; | 1738 | wm8903_add_widgets(socdev->codec); |
1742 | mutex_init(&codec->mutex); | ||
1743 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1744 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1745 | 1739 | ||
1746 | wm8903_socdev = socdev; | 1740 | ret = snd_soc_init_card(socdev); |
1747 | 1741 | if (ret < 0) { | |
1748 | codec->hw_write = (hw_write_t)i2c_master_send; | 1742 | dev_err(&pdev->dev, "wm8903: failed to register card\n"); |
1749 | ret = i2c_add_driver(&wm8903_i2c_driver); | 1743 | goto card_err; |
1750 | if (ret != 0) { | ||
1751 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
1752 | goto err_priv; | ||
1753 | } else { | ||
1754 | memset(&board_info, 0, sizeof(board_info)); | ||
1755 | strlcpy(board_info.type, "wm8903", I2C_NAME_SIZE); | ||
1756 | board_info.addr = setup->i2c_address; | ||
1757 | |||
1758 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
1759 | if (!adapter) { | ||
1760 | dev_err(&pdev->dev, "Can't get I2C bus %d\n", | ||
1761 | setup->i2c_bus); | ||
1762 | ret = -ENODEV; | ||
1763 | goto err_adapter; | ||
1764 | } | ||
1765 | |||
1766 | i2c_client = i2c_new_device(adapter, &board_info); | ||
1767 | i2c_put_adapter(adapter); | ||
1768 | if (i2c_client == NULL) { | ||
1769 | dev_err(&pdev->dev, | ||
1770 | "I2C driver registration failed\n"); | ||
1771 | ret = -ENODEV; | ||
1772 | goto err_adapter; | ||
1773 | } | ||
1774 | } | 1744 | } |
1775 | 1745 | ||
1776 | return ret; | 1746 | return ret; |
1777 | 1747 | ||
1778 | err_adapter: | 1748 | card_err: |
1779 | i2c_del_driver(&wm8903_i2c_driver); | 1749 | snd_soc_free_pcms(socdev); |
1780 | err_priv: | 1750 | snd_soc_dapm_free(socdev); |
1781 | kfree(codec->private_data); | 1751 | err: |
1782 | err_codec: | ||
1783 | kfree(codec); | ||
1784 | return ret; | 1752 | return ret; |
1785 | } | 1753 | } |
1786 | 1754 | ||
@@ -1795,10 +1763,6 @@ static int wm8903_remove(struct platform_device *pdev) | |||
1795 | 1763 | ||
1796 | snd_soc_free_pcms(socdev); | 1764 | snd_soc_free_pcms(socdev); |
1797 | snd_soc_dapm_free(socdev); | 1765 | snd_soc_dapm_free(socdev); |
1798 | i2c_unregister_device(socdev->codec->control_data); | ||
1799 | i2c_del_driver(&wm8903_i2c_driver); | ||
1800 | kfree(codec->private_data); | ||
1801 | kfree(codec); | ||
1802 | 1766 | ||
1803 | return 0; | 1767 | return 0; |
1804 | } | 1768 | } |
@@ -1813,13 +1777,13 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8903); | |||
1813 | 1777 | ||
1814 | static int __init wm8903_modinit(void) | 1778 | static int __init wm8903_modinit(void) |
1815 | { | 1779 | { |
1816 | return snd_soc_register_dai(&wm8903_dai); | 1780 | return i2c_add_driver(&wm8903_i2c_driver); |
1817 | } | 1781 | } |
1818 | module_init(wm8903_modinit); | 1782 | module_init(wm8903_modinit); |
1819 | 1783 | ||
1820 | static void __exit wm8903_exit(void) | 1784 | static void __exit wm8903_exit(void) |
1821 | { | 1785 | { |
1822 | snd_soc_unregister_dai(&wm8903_dai); | 1786 | i2c_del_driver(&wm8903_i2c_driver); |
1823 | } | 1787 | } |
1824 | module_exit(wm8903_exit); | 1788 | module_exit(wm8903_exit); |
1825 | 1789 | ||
diff --git a/sound/soc/codecs/wm8903.h b/sound/soc/codecs/wm8903.h index cec622f2f660..0ea27e2b9963 100644 --- a/sound/soc/codecs/wm8903.h +++ b/sound/soc/codecs/wm8903.h | |||
@@ -18,11 +18,6 @@ | |||
18 | extern struct snd_soc_dai wm8903_dai; | 18 | extern struct snd_soc_dai wm8903_dai; |
19 | extern struct snd_soc_codec_device soc_codec_dev_wm8903; | 19 | extern struct snd_soc_codec_device soc_codec_dev_wm8903; |
20 | 20 | ||
21 | struct wm8903_setup_data { | ||
22 | int i2c_bus; | ||
23 | int i2c_address; | ||
24 | }; | ||
25 | |||
26 | #define WM8903_MCLK_DIV_2 1 | 21 | #define WM8903_MCLK_DIV_2 1 |
27 | #define WM8903_CLK_SYS 2 | 22 | #define WM8903_CLK_SYS 2 |
28 | #define WM8903_BCLK 3 | 23 | #define WM8903_BCLK 3 |