summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShengjiu Wang <shengjiu.wang@nxp.com>2020-08-14 17:32:41 +0800
committerMark Brown <broonie@kernel.org>2020-08-18 14:52:37 +0100
commit7e3096e8f823682c20e033113ec32dd590364774 (patch)
tree9e7d796040d65384245295a37d37fceb39f5c86b
parent617a156f2ebae841bcd64ee5a21d0e12b5d733ab (diff)
ASoC: ak4458: Add regulator support
"AVDD" is for analog power supply, "DVDD" is for digital power supply, they can improve the power management. As the regulator is enabled in pm runtime resume, which is behind the component driver probe, so accessing registers in component driver probe will fail. Fix this issue by enabling regcache_cache_only after pm_runtime_enable. Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com> Link: https://lore.kernel.org/r/1597397561-2426-2-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/codecs/ak4458.c31
1 files changed, 30 insertions, 1 deletions
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c
index cbe3c782e0ca..763e6839428f 100644
--- a/sound/soc/codecs/ak4458.c
+++ b/sound/soc/codecs/ak4458.c
@@ -12,6 +12,7 @@
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <sound/initval.h>
#include <sound/pcm_params.h>
@@ -21,6 +22,12 @@
#include "ak4458.h"
+#define AK4458_NUM_SUPPLIES 2
+static const char *ak4458_supply_names[AK4458_NUM_SUPPLIES] = {
+ "DVDD",
+ "AVDD",
+};
+
struct ak4458_drvdata {
struct snd_soc_dai_driver *dai_drv;
const struct snd_soc_component_driver *comp_drv;
@@ -28,6 +35,7 @@ struct ak4458_drvdata {
/* AK4458 Codec Private Data */
struct ak4458_priv {
+ struct regulator_bulk_data supplies[AK4458_NUM_SUPPLIES];
struct device *dev;
struct regmap *regmap;
struct gpio_desc *reset_gpiod;
@@ -587,12 +595,22 @@ static int __maybe_unused ak4458_runtime_suspend(struct device *dev)
if (ak4458->mute_gpiod)
gpiod_set_value_cansleep(ak4458->mute_gpiod, 0);
+ regulator_bulk_disable(ARRAY_SIZE(ak4458->supplies),
+ ak4458->supplies);
return 0;
}
static int __maybe_unused ak4458_runtime_resume(struct device *dev)
{
struct ak4458_priv *ak4458 = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(ak4458->supplies),
+ ak4458->supplies);
+ if (ret != 0) {
+ dev_err(ak4458->dev, "Failed to enable supplies: %d\n", ret);
+ return ret;
+ }
if (ak4458->mute_gpiod)
gpiod_set_value_cansleep(ak4458->mute_gpiod, 1);
@@ -667,7 +685,7 @@ static int ak4458_i2c_probe(struct i2c_client *i2c)
{
struct ak4458_priv *ak4458;
const struct ak4458_drvdata *drvdata;
- int ret;
+ int ret, i;
ak4458 = devm_kzalloc(&i2c->dev, sizeof(*ak4458), GFP_KERNEL);
if (!ak4458)
@@ -692,6 +710,16 @@ static int ak4458_i2c_probe(struct i2c_client *i2c)
if (IS_ERR(ak4458->mute_gpiod))
return PTR_ERR(ak4458->mute_gpiod);
+ for (i = 0; i < ARRAY_SIZE(ak4458->supplies); i++)
+ ak4458->supplies[i].supply = ak4458_supply_names[i];
+
+ ret = devm_regulator_bulk_get(ak4458->dev, ARRAY_SIZE(ak4458->supplies),
+ ak4458->supplies);
+ if (ret != 0) {
+ dev_err(ak4458->dev, "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
ret = devm_snd_soc_register_component(ak4458->dev, drvdata->comp_drv,
drvdata->dai_drv, 1);
if (ret < 0) {
@@ -700,6 +728,7 @@ static int ak4458_i2c_probe(struct i2c_client *i2c)
}
pm_runtime_enable(&i2c->dev);
+ regcache_cache_only(ak4458->regmap, true);
return 0;
}