diff options
-rw-r--r-- | include/sound/wm8903.h | 20 | ||||
-rw-r--r-- | sound/soc/codecs/wm8903.c | 126 |
2 files changed, 144 insertions, 2 deletions
diff --git a/include/sound/wm8903.h b/include/sound/wm8903.h index b4a0db2307ef..86172cf4339f 100644 --- a/include/sound/wm8903.h +++ b/include/sound/wm8903.h | |||
@@ -37,6 +37,21 @@ | |||
37 | #define WM8903_MICBIAS_ENA_WIDTH 1 /* MICBIAS_ENA */ | 37 | #define WM8903_MICBIAS_ENA_WIDTH 1 /* MICBIAS_ENA */ |
38 | 38 | ||
39 | /* | 39 | /* |
40 | * WM8903_GPn_FN values | ||
41 | * | ||
42 | * See datasheets for list of valid values per pin | ||
43 | */ | ||
44 | #define WM8903_GPn_FN_GPIO_OUTPUT 0 | ||
45 | #define WM8903_GPn_FN_BCLK 1 | ||
46 | #define WM8903_GPn_FN_IRQ_OUTPT 2 | ||
47 | #define WM8903_GPn_FN_GPIO_INPUT 3 | ||
48 | #define WM8903_GPn_FN_MICBIAS_CURRENT_DETECT 4 | ||
49 | #define WM8903_GPn_FN_MICBIAS_SHORT_DETECT 5 | ||
50 | #define WM8903_GPn_FN_DMIC_LR_CLK_OUTPUT 6 | ||
51 | #define WM8903_GPn_FN_FLL_LOCK_OUTPUT 8 | ||
52 | #define WM8903_GPn_FN_FLL_CLOCK_OUTPUT 9 | ||
53 | |||
54 | /* | ||
40 | * R116 (0x74) - GPIO Control 1 | 55 | * R116 (0x74) - GPIO Control 1 |
41 | */ | 56 | */ |
42 | #define WM8903_GP1_FN_MASK 0x1F00 /* GP1_FN - [12:8] */ | 57 | #define WM8903_GP1_FN_MASK 0x1F00 /* GP1_FN - [12:8] */ |
@@ -231,6 +246,8 @@ | |||
231 | #define WM8903_GP5_DB_SHIFT 0 /* GP5_DB */ | 246 | #define WM8903_GP5_DB_SHIFT 0 /* GP5_DB */ |
232 | #define WM8903_GP5_DB_WIDTH 1 /* GP5_DB */ | 247 | #define WM8903_GP5_DB_WIDTH 1 /* GP5_DB */ |
233 | 248 | ||
249 | #define WM8903_NUM_GPIO 5 | ||
250 | |||
234 | struct wm8903_platform_data { | 251 | struct wm8903_platform_data { |
235 | bool irq_active_low; /* Set if IRQ active low, default high */ | 252 | bool irq_active_low; /* Set if IRQ active low, default high */ |
236 | 253 | ||
@@ -243,7 +260,8 @@ struct wm8903_platform_data { | |||
243 | 260 | ||
244 | int micdet_delay; /* Delay after microphone detection (ms) */ | 261 | int micdet_delay; /* Delay after microphone detection (ms) */ |
245 | 262 | ||
246 | u32 gpio_cfg[5]; /* Default register values for GPIO pin mux */ | 263 | int gpio_base; |
264 | u32 gpio_cfg[WM8903_NUM_GPIO]; /* Default register values for GPIO pin mux */ | ||
247 | }; | 265 | }; |
248 | 266 | ||
249 | #endif | 267 | #endif |
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index a2a446cb1807..9c4f2c4febc2 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * wm8903.c -- WM8903 ALSA SoC Audio driver | 2 | * wm8903.c -- WM8903 ALSA SoC Audio driver |
3 | * | 3 | * |
4 | * Copyright 2008 Wolfson Microelectronics | 4 | * Copyright 2008 Wolfson Microelectronics |
5 | * Copyright 2011 NVIDIA, Inc. | ||
5 | * | 6 | * |
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 7 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
7 | * | 8 | * |
@@ -19,6 +20,7 @@ | |||
19 | #include <linux/init.h> | 20 | #include <linux/init.h> |
20 | #include <linux/completion.h> | 21 | #include <linux/completion.h> |
21 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/gpio.h> | ||
22 | #include <linux/pm.h> | 24 | #include <linux/pm.h> |
23 | #include <linux/i2c.h> | 25 | #include <linux/i2c.h> |
24 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
@@ -213,6 +215,7 @@ static u16 wm8903_reg_defaults[] = { | |||
213 | }; | 215 | }; |
214 | 216 | ||
215 | struct wm8903_priv { | 217 | struct wm8903_priv { |
218 | struct snd_soc_codec *codec; | ||
216 | 219 | ||
217 | int sysclk; | 220 | int sysclk; |
218 | int irq; | 221 | int irq; |
@@ -230,6 +233,10 @@ struct wm8903_priv { | |||
230 | int mic_short; | 233 | int mic_short; |
231 | int mic_last_report; | 234 | int mic_last_report; |
232 | int mic_delay; | 235 | int mic_delay; |
236 | |||
237 | #ifdef CONFIG_GPIOLIB | ||
238 | struct gpio_chip gpio_chip; | ||
239 | #endif | ||
233 | }; | 240 | }; |
234 | 241 | ||
235 | static int wm8903_volatile_register(struct snd_soc_codec *codec, unsigned int reg) | 242 | static int wm8903_volatile_register(struct snd_soc_codec *codec, unsigned int reg) |
@@ -1635,6 +1642,119 @@ static int wm8903_resume(struct snd_soc_codec *codec) | |||
1635 | return 0; | 1642 | return 0; |
1636 | } | 1643 | } |
1637 | 1644 | ||
1645 | #ifdef CONFIG_GPIOLIB | ||
1646 | static inline struct wm8903_priv *gpio_to_wm8903(struct gpio_chip *chip) | ||
1647 | { | ||
1648 | return container_of(chip, struct wm8903_priv, gpio_chip); | ||
1649 | } | ||
1650 | |||
1651 | static int wm8903_gpio_request(struct gpio_chip *chip, unsigned offset) | ||
1652 | { | ||
1653 | if (offset >= WM8903_NUM_GPIO) | ||
1654 | return -EINVAL; | ||
1655 | |||
1656 | return 0; | ||
1657 | } | ||
1658 | |||
1659 | static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset) | ||
1660 | { | ||
1661 | struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); | ||
1662 | struct snd_soc_codec *codec = wm8903->codec; | ||
1663 | unsigned int mask, val; | ||
1664 | |||
1665 | mask = WM8903_GP1_FN_MASK | WM8903_GP1_DIR_MASK; | ||
1666 | val = (WM8903_GPn_FN_GPIO_INPUT << WM8903_GP1_FN_SHIFT) | | ||
1667 | WM8903_GP1_DIR; | ||
1668 | |||
1669 | return snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset, | ||
1670 | mask, val); | ||
1671 | } | ||
1672 | |||
1673 | static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
1674 | { | ||
1675 | struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); | ||
1676 | struct snd_soc_codec *codec = wm8903->codec; | ||
1677 | int reg; | ||
1678 | |||
1679 | reg = snd_soc_read(codec, WM8903_GPIO_CONTROL_1 + offset); | ||
1680 | |||
1681 | return (reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT; | ||
1682 | } | ||
1683 | |||
1684 | static int wm8903_gpio_direction_out(struct gpio_chip *chip, | ||
1685 | unsigned offset, int value) | ||
1686 | { | ||
1687 | struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); | ||
1688 | struct snd_soc_codec *codec = wm8903->codec; | ||
1689 | unsigned int mask, val; | ||
1690 | |||
1691 | mask = WM8903_GP1_FN_MASK | WM8903_GP1_DIR_MASK | WM8903_GP1_LVL_MASK; | ||
1692 | val = (WM8903_GPn_FN_GPIO_OUTPUT << WM8903_GP1_FN_SHIFT) | | ||
1693 | (value << WM8903_GP2_LVL_SHIFT); | ||
1694 | |||
1695 | return snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset, | ||
1696 | mask, val); | ||
1697 | } | ||
1698 | |||
1699 | static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
1700 | { | ||
1701 | struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); | ||
1702 | struct snd_soc_codec *codec = wm8903->codec; | ||
1703 | |||
1704 | snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset, | ||
1705 | WM8903_GP1_LVL_MASK, value << WM8903_GP1_LVL_SHIFT); | ||
1706 | } | ||
1707 | |||
1708 | static struct gpio_chip wm8903_template_chip = { | ||
1709 | .label = "wm8903", | ||
1710 | .owner = THIS_MODULE, | ||
1711 | .request = wm8903_gpio_request, | ||
1712 | .direction_input = wm8903_gpio_direction_in, | ||
1713 | .get = wm8903_gpio_get, | ||
1714 | .direction_output = wm8903_gpio_direction_out, | ||
1715 | .set = wm8903_gpio_set, | ||
1716 | .can_sleep = 1, | ||
1717 | }; | ||
1718 | |||
1719 | static void wm8903_init_gpio(struct snd_soc_codec *codec) | ||
1720 | { | ||
1721 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); | ||
1722 | struct wm8903_platform_data *pdata = dev_get_platdata(codec->dev); | ||
1723 | int ret; | ||
1724 | |||
1725 | wm8903->gpio_chip = wm8903_template_chip; | ||
1726 | wm8903->gpio_chip.ngpio = WM8903_NUM_GPIO; | ||
1727 | wm8903->gpio_chip.dev = codec->dev; | ||
1728 | |||
1729 | if (pdata && pdata->gpio_base) | ||
1730 | wm8903->gpio_chip.base = pdata->gpio_base; | ||
1731 | else | ||
1732 | wm8903->gpio_chip.base = -1; | ||
1733 | |||
1734 | ret = gpiochip_add(&wm8903->gpio_chip); | ||
1735 | if (ret != 0) | ||
1736 | dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret); | ||
1737 | } | ||
1738 | |||
1739 | static void wm8903_free_gpio(struct snd_soc_codec *codec) | ||
1740 | { | ||
1741 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); | ||
1742 | int ret; | ||
1743 | |||
1744 | ret = gpiochip_remove(&wm8903->gpio_chip); | ||
1745 | if (ret != 0) | ||
1746 | dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret); | ||
1747 | } | ||
1748 | #else | ||
1749 | static void wm8903_init_gpio(struct snd_soc_codec *codec) | ||
1750 | { | ||
1751 | } | ||
1752 | |||
1753 | static void wm8903_free_gpio(struct snd_soc_codec *codec) | ||
1754 | { | ||
1755 | } | ||
1756 | #endif | ||
1757 | |||
1638 | static int wm8903_probe(struct snd_soc_codec *codec) | 1758 | static int wm8903_probe(struct snd_soc_codec *codec) |
1639 | { | 1759 | { |
1640 | struct wm8903_platform_data *pdata = dev_get_platdata(codec->dev); | 1760 | struct wm8903_platform_data *pdata = dev_get_platdata(codec->dev); |
@@ -1643,6 +1763,7 @@ static int wm8903_probe(struct snd_soc_codec *codec) | |||
1643 | int trigger, irq_pol; | 1763 | int trigger, irq_pol; |
1644 | u16 val; | 1764 | u16 val; |
1645 | 1765 | ||
1766 | wm8903->codec = codec; | ||
1646 | init_completion(&wm8903->wseq); | 1767 | init_completion(&wm8903->wseq); |
1647 | 1768 | ||
1648 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); | 1769 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); |
@@ -1667,7 +1788,7 @@ static int wm8903_probe(struct snd_soc_codec *codec) | |||
1667 | /* Set up GPIOs and microphone detection */ | 1788 | /* Set up GPIOs and microphone detection */ |
1668 | if (pdata) { | 1789 | if (pdata) { |
1669 | for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) { | 1790 | for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) { |
1670 | if (!pdata->gpio_cfg[i]) | 1791 | if (pdata->gpio_cfg[i] == WM8903_GPIO_NO_CONFIG) |
1671 | continue; | 1792 | continue; |
1672 | 1793 | ||
1673 | snd_soc_write(codec, WM8903_GPIO_CONTROL_1 + i, | 1794 | snd_soc_write(codec, WM8903_GPIO_CONTROL_1 + i, |
@@ -1749,12 +1870,15 @@ static int wm8903_probe(struct snd_soc_codec *codec) | |||
1749 | ARRAY_SIZE(wm8903_snd_controls)); | 1870 | ARRAY_SIZE(wm8903_snd_controls)); |
1750 | wm8903_add_widgets(codec); | 1871 | wm8903_add_widgets(codec); |
1751 | 1872 | ||
1873 | wm8903_init_gpio(codec); | ||
1874 | |||
1752 | return ret; | 1875 | return ret; |
1753 | } | 1876 | } |
1754 | 1877 | ||
1755 | /* power down chip */ | 1878 | /* power down chip */ |
1756 | static int wm8903_remove(struct snd_soc_codec *codec) | 1879 | static int wm8903_remove(struct snd_soc_codec *codec) |
1757 | { | 1880 | { |
1881 | wm8903_free_gpio(codec); | ||
1758 | wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1882 | wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1759 | return 0; | 1883 | return 0; |
1760 | } | 1884 | } |