ASoC: adau1701: add regulator consumer support
authorPascal Huerst <pascal.huerst@gmail.com>
Mon, 20 Apr 2015 09:12:03 +0000 (11:12 +0200)
committerMark Brown <broonie@kernel.org>
Mon, 27 Apr 2015 14:37:32 +0000 (15:37 +0100)
The adau1701 has two power domains, DVDD and AVDD.
Enable them both as long as the codec is in use.

Signed-off-by: Pascal Huerst <pascal.huerst@gmail.com>
Acked-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Mark Brown <broonie@kernel.org>
Documentation/devicetree/bindings/sound/adi,adau1701.txt
sound/soc/codecs/adau1701.c

index 547a49b..0d1128c 100644 (file)
@@ -20,6 +20,8 @@ Optional properties:
                        pin configurations as described in the datasheet,
                        table 53. Note that the value of this property has
                        to be prefixed with '/bits/ 8'.
+ - avdd-supply:        Power supply for AVDD, providing 3.3V
+ - dvdd-supply:        Power supply for DVDD, providing 3.3V
 
 Examples:
 
@@ -28,6 +30,8 @@ Examples:
                        compatible = "adi,adau1701";
                        reg = <0x34>;
                        reset-gpio = <&gpio 23 0>;
+                       avdd-supply = <&vdd_3v3_reg>;
+                       dvdd-supply = <&vdd_3v3_reg>;
                        adi,pll-mode-gpios = <&gpio 24 0 &gpio 25 0>;
                        adi,pin-config = /bits/ 8 <0x4 0x7 0x5 0x5 0x4 0x4
                                                    0x4 0x4 0x4 0x4 0x4 0x4>;
index d4e219b..ca94ae8 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
 #include <linux/regmap.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 
 #define ADAU1701_FIRMWARE "adau1701.bin"
 
+static const char * const supply_names[] = {
+       "dvdd", "avdd"
+};
+
 struct adau1701 {
        int gpio_nreset;
        int gpio_pll_mode[2];
@@ -112,6 +117,7 @@ struct adau1701 {
        u8 pin_config[12];
 
        struct sigmadsp *sigmadsp;
+       struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
 };
 
 static const struct snd_kcontrol_new adau1701_controls[] = {
@@ -669,6 +675,13 @@ static int adau1701_probe(struct snd_soc_codec *codec)
        if (ret)
                return ret;
 
+       ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies),
+                                   adau1701->supplies);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
+               return ret;
+       }
+
        /*
         * Let the pll_clkdiv variable default to something that won't happen
         * at runtime. That way, we can postpone the firmware download from
@@ -680,7 +693,7 @@ static int adau1701_probe(struct snd_soc_codec *codec)
        /* initalize with pre-configured pll mode settings */
        ret = adau1701_reset(codec, adau1701->pll_clkdiv, 0);
        if (ret < 0)
-               return ret;
+               goto exit_regulators_disable;
 
        /* set up pin config */
        val = 0;
@@ -696,10 +709,60 @@ static int adau1701_probe(struct snd_soc_codec *codec)
        regmap_write(adau1701->regmap, ADAU1701_PINCONF_1, val);
 
        return 0;
+
+exit_regulators_disable:
+
+       regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies);
+       return ret;
 }
 
+static int adau1701_remove(struct snd_soc_codec *codec)
+{
+       struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+
+       if (gpio_is_valid(adau1701->gpio_nreset))
+               gpio_set_value_cansleep(adau1701->gpio_nreset, 0);
+
+       regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int adau1701_suspend(struct snd_soc_codec *codec)
+{
+       struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+
+       regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies),
+                              adau1701->supplies);
+
+       return 0;
+}
+
+static int adau1701_resume(struct snd_soc_codec *codec)
+{
+       struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+        ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies),
+                                   adau1701->supplies);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
+               return ret;
+       }
+
+       return adau1701_reset(codec, adau1701->pll_clkdiv, 0);
+}
+#else
+#define adau1701_resume        NULL
+#define adau1701_suspend       NULL
+#endif /* CONFIG_PM */
+
 static struct snd_soc_codec_driver adau1701_codec_drv = {
        .probe                  = adau1701_probe,
+       .remove                 = adau1701_remove,
+       .resume                 = adau1701_resume,
+       .suspend                = adau1701_suspend,
        .set_bias_level         = adau1701_set_bias_level,
        .idle_bias_off          = true,
 
@@ -730,32 +793,58 @@ static int adau1701_i2c_probe(struct i2c_client *client,
        struct device *dev = &client->dev;
        int gpio_nreset = -EINVAL;
        int gpio_pll_mode[2] = { -EINVAL, -EINVAL };
-       int ret;
+       int ret, i;
 
        adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL);
        if (!adau1701)
                return -ENOMEM;
 
+       for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+               adau1701->supplies[i].supply = supply_names[i];
+
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(adau1701->supplies),
+                       adau1701->supplies);
+       if (ret < 0) {
+               dev_err(dev, "Failed to get regulators: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies),
+                       adau1701->supplies);
+       if (ret < 0) {
+               dev_err(dev, "Failed to enable regulators: %d\n", ret);
+               return ret;
+       }
+
        adau1701->client = client;
        adau1701->regmap = devm_regmap_init(dev, NULL, client,
                                            &adau1701_regmap);
-       if (IS_ERR(adau1701->regmap))
-               return PTR_ERR(adau1701->regmap);
+       if (IS_ERR(adau1701->regmap)) {
+               ret = PTR_ERR(adau1701->regmap);
+               goto exit_regulators_disable;
+       }
+
 
        if (dev->of_node) {
                gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0);
-               if (gpio_nreset < 0 && gpio_nreset != -ENOENT)
-                       return gpio_nreset;
+               if (gpio_nreset < 0 && gpio_nreset != -ENOENT) {
+                       ret = gpio_nreset;
+                       goto exit_regulators_disable;
+               }
 
                gpio_pll_mode[0] = of_get_named_gpio(dev->of_node,
                                                   "adi,pll-mode-gpios", 0);
-               if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT)
-                       return gpio_pll_mode[0];
+               if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT) {
+                       ret = gpio_pll_mode[0];
+                       goto exit_regulators_disable;
+               }
 
                gpio_pll_mode[1] = of_get_named_gpio(dev->of_node,
                                                   "adi,pll-mode-gpios", 1);
-               if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT)
-                       return gpio_pll_mode[1];
+               if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT) {
+                       ret = gpio_pll_mode[1];
+                       goto exit_regulators_disable;
+               }
 
                of_property_read_u32(dev->of_node, "adi,pll-clkdiv",
                                     &adau1701->pll_clkdiv);
@@ -769,7 +858,7 @@ static int adau1701_i2c_probe(struct i2c_client *client,
                ret = devm_gpio_request_one(dev, gpio_nreset, GPIOF_OUT_INIT_LOW,
                                            "ADAU1701 Reset");
                if (ret < 0)
-                       return ret;
+                       goto exit_regulators_disable;
        }
 
        if (gpio_is_valid(gpio_pll_mode[0]) &&
@@ -778,13 +867,13 @@ static int adau1701_i2c_probe(struct i2c_client *client,
                                            GPIOF_OUT_INIT_LOW,
                                            "ADAU1701 PLL mode 0");
                if (ret < 0)
-                       return ret;
+                       goto exit_regulators_disable;
 
                ret = devm_gpio_request_one(dev, gpio_pll_mode[1],
                                            GPIOF_OUT_INIT_LOW,
                                            "ADAU1701 PLL mode 1");
                if (ret < 0)
-                       return ret;
+                       goto exit_regulators_disable;
        }
 
        adau1701->gpio_nreset = gpio_nreset;
@@ -795,11 +884,17 @@ static int adau1701_i2c_probe(struct i2c_client *client,
 
        adau1701->sigmadsp = devm_sigmadsp_init_i2c(client,
                &adau1701_sigmadsp_ops, ADAU1701_FIRMWARE);
-       if (IS_ERR(adau1701->sigmadsp))
-               return PTR_ERR(adau1701->sigmadsp);
+       if (IS_ERR(adau1701->sigmadsp)) {
+               ret = PTR_ERR(adau1701->sigmadsp);
+               goto exit_regulators_disable;
+       }
 
        ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv,
                        &adau1701_dai, 1);
+
+exit_regulators_disable:
+
+       regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies);
        return ret;
 }