浏览代码

ASoC: cs4271: add regulator consumer support

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@gmail.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Pascal Huerst 9 年之前
父节点
当前提交
9a397f4736
共有 2 个文件被更改,包括 68 次插入8 次删除
  1. 7 0
      Documentation/devicetree/bindings/sound/cs4271.txt
  2. 61 8
      sound/soc/codecs/cs4271.c

+ 7 - 0
Documentation/devicetree/bindings/sound/cs4271.txt

@@ -33,12 +33,19 @@ Optional properties:
 	Note that this is not needed in case the clocks are stable
 	Note that this is not needed in case the clocks are stable
 	throughout the entire runtime of the codec.
 	throughout the entire runtime of the codec.
 
 
+ - vd-supply:	Digital power
+ - vl-supply:	Logic power
+ - va-supply:	Analog Power
+
 Examples:
 Examples:
 
 
 	codec_i2c: cs4271@10 {
 	codec_i2c: cs4271@10 {
 		compatible = "cirrus,cs4271";
 		compatible = "cirrus,cs4271";
 		reg = <0x10>;
 		reg = <0x10>;
 		reset-gpio = <&gpio 23 0>;
 		reset-gpio = <&gpio 23 0>;
+		vd-supply = <&vdd_3v3_reg>;
+		vl-supply = <&vdd_3v3_reg>;
+		va-supply = <&vdd_3v3_reg>;
 	};
 	};
 
 
 	codec_spi: cs4271@0 {
 	codec_spi: cs4271@0 {

+ 61 - 8
sound/soc/codecs/cs4271.c

@@ -26,6 +26,7 @@
 #include <linux/of.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
 #include <sound/pcm.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
 #include <sound/tlv.h>
@@ -157,6 +158,10 @@ static bool cs4271_volatile_reg(struct device *dev, unsigned int reg)
 	return reg == CS4271_CHIPID;
 	return reg == CS4271_CHIPID;
 }
 }
 
 
+static const char * const supply_names[] = {
+	"vd", "vl", "va"
+};
+
 struct cs4271_private {
 struct cs4271_private {
 	unsigned int			mclk;
 	unsigned int			mclk;
 	bool				master;
 	bool				master;
@@ -170,6 +175,7 @@ struct cs4271_private {
 	int				gpio_disable;
 	int				gpio_disable;
 	/* enable soft reset workaround */
 	/* enable soft reset workaround */
 	bool				enable_soft_reset;
 	bool				enable_soft_reset;
+	struct regulator_bulk_data      supplies[ARRAY_SIZE(supply_names)];
 };
 };
 
 
 static const struct snd_soc_dapm_widget cs4271_dapm_widgets[] = {
 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,
 	.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
 #ifdef CONFIG_PM
 static int cs4271_soc_suspend(struct snd_soc_codec *codec)
 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)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
+	regcache_mark_dirty(cs4271->regmap);
+	regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -507,6 +530,16 @@ static int cs4271_soc_resume(struct snd_soc_codec *codec)
 	int ret;
 	int ret;
 	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
 	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 */
 	/* Restore codec state */
 	ret = regcache_sync(cs4271->regmap);
 	ret = regcache_sync(cs4271->regmap);
 	if (ret < 0)
 	if (ret < 0)
@@ -553,19 +586,24 @@ static int cs4271_codec_probe(struct snd_soc_codec *codec)
 	}
 	}
 #endif
 #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) {
 	if (cs4271plat) {
 		amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec;
 		amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec;
 		cs4271->enable_soft_reset = cs4271plat->enable_soft_reset;
 		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,
 	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
 				 CS4271_MODE2_PDN | CS4271_MODE2_CPEN,
 				 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 */
 		/* Set codec to the reset state */
 		gpio_set_value(cs4271->gpio_nreset, 0);
 		gpio_set_value(cs4271->gpio_nreset, 0);
 
 
+	regcache_mark_dirty(cs4271->regmap);
+	regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);
+
 	return 0;
 	return 0;
 };
 };
 
 
@@ -617,6 +658,7 @@ static int cs4271_common_probe(struct device *dev,
 {
 {
 	struct cs4271_platform_data *cs4271plat = dev->platform_data;
 	struct cs4271_platform_data *cs4271plat = dev->platform_data;
 	struct cs4271_private *cs4271;
 	struct cs4271_private *cs4271;
+	int i, ret;
 
 
 	cs4271 = devm_kzalloc(dev, sizeof(*cs4271), GFP_KERNEL);
 	cs4271 = devm_kzalloc(dev, sizeof(*cs4271), GFP_KERNEL);
 	if (!cs4271)
 	if (!cs4271)
@@ -638,6 +680,17 @@ static int cs4271_common_probe(struct device *dev,
 			return ret;
 			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;
 	*c = cs4271;
 	return 0;
 	return 0;
 }
 }