From: Alexey Charkov Date: Mon, 25 May 2026 09:20:46 +0000 (+0400) Subject: ASoC: codecs: nau8822: add support for supply regulators X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f8e7cd48e5b3b38ec5e1542b73b670a7770d2d7c;p=thirdparty%2Flinux.git ASoC: codecs: nau8822: add support for supply regulators 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 Link: https://patch.msgid.link/20260525-nau8822-reg-v2-2-7d37ae393e46@flipper.net Signed-off-by: Mark Brown --- diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c index a11759f85eaca..cd4a7de47939b 100644 --- a/sound/soc/codecs/nau8822.c +++ b/sound/soc/codecs/nau8822.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -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 13fe0a091e9ed..24799c7b5931b 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__ */