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 |
