]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ASoC: tlv320aic3x: Fix class-D initialization for tlv320aic3007
authorPrimoz Fiser <primoz.fiser@norik.com>
Thu, 25 Sep 2025 08:59:29 +0000 (10:59 +0200)
committerMark Brown <broonie@kernel.org>
Fri, 26 Sep 2025 00:34:43 +0000 (01:34 +0100)
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>
sound/soc/codecs/tlv320aic3x.c

index f1649df197389d301901544b875757ea9b95a1b0..eea8ca285f8e0fe0305a0ed0638ef8211ca58a77 100644 (file)
@@ -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;