Commit 9a397f47 authored by Pascal Huerst's avatar Pascal Huerst Committed by Mark Brown
Browse files

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: default avatarPascal Huerst <pascal.huerst@gmail.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 92e963f5
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -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
Original line number Original line Diff line number Diff line
@@ -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 */
	/* Reset codec */
		gpio_direction_output(cs4271->gpio_nreset, 0);
	cs4271_reset(codec);
		mdelay(1);

		gpio_set_value(cs4271->gpio_nreset, 1);
	ret = regcache_sync(cs4271->regmap);
		/* Give the codec time to wake up */
	if (ret < 0)
		mdelay(1);
		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;
}
}