[alsa-devel] [PATCH 1/3] ASoC: ak5386: add regulator consumer support
The chip has two power supplies, VA and VDD. Register and enable them both.
Signed-off-by: Daniel Mack zonque@gmail.com --- sound/soc/codecs/ak5386.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-)
diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c index 72e953b..99fb5db 100644 --- a/sound/soc/codecs/ak5386.c +++ b/sound/soc/codecs/ak5386.c @@ -14,12 +14,18 @@ #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/of_device.h> +#include <linux/regulator/consumer.h> #include <sound/soc.h> #include <sound/pcm.h> #include <sound/initval.h>
+static const char *supply_names[] = { + "va", "vd" +}; + struct ak5386_priv { int reset_gpio; + struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; };
static const struct snd_soc_dapm_widget ak5386_dapm_widgets[] = { @@ -122,6 +128,7 @@ static int ak5386_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ak5386_priv *priv; + int ret, i;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -130,6 +137,19 @@ static int ak5386_probe(struct platform_device *pdev) priv->reset_gpio = -EINVAL; dev_set_drvdata(dev, priv);
+ for (i = 0; i < ARRAY_SIZE(supply_names); i++) + priv->supplies[i].supply = supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies), + priv->supplies); + if (ret < 0) + return ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), + priv->supplies); + if (ret < 0) + return ret; + if (of_match_device(of_match_ptr(ak5386_dt_ids), dev)) priv->reset_gpio = of_get_named_gpio(dev->of_node, "reset-gpio", 0); @@ -140,13 +160,22 @@ static int ak5386_probe(struct platform_device *pdev) "AK5386 Reset")) priv->reset_gpio = -EINVAL;
- return snd_soc_register_codec(dev, &soc_codec_ak5386, - &ak5386_dai, 1); + ret = snd_soc_register_codec(dev, &soc_codec_ak5386, + &ak5386_dai, 1); + if (ret < 0) + regulator_bulk_disable(ARRAY_SIZE(priv->supplies), + priv->supplies); + return ret; }
static int ak5386_remove(struct platform_device *pdev) { - snd_soc_unregister_codec(&pdev->dev); + struct device *dev = &pdev->dev; + struct ak5386_priv *priv = dev_get_drvdata(dev); + + snd_soc_unregister_codec(dev); + regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); + return 0; }
The AK4104 has only one power supply, called VDD. Make sure it is enabled during the life-time of the module.
Signed-off-by: Daniel Mack zonque@gmail.com --- sound/soc/codecs/ak4104.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-)
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index b4819dc..c7a541d 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -11,13 +11,14 @@
#include <linux/module.h> #include <linux/slab.h> -#include <sound/core.h> -#include <sound/soc.h> -#include <sound/initval.h> #include <linux/spi/spi.h> #include <linux/of_device.h> #include <linux/of_gpio.h> +#include <linux/regulator/consumer.h> #include <sound/asoundef.h> +#include <sound/core.h> +#include <sound/soc.h> +#include <sound/initval.h>
/* AK4104 registers addresses */ #define AK4104_REG_CONTROL1 0x00 @@ -47,6 +48,7 @@
struct ak4104_private { struct regmap *regmap; + struct regulator *regulator; };
static const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = { @@ -176,20 +178,30 @@ static int ak4104_probe(struct snd_soc_codec *codec)
codec->control_data = ak4104->regmap;
+ ret = regulator_enable(ak4104->regulator); + if (ret < 0) { + dev_err(codec->dev, "Unable to enable regulator: %d\n", ret); + return ret; + } + /* set power-up and non-reset bits */ ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN); if (ret < 0) - return ret; + goto exit_disable_regulator;
/* enable transmitter */ ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX, AK4104_TX_TXE, AK4104_TX_TXE); if (ret < 0) - return ret; + goto exit_disable_regulator;
return 0; + +exit_disable_regulator: + regulator_disable(ak4104->regulator); + return ret; }
static int ak4104_remove(struct snd_soc_codec *codec) @@ -198,6 +210,7 @@ static int ak4104_remove(struct snd_soc_codec *codec)
regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0); + regulator_disable(ak4104->regulator);
return 0; } @@ -241,6 +254,13 @@ static int ak4104_spi_probe(struct spi_device *spi) if (ak4104 == NULL) return -ENOMEM;
+ ak4104->regulator = devm_regulator_get(&spi->dev, "vdd"); + if (IS_ERR(ak4104->regulator)) { + ret = PTR_ERR(ak4104->regulator); + dev_err(&spi->dev, "Unable to get Vdd regulator: %d\n", ret); + return ret; + } + ak4104->regmap = devm_regmap_init_spi(spi, &ak4104_regmap); if (IS_ERR(ak4104->regmap)) { ret = PTR_ERR(ak4104->regmap);
On 03/26/2014 11:22 AM, Daniel Mack wrote:
The AK4104 has only one power supply, called VDD. Make sure it is enabled during the life-time of the module.
Sorry, I just noticed there was an update for this driver in the ASoC for-next branch that causes a trivial conflict for this particular patch. If desired, I can resend a rebased version. The other two patches are unaffected.
Signed-off-by: Daniel Mack zonque@gmail.com
sound/soc/codecs/ak4104.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-)
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index b4819dc..c7a541d 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -11,13 +11,14 @@
#include <linux/module.h> #include <linux/slab.h> -#include <sound/core.h> -#include <sound/soc.h> -#include <sound/initval.h> #include <linux/spi/spi.h> #include <linux/of_device.h> #include <linux/of_gpio.h> +#include <linux/regulator/consumer.h> #include <sound/asoundef.h> +#include <sound/core.h> +#include <sound/soc.h> +#include <sound/initval.h>
/* AK4104 registers addresses */ #define AK4104_REG_CONTROL1 0x00 @@ -47,6 +48,7 @@
struct ak4104_private { struct regmap *regmap;
- struct regulator *regulator;
};
static const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = { @@ -176,20 +178,30 @@ static int ak4104_probe(struct snd_soc_codec *codec)
codec->control_data = ak4104->regmap;
- ret = regulator_enable(ak4104->regulator);
- if (ret < 0) {
dev_err(codec->dev, "Unable to enable regulator: %d\n", ret);
return ret;
- }
- /* set power-up and non-reset bits */ ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN); if (ret < 0)
return ret;
goto exit_disable_regulator;
/* enable transmitter */ ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX, AK4104_TX_TXE, AK4104_TX_TXE); if (ret < 0)
return ret;
goto exit_disable_regulator;
return 0;
+exit_disable_regulator:
- regulator_disable(ak4104->regulator);
- return ret;
}
static int ak4104_remove(struct snd_soc_codec *codec) @@ -198,6 +210,7 @@ static int ak4104_remove(struct snd_soc_codec *codec)
regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0);
regulator_disable(ak4104->regulator);
return 0;
} @@ -241,6 +254,13 @@ static int ak4104_spi_probe(struct spi_device *spi) if (ak4104 == NULL) return -ENOMEM;
- ak4104->regulator = devm_regulator_get(&spi->dev, "vdd");
- if (IS_ERR(ak4104->regulator)) {
ret = PTR_ERR(ak4104->regulator);
dev_err(&spi->dev, "Unable to get Vdd regulator: %d\n", ret);
return ret;
- }
- ak4104->regmap = devm_regmap_init_spi(spi, &ak4104_regmap); if (IS_ERR(ak4104->regmap)) { ret = PTR_ERR(ak4104->regmap);
The TAS5086 has two power domains, DVDD and AVDD. Add support for regulators to the TAS5086 codec driver.
Signed-off-by: Daniel Mack zonque@gmail.com --- sound/soc/codecs/tas5086.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-)
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index a895a5e..e87a577 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -36,6 +36,7 @@ #include <linux/gpio.h> #include <linux/i2c.h> #include <linux/regmap.h> +#include <linux/regulator/consumer.h> #include <linux/spi/spi.h> #include <linux/of.h> #include <linux/of_device.h> @@ -240,6 +241,10 @@ static int tas5086_reg_read(void *context, unsigned int reg, return 0; }
+static const char *supply_names[] = { + "dvdd", "avdd" +}; + struct tas5086_private { struct regmap *regmap; unsigned int mclk, sclk; @@ -251,6 +256,7 @@ struct tas5086_private { int rate; /* GPIO driving Reset pin, if any */ int gpio_nreset; + struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; };
static int tas5086_deemph[] = { 0, 32000, 44100, 48000 }; @@ -773,6 +779,8 @@ static int tas5086_soc_suspend(struct snd_soc_codec *codec) if (ret < 0) return ret;
+ regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); + return 0; }
@@ -781,6 +789,10 @@ static int tas5086_soc_resume(struct snd_soc_codec *codec) struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); int ret;
+ ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); + if (ret < 0) + return ret; + tas5086_reset(priv); regcache_mark_dirty(priv->regmap);
@@ -812,6 +824,12 @@ static int tas5086_probe(struct snd_soc_codec *codec) struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); int i, ret;
+ ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); + if (ret < 0) { + dev_err(codec->dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + priv->pwm_start_mid_z = 0; priv->charge_period = 1300000; /* hardware default is 1300 ms */
@@ -834,14 +852,19 @@ static int tas5086_probe(struct snd_soc_codec *codec)
ret = tas5086_init(codec->dev, priv); if (ret < 0) - return ret; + goto exit_disable_regulators;
/* set master volume to 0 dB */ ret = regmap_write(priv->regmap, TAS5086_MASTER_VOL, 0x30); if (ret < 0) - return ret; + goto exit_disable_regulators;
return 0; + +exit_disable_regulators: + regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); + + return ret; }
static int tas5086_remove(struct snd_soc_codec *codec) @@ -852,6 +875,8 @@ static int tas5086_remove(struct snd_soc_codec *codec) /* Set codec to the reset state */ gpio_set_value(priv->gpio_nreset, 0);
+ regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); + return 0; };
@@ -900,6 +925,16 @@ static int tas5086_i2c_probe(struct i2c_client *i2c, if (!priv) return -ENOMEM;
+ for (i = 0; i < ARRAY_SIZE(supply_names); i++) + priv->supplies[i].supply = supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies), + priv->supplies); + if (ret < 0) { + dev_err(dev, "Failed to get regulators: %d\n", ret); + return ret; + } + priv->regmap = devm_regmap_init(dev, NULL, i2c, &tas5086_regmap); if (IS_ERR(priv->regmap)) { ret = PTR_ERR(priv->regmap);
On 03/26/2014 11:22 AM, Daniel Mack wrote:
The TAS5086 has two power domains, DVDD and AVDD. Add support for regulators to the TAS5086 codec driver.
Meh, this one needs more tweaking as well. Please ignore all patches in this series; I'll resend once things work as expected. Sorry for the noise.
Signed-off-by: Daniel Mack zonque@gmail.com
sound/soc/codecs/tas5086.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-)
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index a895a5e..e87a577 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -36,6 +36,7 @@ #include <linux/gpio.h> #include <linux/i2c.h> #include <linux/regmap.h> +#include <linux/regulator/consumer.h> #include <linux/spi/spi.h> #include <linux/of.h> #include <linux/of_device.h> @@ -240,6 +241,10 @@ static int tas5086_reg_read(void *context, unsigned int reg, return 0; }
+static const char *supply_names[] = {
- "dvdd", "avdd"
+};
struct tas5086_private { struct regmap *regmap; unsigned int mclk, sclk; @@ -251,6 +256,7 @@ struct tas5086_private { int rate; /* GPIO driving Reset pin, if any */ int gpio_nreset;
- struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
};
static int tas5086_deemph[] = { 0, 32000, 44100, 48000 }; @@ -773,6 +779,8 @@ static int tas5086_soc_suspend(struct snd_soc_codec *codec) if (ret < 0) return ret;
- regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
- return 0;
}
@@ -781,6 +789,10 @@ static int tas5086_soc_resume(struct snd_soc_codec *codec) struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); int ret;
- ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
- if (ret < 0)
return ret;
- tas5086_reset(priv); regcache_mark_dirty(priv->regmap);
@@ -812,6 +824,12 @@ static int tas5086_probe(struct snd_soc_codec *codec) struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); int i, ret;
- ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
- if (ret < 0) {
dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
return ret;
- }
- priv->pwm_start_mid_z = 0; priv->charge_period = 1300000; /* hardware default is 1300 ms */
@@ -834,14 +852,19 @@ static int tas5086_probe(struct snd_soc_codec *codec)
ret = tas5086_init(codec->dev, priv); if (ret < 0)
return ret;
goto exit_disable_regulators;
/* set master volume to 0 dB */ ret = regmap_write(priv->regmap, TAS5086_MASTER_VOL, 0x30); if (ret < 0)
return ret;
goto exit_disable_regulators;
return 0;
+exit_disable_regulators:
- regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
- return ret;
}
static int tas5086_remove(struct snd_soc_codec *codec) @@ -852,6 +875,8 @@ static int tas5086_remove(struct snd_soc_codec *codec) /* Set codec to the reset state */ gpio_set_value(priv->gpio_nreset, 0);
- regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
- return 0;
};
@@ -900,6 +925,16 @@ static int tas5086_i2c_probe(struct i2c_client *i2c, if (!priv) return -ENOMEM;
- for (i = 0; i < ARRAY_SIZE(supply_names); i++)
priv->supplies[i].supply = supply_names[i];
- ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies),
priv->supplies);
- if (ret < 0) {
dev_err(dev, "Failed to get regulators: %d\n", ret);
return ret;
- }
- priv->regmap = devm_regmap_init(dev, NULL, i2c, &tas5086_regmap); if (IS_ERR(priv->regmap)) { ret = PTR_ERR(priv->regmap);
On Wed, Mar 26, 2014 at 05:31:18PM +0100, Daniel Mack wrote:
On 03/26/2014 11:22 AM, Daniel Mack wrote:
The TAS5086 has two power domains, DVDD and AVDD. Add support for regulators to the TAS5086 codec driver.
Meh, this one needs more tweaking as well. Please ignore all patches in this series; I'll resend once things work as expected. Sorry for the noise.
No problem.
participants (2)
-
Daniel Mack
-
Mark Brown