ASoC: rt5677: Add a configuration option for LDO2_POW pin
authorAnatol Pomozov <anatol.pomozov@gmail.com>
Wed, 17 Sep 2014 20:14:20 +0000 (13:14 -0700)
committerMark Brown <broonie@kernel.org>
Wed, 24 Sep 2014 08:59:03 +0000 (09:59 +0100)
Some boards have this pin statically tied and do not require any configuration,
some other boards allow to enable chip using GPIO.

Add an option that tells which GPIO is used to power the audio codec.

Signed-off-by: Anatol Pomozov <anatol.pomozov@gmail.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Documentation/devicetree/bindings/sound/rt5677.txt [new file with mode: 0644]
sound/soc/codecs/rt5677.c
sound/soc/codecs/rt5677.h

diff --git a/Documentation/devicetree/bindings/sound/rt5677.txt b/Documentation/devicetree/bindings/sound/rt5677.txt
new file mode 100644 (file)
index 0000000..98509fb
--- /dev/null
@@ -0,0 +1,41 @@
+RT5677 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "realtek,rt5677".
+
+- reg : The I2C address of the device.
+
+- interrupts : The CODEC's interrupt output.
+
+Optional properties:
+
+- realtek,pow-ldo2-gpio : The GPIO that controls the CODEC's POW_LDO2 pin.
+
+Pins on the device (for linking into audio routes):
+
+  * IN1P
+  * IN1N
+  * IN2P
+  * IN2N
+  * MICBIAS1
+  * DMIC1
+  * DMIC2
+  * DMIC3
+  * DMIC4
+  * LOUT1
+  * LOUT2
+  * LOUT3
+
+Example:
+
+rt5677 {
+       compatible = "realtek,rt5677";
+       reg = <0x2c>;
+       interrupt-parent = <&gpio>;
+       interrupts = <TEGRA_GPIO(W, 3) GPIO_ACTIVE_HIGH>;
+       realtek,pow-ldo2-gpio =
+               <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
+};
index 4a0f3dfb2a4722ce44f604e9cdf46d88d7450ffb..d2c6abf38ad21a700868723f4e1b2064d5d7f073 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
+#include <linux/of_gpio.h>
 #include <linux/regmap.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
@@ -3381,6 +3382,8 @@ static int rt5677_remove(struct snd_soc_codec *codec)
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
        regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
+       if (gpio_is_valid(rt5677->pow_ldo2))
+               gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
 
        return 0;
 }
@@ -3392,6 +3395,8 @@ static int rt5677_suspend(struct snd_soc_codec *codec)
 
        regcache_cache_only(rt5677->regmap, true);
        regcache_mark_dirty(rt5677->regmap);
+       if (gpio_is_valid(rt5677->pow_ldo2))
+               gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
 
        return 0;
 }
@@ -3400,6 +3405,10 @@ static int rt5677_resume(struct snd_soc_codec *codec)
 {
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
+       if (gpio_is_valid(rt5677->pow_ldo2)) {
+               gpio_set_value_cansleep(rt5677->pow_ldo2, 1);
+               msleep(10);
+       }
        regcache_cache_only(rt5677->regmap, false);
        regcache_sync(rt5677->regmap);
 
@@ -3558,6 +3567,24 @@ static const struct i2c_device_id rt5677_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id);
 
+static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np)
+{
+       rt5677->pow_ldo2 = of_get_named_gpio(np,
+                                       "realtek,pow-ldo2-gpio", 0);
+
+       /*
+        * POW_LDO2 is optional (it may be statically tied on the board).
+        * -ENOENT means that the property doesn't exist, i.e. there is no
+        * GPIO, so is not an error. Any other error code means the property
+        * exists, but could not be parsed.
+        */
+       if (!gpio_is_valid(rt5677->pow_ldo2) &&
+                       (rt5677->pow_ldo2 != -ENOENT))
+               return rt5677->pow_ldo2;
+
+       return 0;
+}
+
 static int rt5677_i2c_probe(struct i2c_client *i2c,
                    const struct i2c_device_id *id)
 {
@@ -3576,6 +3603,33 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
        if (pdata)
                rt5677->pdata = *pdata;
 
+       if (i2c->dev.of_node) {
+               ret = rt5677_parse_dt(rt5677, i2c->dev.of_node);
+               if (ret) {
+                       dev_err(&i2c->dev, "Failed to parse device tree: %d\n",
+                               ret);
+                       return ret;
+               }
+       } else {
+               rt5677->pow_ldo2 = -EINVAL;
+       }
+
+       if (gpio_is_valid(rt5677->pow_ldo2)) {
+               ret = devm_gpio_request_one(&i2c->dev, rt5677->pow_ldo2,
+                                           GPIOF_OUT_INIT_HIGH,
+                                           "RT5677 POW_LDO2");
+               if (ret < 0) {
+                       dev_err(&i2c->dev, "Failed to request POW_LDO2 %d: %d\n",
+                               rt5677->pow_ldo2, ret);
+                       return ret;
+               }
+               /* Wait a while until I2C bus becomes available. The datasheet
+                * does not specify the exact we should wait but startup
+                * sequence mentiones at least a few milliseconds.
+                */
+               msleep(10);
+       }
+
        rt5677->regmap = devm_regmap_init_i2c(i2c, &rt5677_regmap);
        if (IS_ERR(rt5677->regmap)) {
                ret = PTR_ERR(rt5677->regmap);
index 1fe88727a0633629ab01ed4f315bc45027145d9e..d4eb6d5e6746f949c2a601613e85595c34f01c20 100644 (file)
@@ -1554,6 +1554,7 @@ struct rt5677_priv {
        int pll_src;
        int pll_in;
        int pll_out;
+       int pow_ldo2; /* POW_LDO2 pin */
 #ifdef CONFIG_GPIOLIB
        struct gpio_chip gpio_chip;
 #endif