[PATCH v2 2/2] ASoC: codecs: nau8822: add support for supply regulators
From: Alexey Charkov
Date: Mon May 25 2026 - 05:21:36 EST
NAU8822 has four power supply pins: VDDA, VDDB, VDDC, and VDDSPK, which
need to be online and stable before communication with the device is
attempted.
Request and enable these regulators at init time, if provided. Also wait
for 100 us after powering up the supply regulators before attempting to
access the device registers, as recommended by the datasheet.
This helps avoid -ENXIO errors when the codec is probed before the
regulators are ready.
Signed-off-by: Alexey Charkov <alchark@xxxxxxxxxxx>
---
sound/soc/codecs/nau8822.c | 46 +++++++++++++++++++++++++++++++++++++++++++---
sound/soc/codecs/nau8822.h | 3 +++
2 files changed, 46 insertions(+), 3 deletions(-)
diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c
index 19fee5f4bf5f..830164e991a7 100644
--- a/sound/soc/codecs/nau8822.c
+++ b/sound/soc/codecs/nau8822.c
@@ -19,6 +19,7 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -108,6 +109,10 @@ static const struct reg_default nau8822_reg_defaults[] = {
{ NAU8822_REG_OUTPUT_TIEOFF, 0x0000 },
};
+static const char * const nau8822_supply_names[NAU8822_NUM_SUPPLIES] = {
+ "vdda", "vddb", "vddc", "vddspk",
+};
+
static bool nau8822_readable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
@@ -1056,6 +1061,7 @@ static int nau8822_suspend(struct snd_soc_component *component)
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF);
+ regulator_bulk_disable(NAU8822_NUM_SUPPLIES, nau8822->supplies);
regcache_mark_dirty(nau8822->regmap);
@@ -1066,6 +1072,15 @@ static int nau8822_resume(struct snd_soc_component *component)
{
struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component);
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ int ret = regulator_bulk_enable(NAU8822_NUM_SUPPLIES, nau8822->supplies);
+
+ if (ret) {
+ dev_err(component->dev,
+ "Failed to enable regulators: %d\n", ret);
+ return ret;
+ }
+
+ fsleep(100);
regcache_sync(nau8822->regmap);
@@ -1153,7 +1168,7 @@ static int nau8822_i2c_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
struct nau8822 *nau8822 = dev_get_platdata(dev);
- int ret;
+ int ret, i;
if (!nau8822) {
nau8822 = devm_kzalloc(dev, sizeof(*nau8822), GFP_KERNEL);
@@ -1167,6 +1182,13 @@ static int nau8822_i2c_probe(struct i2c_client *i2c)
return dev_err_probe(&i2c->dev, PTR_ERR(nau8822->mclk),
"Error getting mclk\n");
+ for (i = 0; i < NAU8822_NUM_SUPPLIES; i++)
+ nau8822->supplies[i].supply = nau8822_supply_names[i];
+
+ ret = devm_regulator_bulk_get(dev, NAU8822_NUM_SUPPLIES, nau8822->supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get regulators\n");
+
nau8822->regmap = devm_regmap_init_i2c(i2c, &nau8822_regmap_config);
if (IS_ERR(nau8822->regmap)) {
ret = PTR_ERR(nau8822->regmap);
@@ -1175,21 +1197,38 @@ static int nau8822_i2c_probe(struct i2c_client *i2c)
}
nau8822->dev = dev;
+ ret = regulator_bulk_enable(NAU8822_NUM_SUPPLIES, nau8822->supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable regulators\n");
+
+ fsleep(100);
+
/* Reset the codec */
ret = regmap_write(nau8822->regmap, NAU8822_REG_RESET, 0x00);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret);
- return ret;
+ goto err_reg;
}
ret = devm_snd_soc_register_component(dev, &soc_component_dev_nau8822,
&nau8822_dai, 1);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
- return ret;
+ goto err_reg;
}
return 0;
+
+err_reg:
+ regulator_bulk_disable(NAU8822_NUM_SUPPLIES, nau8822->supplies);
+ return ret;
+}
+
+static void nau8822_i2c_remove(struct i2c_client *i2c)
+{
+ struct nau8822 *nau8822 = i2c_get_clientdata(i2c);
+
+ regulator_bulk_disable(NAU8822_NUM_SUPPLIES, nau8822->supplies);
}
static const struct i2c_device_id nau8822_i2c_id[] = {
@@ -1212,6 +1251,7 @@ static struct i2c_driver nau8822_i2c_driver = {
.of_match_table = of_match_ptr(nau8822_of_match),
},
.probe = nau8822_i2c_probe,
+ .remove = nau8822_i2c_remove,
.id_table = nau8822_i2c_id,
};
module_i2c_driver(nau8822_i2c_driver);
diff --git a/sound/soc/codecs/nau8822.h b/sound/soc/codecs/nau8822.h
index 13fe0a091e9e..24799c7b5931 100644
--- a/sound/soc/codecs/nau8822.h
+++ b/sound/soc/codecs/nau8822.h
@@ -211,6 +211,8 @@ struct nau8822_pll {
int freq_out;
};
+#define NAU8822_NUM_SUPPLIES 4
+
/* Codec Private Data */
struct nau8822 {
struct device *dev;
@@ -219,6 +221,7 @@ struct nau8822 {
struct nau8822_pll pll;
int sysclk;
int div_id;
+ struct regulator_bulk_data supplies[NAU8822_NUM_SUPPLIES];
};
#endif /* __NAU8822_H__ */
--
2.52.0