Skip to content

Commit f8e7cd4

Browse files
alcharkbroonie
authored andcommitted
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 <alchark@flipper.net> Link: https://patch.msgid.link/20260525-nau8822-reg-v2-2-7d37ae393e46@flipper.net Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent caba925 commit f8e7cd4

2 files changed

Lines changed: 46 additions & 3 deletions

File tree

sound/soc/codecs/nau8822.c

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/pm.h>
2020
#include <linux/i2c.h>
2121
#include <linux/regmap.h>
22+
#include <linux/regulator/consumer.h>
2223
#include <linux/slab.h>
2324
#include <sound/core.h>
2425
#include <sound/pcm.h>
@@ -108,6 +109,10 @@ static const struct reg_default nau8822_reg_defaults[] = {
108109
{ NAU8822_REG_OUTPUT_TIEOFF, 0x0000 },
109110
};
110111

112+
static const char * const nau8822_supply_names[NAU8822_NUM_SUPPLIES] = {
113+
"vdda", "vddb", "vddc", "vddspk",
114+
};
115+
111116
static bool nau8822_readable_reg(struct device *dev, unsigned int reg)
112117
{
113118
switch (reg) {
@@ -1056,6 +1061,7 @@ static int nau8822_suspend(struct snd_soc_component *component)
10561061
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
10571062

10581063
snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF);
1064+
regulator_bulk_disable(NAU8822_NUM_SUPPLIES, nau8822->supplies);
10591065

10601066
regcache_mark_dirty(nau8822->regmap);
10611067

@@ -1066,6 +1072,15 @@ static int nau8822_resume(struct snd_soc_component *component)
10661072
{
10671073
struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component);
10681074
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
1075+
int ret = regulator_bulk_enable(NAU8822_NUM_SUPPLIES, nau8822->supplies);
1076+
1077+
if (ret) {
1078+
dev_err(component->dev,
1079+
"Failed to enable regulators: %d\n", ret);
1080+
return ret;
1081+
}
1082+
1083+
fsleep(100);
10691084

10701085
regcache_sync(nau8822->regmap);
10711086

@@ -1153,7 +1168,7 @@ static int nau8822_i2c_probe(struct i2c_client *i2c)
11531168
{
11541169
struct device *dev = &i2c->dev;
11551170
struct nau8822 *nau8822 = dev_get_platdata(dev);
1156-
int ret;
1171+
int ret, i;
11571172

11581173
if (!nau8822) {
11591174
nau8822 = devm_kzalloc(dev, sizeof(*nau8822), GFP_KERNEL);
@@ -1167,6 +1182,13 @@ static int nau8822_i2c_probe(struct i2c_client *i2c)
11671182
return dev_err_probe(&i2c->dev, PTR_ERR(nau8822->mclk),
11681183
"Error getting mclk\n");
11691184

1185+
for (i = 0; i < NAU8822_NUM_SUPPLIES; i++)
1186+
nau8822->supplies[i].supply = nau8822_supply_names[i];
1187+
1188+
ret = devm_regulator_bulk_get(dev, NAU8822_NUM_SUPPLIES, nau8822->supplies);
1189+
if (ret)
1190+
return dev_err_probe(dev, ret, "Failed to get regulators\n");
1191+
11701192
nau8822->regmap = devm_regmap_init_i2c(i2c, &nau8822_regmap_config);
11711193
if (IS_ERR(nau8822->regmap)) {
11721194
ret = PTR_ERR(nau8822->regmap);
@@ -1175,21 +1197,38 @@ static int nau8822_i2c_probe(struct i2c_client *i2c)
11751197
}
11761198
nau8822->dev = dev;
11771199

1200+
ret = regulator_bulk_enable(NAU8822_NUM_SUPPLIES, nau8822->supplies);
1201+
if (ret)
1202+
return dev_err_probe(dev, ret, "Failed to enable regulators\n");
1203+
1204+
fsleep(100);
1205+
11781206
/* Reset the codec */
11791207
ret = regmap_write(nau8822->regmap, NAU8822_REG_RESET, 0x00);
11801208
if (ret != 0) {
11811209
dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret);
1182-
return ret;
1210+
goto err_reg;
11831211
}
11841212

11851213
ret = devm_snd_soc_register_component(dev, &soc_component_dev_nau8822,
11861214
&nau8822_dai, 1);
11871215
if (ret != 0) {
11881216
dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
1189-
return ret;
1217+
goto err_reg;
11901218
}
11911219

11921220
return 0;
1221+
1222+
err_reg:
1223+
regulator_bulk_disable(NAU8822_NUM_SUPPLIES, nau8822->supplies);
1224+
return ret;
1225+
}
1226+
1227+
static void nau8822_i2c_remove(struct i2c_client *i2c)
1228+
{
1229+
struct nau8822 *nau8822 = i2c_get_clientdata(i2c);
1230+
1231+
regulator_bulk_disable(NAU8822_NUM_SUPPLIES, nau8822->supplies);
11931232
}
11941233

11951234
static const struct i2c_device_id nau8822_i2c_id[] = {
@@ -1212,6 +1251,7 @@ static struct i2c_driver nau8822_i2c_driver = {
12121251
.of_match_table = of_match_ptr(nau8822_of_match),
12131252
},
12141253
.probe = nau8822_i2c_probe,
1254+
.remove = nau8822_i2c_remove,
12151255
.id_table = nau8822_i2c_id,
12161256
};
12171257
module_i2c_driver(nau8822_i2c_driver);

sound/soc/codecs/nau8822.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,8 @@ struct nau8822_pll {
211211
int freq_out;
212212
};
213213

214+
#define NAU8822_NUM_SUPPLIES 4
215+
214216
/* Codec Private Data */
215217
struct nau8822 {
216218
struct device *dev;
@@ -219,6 +221,7 @@ struct nau8822 {
219221
struct nau8822_pll pll;
220222
int sysclk;
221223
int div_id;
224+
struct regulator_bulk_data supplies[NAU8822_NUM_SUPPLIES];
222225
};
223226

224227
#endif /* __NAU8822_H__ */

0 commit comments

Comments
 (0)