aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/wm8903.h20
-rw-r--r--sound/soc/codecs/wm8903.c126
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
234struct wm8903_platform_data { 251struct 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
215struct wm8903_priv { 217struct 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
235static int wm8903_volatile_register(struct snd_soc_codec *codec, unsigned int reg) 242static 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
1646static inline struct wm8903_priv *gpio_to_wm8903(struct gpio_chip *chip)
1647{
1648 return container_of(chip, struct wm8903_priv, gpio_chip);
1649}
1650
1651static 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
1659static 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
1673static 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
1684static 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
1699static 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
1708static 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
1719static 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
1739static 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
1749static void wm8903_init_gpio(struct snd_soc_codec *codec)
1750{
1751}
1752
1753static void wm8903_free_gpio(struct snd_soc_codec *codec)
1754{
1755}
1756#endif
1757
1638static int wm8903_probe(struct snd_soc_codec *codec) 1758static 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 */
1756static int wm8903_remove(struct snd_soc_codec *codec) 1879static 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}