[PATCH] ASoC: cs4271: add regulator consumer support

From: Pascal Huerst
Date: Tue Feb 16 2016 - 10:19:06 EST


The cs4271 has three power domains: vd, vl and va.
Enable them all, as long as the codec is in use.

While at it, factored out the reset code into its own function.

Signed-off-by: Pascal Huerst <pascal.huerst@xxxxxxxxx>
Signed-off-by: Mark Brown <broonie@xxxxxxxxxx>
---
Documentation/devicetree/bindings/sound/cs4271.txt | 7 +++
sound/soc/codecs/cs4271.c | 69 +++++++++++++++++++---
2 files changed, 68 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/cs4271.txt b/Documentation/devicetree/bindings/sound/cs4271.txt
index e2cd1d7539e5..6e699ceabacd 100644
--- a/Documentation/devicetree/bindings/sound/cs4271.txt
+++ b/Documentation/devicetree/bindings/sound/cs4271.txt
@@ -33,12 +33,19 @@ Optional properties:
Note that this is not needed in case the clocks are stable
throughout the entire runtime of the codec.

+ - vd-supply: Digital power
+ - vl-supply: Logic power
+ - va-supply: Analog Power
+
Examples:

codec_i2c: cs4271@10 {
compatible = "cirrus,cs4271";
reg = <0x10>;
reset-gpio = <&gpio 23 0>;
+ vd-supply = <&vdd_3v3_reg>;
+ vl-supply = <&vdd_3v3_reg>;
+ va-supply = <&vdd_3v3_reg>;
};

codec_spi: cs4271@0 {
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index e770ee6f36da..0c0010b25421 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -26,6 +26,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/tlv.h>
@@ -157,6 +158,10 @@ static bool cs4271_volatile_reg(struct device *dev, unsigned int reg)
return reg == CS4271_CHIPID;
}

+static const char * const supply_names[] = {
+ "vd", "vl", "va"
+};
+
struct cs4271_private {
unsigned int mclk;
bool master;
@@ -170,6 +175,7 @@ struct cs4271_private {
int gpio_disable;
/* enable soft reset workaround */
bool enable_soft_reset;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
};

static const struct snd_soc_dapm_widget cs4271_dapm_widgets[] = {
@@ -487,6 +493,20 @@ static struct snd_soc_dai_driver cs4271_dai = {
.symmetric_rates = 1,
};

+static int cs4271_reset(struct snd_soc_codec *codec)
+{
+ struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+
+ if (gpio_is_valid(cs4271->gpio_nreset)) {
+ gpio_set_value(cs4271->gpio_nreset, 0);
+ mdelay(1);
+ gpio_set_value(cs4271->gpio_nreset, 1);
+ mdelay(1);
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_PM
static int cs4271_soc_suspend(struct snd_soc_codec *codec)
{
@@ -499,6 +519,9 @@ static int cs4271_soc_suspend(struct snd_soc_codec *codec)
if (ret < 0)
return ret;

+ regcache_mark_dirty(cs4271->regmap);
+ regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);
+
return 0;
}

@@ -507,6 +530,16 @@ static int cs4271_soc_resume(struct snd_soc_codec *codec)
int ret;
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);

+ ret = regulator_bulk_enable(ARRAY_SIZE(cs4271->supplies),
+ cs4271->supplies);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
+ return ret;
+ }
+
+ /* Do a proper reset after power up */
+ cs4271_reset(codec);
+
/* Restore codec state */
ret = regcache_sync(cs4271->regmap);
if (ret < 0)
@@ -553,19 +586,24 @@ static int cs4271_codec_probe(struct snd_soc_codec *codec)
}
#endif

+ ret = regulator_bulk_enable(ARRAY_SIZE(cs4271->supplies),
+ cs4271->supplies);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
+ return ret;
+ }
+
if (cs4271plat) {
amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec;
cs4271->enable_soft_reset = cs4271plat->enable_soft_reset;
}

- if (gpio_is_valid(cs4271->gpio_nreset)) {
- /* Reset codec */
- gpio_direction_output(cs4271->gpio_nreset, 0);
- mdelay(1);
- gpio_set_value(cs4271->gpio_nreset, 1);
- /* Give the codec time to wake up */
- mdelay(1);
- }
+ /* Reset codec */
+ cs4271_reset(codec);
+
+ ret = regcache_sync(cs4271->regmap);
+ if (ret < 0)
+ return ret;

ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
CS4271_MODE2_PDN | CS4271_MODE2_CPEN,
@@ -595,6 +633,9 @@ static int cs4271_codec_remove(struct snd_soc_codec *codec)
/* Set codec to the reset state */
gpio_set_value(cs4271->gpio_nreset, 0);

+ regcache_mark_dirty(cs4271->regmap);
+ regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);
+
return 0;
};

@@ -617,6 +658,7 @@ static int cs4271_common_probe(struct device *dev,
{
struct cs4271_platform_data *cs4271plat = dev->platform_data;
struct cs4271_private *cs4271;
+ int i, ret;

cs4271 = devm_kzalloc(dev, sizeof(*cs4271), GFP_KERNEL);
if (!cs4271)
@@ -638,6 +680,17 @@ static int cs4271_common_probe(struct device *dev,
return ret;
}

+ for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+ cs4271->supplies[i].supply = supply_names[i];
+
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs4271->supplies),
+ cs4271->supplies);
+
+ if (ret < 0) {
+ dev_err(dev, "Failed to get regulators: %d\n", ret);
+ return ret;
+ }
+
*c = cs4271;
return 0;
}
--
2.7.0