mirror of
https://github.com/torvalds/linux.git
synced 2026-05-22 06:01:53 +02:00
ASoC: tlv320aic3x: Fix class-D initialization for tlv320aic3007
The problem of having class-D initialization sequence in probe using regmap_register_patch() is that it will do hardware register writes immediately after being called as it bypasses regcache. Afterwards, in aic3x_init() we also perform codec soft reset, rendering class-D init sequence pointless. This issue is even more apparent when using reset GPIO line, since in that case class-D amplifier initialization fails with "Failed to init class D: -5" message as codec is already held in reset state after requesting the reset GPIO and hence hardware I/O fails with -EIO errno. Thus move class-D amplifier initialization sequence from probe function to aic3x_set_power() just before the usual regcache sync. Use bypassed regmap_multi_reg_write_bypassed() function to make sure, class-D init sequence is performed in proper order as described in the datasheet. Signed-off-by: Primoz Fiser <primoz.fiser@norik.com> Link: https://patch.msgid.link/20250925085929.2581749-1-primoz.fiser@norik.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
ba0c67d3c4
commit
733a763dd8
|
|
@ -121,6 +121,16 @@ static const struct reg_default aic3x_reg[] = {
|
|||
{ 108, 0x00 }, { 109, 0x00 },
|
||||
};
|
||||
|
||||
static const struct reg_sequence aic3007_class_d[] = {
|
||||
/* Class-D speaker driver init; datasheet p. 46 */
|
||||
{ AIC3X_PAGE_SELECT, 0x0D },
|
||||
{ 0xD, 0x0D },
|
||||
{ 0x8, 0x5C },
|
||||
{ 0x8, 0x5D },
|
||||
{ 0x8, 0x5C },
|
||||
{ AIC3X_PAGE_SELECT, 0x00 },
|
||||
};
|
||||
|
||||
static bool aic3x_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
|
|
@ -1393,6 +1403,10 @@ static int aic3x_set_power(struct snd_soc_component *component, int power)
|
|||
gpiod_set_value(aic3x->gpio_reset, 0);
|
||||
}
|
||||
|
||||
if (aic3x->model == AIC3X_MODEL_3007)
|
||||
regmap_multi_reg_write_bypassed(aic3x->regmap, aic3007_class_d,
|
||||
ARRAY_SIZE(aic3007_class_d));
|
||||
|
||||
/* Sync reg_cache with the hardware */
|
||||
regcache_cache_only(aic3x->regmap, false);
|
||||
regcache_sync(aic3x->regmap);
|
||||
|
|
@ -1723,17 +1737,6 @@ static void aic3x_configure_ocmv(struct device *dev, struct aic3x_priv *aic3x)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static const struct reg_sequence aic3007_class_d[] = {
|
||||
/* Class-D speaker driver init; datasheet p. 46 */
|
||||
{ AIC3X_PAGE_SELECT, 0x0D },
|
||||
{ 0xD, 0x0D },
|
||||
{ 0x8, 0x5C },
|
||||
{ 0x8, 0x5D },
|
||||
{ 0x8, 0x5C },
|
||||
{ AIC3X_PAGE_SELECT, 0x00 },
|
||||
};
|
||||
|
||||
int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver_data)
|
||||
{
|
||||
struct aic3x_priv *aic3x;
|
||||
|
|
@ -1823,13 +1826,6 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver
|
|||
|
||||
aic3x_configure_ocmv(dev, aic3x);
|
||||
|
||||
if (aic3x->model == AIC3X_MODEL_3007) {
|
||||
ret = regmap_register_patch(aic3x->regmap, aic3007_class_d,
|
||||
ARRAY_SIZE(aic3007_class_d));
|
||||
if (ret != 0)
|
||||
dev_err(dev, "Failed to init class D: %d\n", ret);
|
||||
}
|
||||
|
||||
ret = devm_snd_soc_register_component(dev, &soc_component_dev_aic3x, &aic3x_dai, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user