Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+121
+1
include/sound/wm8962.h
··· 15 15 #define WM8962_GPIO_SET 0x10000 16 16 17 17 struct wm8962_pdata { 18 + int gpio_base; 18 19 u32 gpio_init[WM8962_MAX_GPIO]; 19 20 20 21 /* Setup for microphone detection, raw value to be written to
+119
sound/soc/codecs/wm8962.c
··· 17 17 #include <linux/delay.h> 18 18 #include <linux/pm.h> 19 19 #include <linux/gcd.h> 20 + #include <linux/gpio.h> 20 21 #include <linux/i2c.h> 21 22 #include <linux/input.h> 22 23 #include <linux/platform_device.h> ··· 70 69 struct input_dev *beep; 71 70 struct work_struct beep_work; 72 71 int beep_rate; 72 + #endif 73 + 74 + #ifdef CONFIG_GPIOLIB 75 + struct gpio_chip gpio_chip; 73 76 #endif 74 77 }; 75 78 ··· 1651 1646 } 1652 1647 #endif 1653 1648 1649 + #ifdef CONFIG_GPIOLIB 1650 + static inline struct wm8962_priv *gpio_to_wm8962(struct gpio_chip *chip) 1651 + { 1652 + return container_of(chip, struct wm8962_priv, gpio_chip); 1653 + } 1654 + 1655 + static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset) 1656 + { 1657 + struct wm8962_priv *wm8962 = gpio_to_wm8962(chip); 1658 + struct snd_soc_codec *codec = wm8962->codec; 1659 + int mask = 0; 1660 + int val; 1661 + 1662 + /* The WM8962 GPIOs aren't linearly numbered. For simplicity 1663 + * we export linear numbers and error out if the unsupported 1664 + * ones are requsted. 1665 + */ 1666 + switch (offset + 1) { 1667 + case 2: 1668 + mask = WM8962_CLKOUT2_SEL_MASK; 1669 + val = 1 << WM8962_CLKOUT2_SEL_SHIFT; 1670 + break; 1671 + case 3: 1672 + mask = WM8962_CLKOUT3_SEL_MASK; 1673 + val = 1 << WM8962_CLKOUT3_SEL_SHIFT; 1674 + break; 1675 + case 5: 1676 + case 6: 1677 + break; 1678 + default: 1679 + return -EINVAL; 1680 + } 1681 + 1682 + /* Some of the GPIOs are behind MFP configuration */ 1683 + if (mask) 1684 + snd_soc_update_bits(codec, WM8962_ANALOGUE_CLOCKING1, 1685 + mask, val); 1686 + 1687 + return 0; 1688 + } 1689 + 1690 + static void wm8962_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 1691 + { 1692 + struct wm8962_priv *wm8962 = gpio_to_wm8962(chip); 1693 + struct snd_soc_codec *codec = wm8962->codec; 1694 + 1695 + snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset, 1696 + WM8962_GP2_LVL, value << WM8962_GP2_LVL_SHIFT); 1697 + } 1698 + 1699 + static int wm8962_gpio_direction_out(struct gpio_chip *chip, 1700 + unsigned offset, int value) 1701 + { 1702 + struct wm8962_priv *wm8962 = gpio_to_wm8962(chip); 1703 + struct snd_soc_codec *codec = wm8962->codec; 1704 + int val; 1705 + 1706 + /* Force function 1 (logic output) */ 1707 + val = (1 << WM8962_GP2_FN_SHIFT) | (value << WM8962_GP2_LVL_SHIFT); 1708 + 1709 + return snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset, 1710 + WM8962_GP2_FN_MASK | WM8962_GP2_LVL, val); 1711 + } 1712 + 1713 + static struct gpio_chip wm8962_template_chip = { 1714 + .label = "wm8962", 1715 + .owner = THIS_MODULE, 1716 + .request = wm8962_gpio_request, 1717 + .direction_output = wm8962_gpio_direction_out, 1718 + .set = wm8962_gpio_set, 1719 + .can_sleep = 1, 1720 + }; 1721 + 1722 + static void wm8962_init_gpio(struct snd_soc_codec *codec) 1723 + { 1724 + struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); 1725 + struct wm8962_pdata *pdata = dev_get_platdata(codec->dev); 1726 + int ret; 1727 + 1728 + wm8962->gpio_chip = wm8962_template_chip; 1729 + wm8962->gpio_chip.ngpio = WM8962_MAX_GPIO; 1730 + wm8962->gpio_chip.dev = codec->dev; 1731 + 1732 + if (pdata && pdata->gpio_base) 1733 + wm8962->gpio_chip.base = pdata->gpio_base; 1734 + else 1735 + wm8962->gpio_chip.base = -1; 1736 + 1737 + ret = gpiochip_add(&wm8962->gpio_chip); 1738 + if (ret != 0) 1739 + dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret); 1740 + } 1741 + 1742 + static void wm8962_free_gpio(struct snd_soc_codec *codec) 1743 + { 1744 + struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); 1745 + int ret; 1746 + 1747 + ret = gpiochip_remove(&wm8962->gpio_chip); 1748 + if (ret != 0) 1749 + dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret); 1750 + } 1751 + #else 1752 + static void wm8962_init_gpio(struct snd_soc_codec *codec) 1753 + { 1754 + } 1755 + 1756 + static void wm8962_free_gpio(struct snd_soc_codec *codec) 1757 + { 1758 + } 1759 + #endif 1760 + 1654 1761 static int wm8962_probe(struct snd_soc_codec *codec) 1655 1762 { 1656 1763 int ret; ··· 1895 1778 wm8962_add_widgets(codec); 1896 1779 1897 1780 wm8962_init_beep(codec); 1781 + wm8962_init_gpio(codec); 1898 1782 1899 1783 if (i2c->irq) { 1900 1784 if (pdata && pdata->irq_active_low) { ··· 1946 1828 if (i2c->irq) 1947 1829 free_irq(i2c->irq, codec); 1948 1830 1831 + wm8962_free_gpio(codec); 1949 1832 wm8962_free_beep(codec); 1950 1833 for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) 1951 1834 regulator_unregister_notifier(wm8962->supplies[i].consumer,
+1
sound/soc/codecs/wm8962.h
··· 181 181 #define WM8962_EQ39 0x175 182 182 #define WM8962_EQ40 0x176 183 183 #define WM8962_EQ41 0x177 184 + #define WM8962_GPIO_BASE 0x200 184 185 #define WM8962_GPIO_2 0x201 185 186 #define WM8962_GPIO_3 0x202 186 187 #define WM8962_GPIO_5 0x204