diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-09-20 12:34:58 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-10-02 17:23:04 -0400 |
commit | 3367b8d4278d1f8a28995cc5e57a995f7147cb73 (patch) | |
tree | 7aba159ed2edcc206ec8b4e61de55fb23e59ceb3 | |
parent | 205d231bfbd26bb10400518586d2a9f1b62858ee (diff) |
ASoC: Add support for WM8962 GPIO outputs
The WM8962 features five GPIOs, add support for controlling their output
state via gpiolib.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
-rw-r--r-- | include/sound/wm8962.h | 1 | ||||
-rw-r--r-- | sound/soc/codecs/wm8962.c | 119 | ||||
-rw-r--r-- | sound/soc/codecs/wm8962.h | 1 |
3 files changed, 121 insertions, 0 deletions
diff --git a/include/sound/wm8962.h b/include/sound/wm8962.h index 9722aac5a138..2b5306c503fb 100644 --- a/include/sound/wm8962.h +++ b/include/sound/wm8962.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #define WM8962_GPIO_SET 0x10000 | 15 | #define WM8962_GPIO_SET 0x10000 |
16 | 16 | ||
17 | struct wm8962_pdata { | 17 | struct wm8962_pdata { |
18 | int gpio_base; | ||
18 | u32 gpio_init[WM8962_MAX_GPIO]; | 19 | u32 gpio_init[WM8962_MAX_GPIO]; |
19 | 20 | ||
20 | /* Setup for microphone detection, raw value to be written to | 21 | /* Setup for microphone detection, raw value to be written to |
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 38cbf85688f6..eb66c66047b1 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
18 | #include <linux/pm.h> | 18 | #include <linux/pm.h> |
19 | #include <linux/gcd.h> | 19 | #include <linux/gcd.h> |
20 | #include <linux/gpio.h> | ||
20 | #include <linux/i2c.h> | 21 | #include <linux/i2c.h> |
21 | #include <linux/input.h> | 22 | #include <linux/input.h> |
22 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
@@ -70,6 +71,10 @@ struct wm8962_priv { | |||
70 | struct work_struct beep_work; | 71 | struct work_struct beep_work; |
71 | int beep_rate; | 72 | int beep_rate; |
72 | #endif | 73 | #endif |
74 | |||
75 | #ifdef CONFIG_GPIOLIB | ||
76 | struct gpio_chip gpio_chip; | ||
77 | #endif | ||
73 | }; | 78 | }; |
74 | 79 | ||
75 | /* We can't use the same notifier block for more than one supply and | 80 | /* We can't use the same notifier block for more than one supply and |
@@ -1646,6 +1651,118 @@ static void wm8962_free_beep(struct snd_soc_codec *codec) | |||
1646 | } | 1651 | } |
1647 | #endif | 1652 | #endif |
1648 | 1653 | ||
1654 | #ifdef CONFIG_GPIOLIB | ||
1655 | static inline struct wm8962_priv *gpio_to_wm8962(struct gpio_chip *chip) | ||
1656 | { | ||
1657 | return container_of(chip, struct wm8962_priv, gpio_chip); | ||
1658 | } | ||
1659 | |||
1660 | static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset) | ||
1661 | { | ||
1662 | struct wm8962_priv *wm8962 = gpio_to_wm8962(chip); | ||
1663 | struct snd_soc_codec *codec = wm8962->codec; | ||
1664 | int mask = 0; | ||
1665 | int val; | ||
1666 | |||
1667 | /* The WM8962 GPIOs aren't linearly numbered. For simplicity | ||
1668 | * we export linear numbers and error out if the unsupported | ||
1669 | * ones are requsted. | ||
1670 | */ | ||
1671 | switch (offset + 1) { | ||
1672 | case 2: | ||
1673 | mask = WM8962_CLKOUT2_SEL_MASK; | ||
1674 | val = 1 << WM8962_CLKOUT2_SEL_SHIFT; | ||
1675 | break; | ||
1676 | case 3: | ||
1677 | mask = WM8962_CLKOUT3_SEL_MASK; | ||
1678 | val = 1 << WM8962_CLKOUT3_SEL_SHIFT; | ||
1679 | break; | ||
1680 | case 5: | ||
1681 | case 6: | ||
1682 | break; | ||
1683 | default: | ||
1684 | return -EINVAL; | ||
1685 | } | ||
1686 | |||
1687 | /* Some of the GPIOs are behind MFP configuration */ | ||
1688 | if (mask) | ||
1689 | snd_soc_update_bits(codec, WM8962_ANALOGUE_CLOCKING1, | ||
1690 | mask, val); | ||
1691 | |||
1692 | return 0; | ||
1693 | } | ||
1694 | |||
1695 | static void wm8962_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
1696 | { | ||
1697 | struct wm8962_priv *wm8962 = gpio_to_wm8962(chip); | ||
1698 | struct snd_soc_codec *codec = wm8962->codec; | ||
1699 | |||
1700 | snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset, | ||
1701 | WM8962_GP2_LVL, value << WM8962_GP2_LVL_SHIFT); | ||
1702 | } | ||
1703 | |||
1704 | static int wm8962_gpio_direction_out(struct gpio_chip *chip, | ||
1705 | unsigned offset, int value) | ||
1706 | { | ||
1707 | struct wm8962_priv *wm8962 = gpio_to_wm8962(chip); | ||
1708 | struct snd_soc_codec *codec = wm8962->codec; | ||
1709 | int val; | ||
1710 | |||
1711 | /* Force function 1 (logic output) */ | ||
1712 | val = (1 << WM8962_GP2_FN_SHIFT) | (value << WM8962_GP2_LVL_SHIFT); | ||
1713 | |||
1714 | return snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset, | ||
1715 | WM8962_GP2_FN_MASK | WM8962_GP2_LVL, val); | ||
1716 | } | ||
1717 | |||
1718 | static struct gpio_chip wm8962_template_chip = { | ||
1719 | .label = "wm8962", | ||
1720 | .owner = THIS_MODULE, | ||
1721 | .request = wm8962_gpio_request, | ||
1722 | .direction_output = wm8962_gpio_direction_out, | ||
1723 | .set = wm8962_gpio_set, | ||
1724 | .can_sleep = 1, | ||
1725 | }; | ||
1726 | |||
1727 | static void wm8962_init_gpio(struct snd_soc_codec *codec) | ||
1728 | { | ||
1729 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); | ||
1730 | struct wm8962_pdata *pdata = dev_get_platdata(codec->dev); | ||
1731 | int ret; | ||
1732 | |||
1733 | wm8962->gpio_chip = wm8962_template_chip; | ||
1734 | wm8962->gpio_chip.ngpio = WM8962_MAX_GPIO; | ||
1735 | wm8962->gpio_chip.dev = codec->dev; | ||
1736 | |||
1737 | if (pdata && pdata->gpio_base) | ||
1738 | wm8962->gpio_chip.base = pdata->gpio_base; | ||
1739 | else | ||
1740 | wm8962->gpio_chip.base = -1; | ||
1741 | |||
1742 | ret = gpiochip_add(&wm8962->gpio_chip); | ||
1743 | if (ret != 0) | ||
1744 | dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret); | ||
1745 | } | ||
1746 | |||
1747 | static void wm8962_free_gpio(struct snd_soc_codec *codec) | ||
1748 | { | ||
1749 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); | ||
1750 | int ret; | ||
1751 | |||
1752 | ret = gpiochip_remove(&wm8962->gpio_chip); | ||
1753 | if (ret != 0) | ||
1754 | dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret); | ||
1755 | } | ||
1756 | #else | ||
1757 | static void wm8962_init_gpio(struct snd_soc_codec *codec) | ||
1758 | { | ||
1759 | } | ||
1760 | |||
1761 | static void wm8962_free_gpio(struct snd_soc_codec *codec) | ||
1762 | { | ||
1763 | } | ||
1764 | #endif | ||
1765 | |||
1649 | static int wm8962_probe(struct snd_soc_codec *codec) | 1766 | static int wm8962_probe(struct snd_soc_codec *codec) |
1650 | { | 1767 | { |
1651 | int ret; | 1768 | int ret; |
@@ -1778,6 +1895,7 @@ static int wm8962_probe(struct snd_soc_codec *codec) | |||
1778 | wm8962_add_widgets(codec); | 1895 | wm8962_add_widgets(codec); |
1779 | 1896 | ||
1780 | wm8962_init_beep(codec); | 1897 | wm8962_init_beep(codec); |
1898 | wm8962_init_gpio(codec); | ||
1781 | 1899 | ||
1782 | if (i2c->irq) { | 1900 | if (i2c->irq) { |
1783 | if (pdata && pdata->irq_active_low) { | 1901 | if (pdata && pdata->irq_active_low) { |
@@ -1828,6 +1946,7 @@ static int wm8962_remove(struct snd_soc_codec *codec) | |||
1828 | if (i2c->irq) | 1946 | if (i2c->irq) |
1829 | free_irq(i2c->irq, codec); | 1947 | free_irq(i2c->irq, codec); |
1830 | 1948 | ||
1949 | wm8962_free_gpio(codec); | ||
1831 | wm8962_free_beep(codec); | 1950 | wm8962_free_beep(codec); |
1832 | for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) | 1951 | for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) |
1833 | regulator_unregister_notifier(wm8962->supplies[i].consumer, | 1952 | regulator_unregister_notifier(wm8962->supplies[i].consumer, |
diff --git a/sound/soc/codecs/wm8962.h b/sound/soc/codecs/wm8962.h index 6145399acb16..fce11998b278 100644 --- a/sound/soc/codecs/wm8962.h +++ b/sound/soc/codecs/wm8962.h | |||
@@ -181,6 +181,7 @@ | |||
181 | #define WM8962_EQ39 0x175 | 181 | #define WM8962_EQ39 0x175 |
182 | #define WM8962_EQ40 0x176 | 182 | #define WM8962_EQ40 0x176 |
183 | #define WM8962_EQ41 0x177 | 183 | #define WM8962_EQ41 0x177 |
184 | #define WM8962_GPIO_BASE 0x200 | ||
184 | #define WM8962_GPIO_2 0x201 | 185 | #define WM8962_GPIO_2 0x201 |
185 | #define WM8962_GPIO_3 0x202 | 186 | #define WM8962_GPIO_3 0x202 |
186 | #define WM8962_GPIO_5 0x204 | 187 | #define WM8962_GPIO_5 0x204 |