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>
This commit is contained in:
parent
92e963f50f
commit
9a397f4736
|
@ -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 {
|
||||||
|
|
|
@ -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 */
|
cs4271_reset(codec);
|
||||||
gpio_direction_output(cs4271->gpio_nreset, 0);
|
|
||||||
mdelay(1);
|
ret = regcache_sync(cs4271->regmap);
|
||||||
gpio_set_value(cs4271->gpio_nreset, 1);
|
if (ret < 0)
|
||||||
/* Give the codec time to wake up */
|
return ret;
|
||||||
mdelay(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue