mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 18:21:24 +02:00
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>
This commit is contained in:
parent
caba9259a2
commit
f8e7cd48e5
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user