diff options
Diffstat (limited to 'sound/soc/codecs/wm8753.c')
-rw-r--r-- | sound/soc/codecs/wm8753.c | 181 |
1 files changed, 123 insertions, 58 deletions
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 5761164fe16d..d426eaa22185 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -2,8 +2,7 @@ | |||
2 | * wm8753.c -- WM8753 ALSA Soc Audio driver | 2 | * wm8753.c -- WM8753 ALSA Soc Audio driver |
3 | * | 3 | * |
4 | * Copyright 2003 Wolfson Microelectronics PLC. | 4 | * Copyright 2003 Wolfson Microelectronics PLC. |
5 | * Author: Liam Girdwood | 5 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | 6 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of the GNU General Public License as published by the | 8 | * under the terms of the GNU General Public License as published by the |
@@ -40,6 +39,7 @@ | |||
40 | #include <linux/pm.h> | 39 | #include <linux/pm.h> |
41 | #include <linux/i2c.h> | 40 | #include <linux/i2c.h> |
42 | #include <linux/platform_device.h> | 41 | #include <linux/platform_device.h> |
42 | #include <linux/spi/spi.h> | ||
43 | #include <sound/core.h> | 43 | #include <sound/core.h> |
44 | #include <sound/pcm.h> | 44 | #include <sound/pcm.h> |
45 | #include <sound/pcm_params.h> | 45 | #include <sound/pcm_params.h> |
@@ -51,7 +51,6 @@ | |||
51 | 51 | ||
52 | #include "wm8753.h" | 52 | #include "wm8753.h" |
53 | 53 | ||
54 | #define AUDIO_NAME "wm8753" | ||
55 | #define WM8753_VERSION "0.16" | 54 | #define WM8753_VERSION "0.16" |
56 | 55 | ||
57 | static int caps_charge = 2000; | 56 | static int caps_charge = 2000; |
@@ -583,7 +582,7 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
583 | 582 | ||
584 | /* out 4 */ | 583 | /* out 4 */ |
585 | {"Out4 Mux", "VREF", "VREF"}, | 584 | {"Out4 Mux", "VREF", "VREF"}, |
586 | {"Out4 Mux", "Capture ST", "Capture ST Mixer"}, | 585 | {"Out4 Mux", "Capture ST", "Playback Mixer"}, |
587 | {"Out4 Mux", "LOUT2", "LOUT2"}, | 586 | {"Out4 Mux", "LOUT2", "LOUT2"}, |
588 | {"Out 4", NULL, "Out4 Mux"}, | 587 | {"Out 4", NULL, "Out4 Mux"}, |
589 | {"OUT4", NULL, "Out 4"}, | 588 | {"OUT4", NULL, "Out 4"}, |
@@ -607,7 +606,7 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
607 | /* Capture Right Mux */ | 606 | /* Capture Right Mux */ |
608 | {"Capture Right Mux", "PGA", "Right Capture Volume"}, | 607 | {"Capture Right Mux", "PGA", "Right Capture Volume"}, |
609 | {"Capture Right Mux", "Line or RXP-RXN", "Line Right Mux"}, | 608 | {"Capture Right Mux", "Line or RXP-RXN", "Line Right Mux"}, |
610 | {"Capture Right Mux", "Sidetone", "Capture ST Mixer"}, | 609 | {"Capture Right Mux", "Sidetone", "Playback Mixer"}, |
611 | 610 | ||
612 | /* Mono Capture mixer-mux */ | 611 | /* Mono Capture mixer-mux */ |
613 | {"Capture Right Mixer", "Stereo", "Capture Right Mux"}, | 612 | {"Capture Right Mixer", "Stereo", "Capture Right Mux"}, |
@@ -1637,86 +1636,145 @@ static struct snd_soc_device *wm8753_socdev; | |||
1637 | * low = 0x1a | 1636 | * low = 0x1a |
1638 | * high = 0x1b | 1637 | * high = 0x1b |
1639 | */ | 1638 | */ |
1640 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
1641 | 1639 | ||
1642 | /* Magic definition of all other variables and things */ | 1640 | static int wm8753_i2c_probe(struct i2c_client *i2c, |
1643 | I2C_CLIENT_INSMOD; | 1641 | const struct i2c_device_id *id) |
1644 | |||
1645 | static struct i2c_driver wm8753_i2c_driver; | ||
1646 | static struct i2c_client client_template; | ||
1647 | |||
1648 | static int wm8753_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
1649 | { | 1642 | { |
1650 | struct snd_soc_device *socdev = wm8753_socdev; | 1643 | struct snd_soc_device *socdev = wm8753_socdev; |
1651 | struct wm8753_setup_data *setup = socdev->codec_data; | ||
1652 | struct snd_soc_codec *codec = socdev->codec; | 1644 | struct snd_soc_codec *codec = socdev->codec; |
1653 | struct i2c_client *i2c; | ||
1654 | int ret; | 1645 | int ret; |
1655 | 1646 | ||
1656 | if (addr != setup->i2c_address) | ||
1657 | return -ENODEV; | ||
1658 | |||
1659 | client_template.adapter = adap; | ||
1660 | client_template.addr = addr; | ||
1661 | |||
1662 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
1663 | if (!i2c) | ||
1664 | return -ENOMEM; | ||
1665 | |||
1666 | i2c_set_clientdata(i2c, codec); | 1647 | i2c_set_clientdata(i2c, codec); |
1667 | codec->control_data = i2c; | 1648 | codec->control_data = i2c; |
1668 | 1649 | ||
1669 | ret = i2c_attach_client(i2c); | ||
1670 | if (ret < 0) { | ||
1671 | pr_err("failed to attach codec at addr %x\n", addr); | ||
1672 | goto err; | ||
1673 | } | ||
1674 | |||
1675 | ret = wm8753_init(socdev); | 1650 | ret = wm8753_init(socdev); |
1676 | if (ret < 0) { | 1651 | if (ret < 0) |
1677 | pr_err("failed to initialise WM8753\n"); | 1652 | pr_err("failed to initialise WM8753\n"); |
1678 | goto err; | ||
1679 | } | ||
1680 | |||
1681 | return ret; | ||
1682 | 1653 | ||
1683 | err: | ||
1684 | kfree(i2c); | ||
1685 | return ret; | 1654 | return ret; |
1686 | } | 1655 | } |
1687 | 1656 | ||
1688 | static int wm8753_i2c_detach(struct i2c_client *client) | 1657 | static int wm8753_i2c_remove(struct i2c_client *client) |
1689 | { | 1658 | { |
1690 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 1659 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
1691 | i2c_detach_client(client); | ||
1692 | kfree(codec->reg_cache); | 1660 | kfree(codec->reg_cache); |
1693 | kfree(client); | ||
1694 | return 0; | 1661 | return 0; |
1695 | } | 1662 | } |
1696 | 1663 | ||
1697 | static int wm8753_i2c_attach(struct i2c_adapter *adap) | 1664 | static const struct i2c_device_id wm8753_i2c_id[] = { |
1698 | { | 1665 | { "wm8753", 0 }, |
1699 | return i2c_probe(adap, &addr_data, wm8753_codec_probe); | 1666 | { } |
1700 | } | 1667 | }; |
1668 | MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id); | ||
1701 | 1669 | ||
1702 | /* corgi i2c codec control layer */ | ||
1703 | static struct i2c_driver wm8753_i2c_driver = { | 1670 | static struct i2c_driver wm8753_i2c_driver = { |
1704 | .driver = { | 1671 | .driver = { |
1705 | .name = "WM8753 I2C Codec", | 1672 | .name = "WM8753 I2C Codec", |
1706 | .owner = THIS_MODULE, | 1673 | .owner = THIS_MODULE, |
1707 | }, | 1674 | }, |
1708 | .id = I2C_DRIVERID_WM8753, | 1675 | .probe = wm8753_i2c_probe, |
1709 | .attach_adapter = wm8753_i2c_attach, | 1676 | .remove = wm8753_i2c_remove, |
1710 | .detach_client = wm8753_i2c_detach, | 1677 | .id_table = wm8753_i2c_id, |
1711 | .command = NULL, | ||
1712 | }; | 1678 | }; |
1713 | 1679 | ||
1714 | static struct i2c_client client_template = { | 1680 | static int wm8753_add_i2c_device(struct platform_device *pdev, |
1715 | .name = "WM8753", | 1681 | const struct wm8753_setup_data *setup) |
1716 | .driver = &wm8753_i2c_driver, | 1682 | { |
1683 | struct i2c_board_info info; | ||
1684 | struct i2c_adapter *adapter; | ||
1685 | struct i2c_client *client; | ||
1686 | int ret; | ||
1687 | |||
1688 | ret = i2c_add_driver(&wm8753_i2c_driver); | ||
1689 | if (ret != 0) { | ||
1690 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
1691 | return ret; | ||
1692 | } | ||
1693 | |||
1694 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1695 | info.addr = setup->i2c_address; | ||
1696 | strlcpy(info.type, "wm8753", I2C_NAME_SIZE); | ||
1697 | |||
1698 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
1699 | if (!adapter) { | ||
1700 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
1701 | setup->i2c_bus); | ||
1702 | goto err_driver; | ||
1703 | } | ||
1704 | |||
1705 | client = i2c_new_device(adapter, &info); | ||
1706 | i2c_put_adapter(adapter); | ||
1707 | if (!client) { | ||
1708 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
1709 | (unsigned int)info.addr); | ||
1710 | goto err_driver; | ||
1711 | } | ||
1712 | |||
1713 | return 0; | ||
1714 | |||
1715 | err_driver: | ||
1716 | i2c_del_driver(&wm8753_i2c_driver); | ||
1717 | return -ENODEV; | ||
1718 | } | ||
1719 | #endif | ||
1720 | |||
1721 | #if defined(CONFIG_SPI_MASTER) | ||
1722 | static int __devinit wm8753_spi_probe(struct spi_device *spi) | ||
1723 | { | ||
1724 | struct snd_soc_device *socdev = wm8753_socdev; | ||
1725 | struct snd_soc_codec *codec = socdev->codec; | ||
1726 | int ret; | ||
1727 | |||
1728 | codec->control_data = spi; | ||
1729 | |||
1730 | ret = wm8753_init(socdev); | ||
1731 | if (ret < 0) | ||
1732 | dev_err(&spi->dev, "failed to initialise WM8753\n"); | ||
1733 | |||
1734 | return ret; | ||
1735 | } | ||
1736 | |||
1737 | static int __devexit wm8753_spi_remove(struct spi_device *spi) | ||
1738 | { | ||
1739 | return 0; | ||
1740 | } | ||
1741 | |||
1742 | static struct spi_driver wm8753_spi_driver = { | ||
1743 | .driver = { | ||
1744 | .name = "wm8753", | ||
1745 | .bus = &spi_bus_type, | ||
1746 | .owner = THIS_MODULE, | ||
1747 | }, | ||
1748 | .probe = wm8753_spi_probe, | ||
1749 | .remove = __devexit_p(wm8753_spi_remove), | ||
1717 | }; | 1750 | }; |
1751 | |||
1752 | static int wm8753_spi_write(struct spi_device *spi, const char *data, int len) | ||
1753 | { | ||
1754 | struct spi_transfer t; | ||
1755 | struct spi_message m; | ||
1756 | u8 msg[2]; | ||
1757 | |||
1758 | if (len <= 0) | ||
1759 | return 0; | ||
1760 | |||
1761 | msg[0] = data[0]; | ||
1762 | msg[1] = data[1]; | ||
1763 | |||
1764 | spi_message_init(&m); | ||
1765 | memset(&t, 0, (sizeof t)); | ||
1766 | |||
1767 | t.tx_buf = &msg[0]; | ||
1768 | t.len = len; | ||
1769 | |||
1770 | spi_message_add_tail(&t, &m); | ||
1771 | spi_sync(spi, &m); | ||
1772 | |||
1773 | return len; | ||
1774 | } | ||
1718 | #endif | 1775 | #endif |
1719 | 1776 | ||
1777 | |||
1720 | static int wm8753_probe(struct platform_device *pdev) | 1778 | static int wm8753_probe(struct platform_device *pdev) |
1721 | { | 1779 | { |
1722 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1780 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
@@ -1748,14 +1806,17 @@ static int wm8753_probe(struct platform_device *pdev) | |||
1748 | 1806 | ||
1749 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1807 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1750 | if (setup->i2c_address) { | 1808 | if (setup->i2c_address) { |
1751 | normal_i2c[0] = setup->i2c_address; | ||
1752 | codec->hw_write = (hw_write_t)i2c_master_send; | 1809 | codec->hw_write = (hw_write_t)i2c_master_send; |
1753 | ret = i2c_add_driver(&wm8753_i2c_driver); | 1810 | ret = wm8753_add_i2c_device(pdev, setup); |
1811 | } | ||
1812 | #endif | ||
1813 | #if defined(CONFIG_SPI_MASTER) | ||
1814 | if (setup->spi) { | ||
1815 | codec->hw_write = (hw_write_t)wm8753_spi_write; | ||
1816 | ret = spi_register_driver(&wm8753_spi_driver); | ||
1754 | if (ret != 0) | 1817 | if (ret != 0) |
1755 | printk(KERN_ERR "can't add i2c driver"); | 1818 | printk(KERN_ERR "can't add spi driver"); |
1756 | } | 1819 | } |
1757 | #else | ||
1758 | /* Add other interfaces here */ | ||
1759 | #endif | 1820 | #endif |
1760 | 1821 | ||
1761 | if (ret != 0) { | 1822 | if (ret != 0) { |
@@ -1796,8 +1857,12 @@ static int wm8753_remove(struct platform_device *pdev) | |||
1796 | snd_soc_free_pcms(socdev); | 1857 | snd_soc_free_pcms(socdev); |
1797 | snd_soc_dapm_free(socdev); | 1858 | snd_soc_dapm_free(socdev); |
1798 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1859 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1860 | i2c_unregister_device(codec->control_data); | ||
1799 | i2c_del_driver(&wm8753_i2c_driver); | 1861 | i2c_del_driver(&wm8753_i2c_driver); |
1800 | #endif | 1862 | #endif |
1863 | #if defined(CONFIG_SPI_MASTER) | ||
1864 | spi_unregister_driver(&wm8753_spi_driver); | ||
1865 | #endif | ||
1801 | kfree(codec->private_data); | 1866 | kfree(codec->private_data); |
1802 | kfree(codec); | 1867 | kfree(codec); |
1803 | 1868 | ||