ASoC: tlv320aic32x4: Fix the divide by zero
authorGuiting Shen <aarongt.shen@gmail.com>
Sun, 13 Aug 2023 12:55:20 +0000 (20:55 +0800)
committerMark Brown <broonie@kernel.org>
Mon, 14 Aug 2023 12:10:37 +0000 (13:10 +0100)
The value of register(NDAC,MDAC,NADC,MADC,BCLKN) maybe zero lead to
divide by zero in clk_aic32x4_div_recalc_rate().And the rate should be
divide by 128 if the value was zero in this function according to the
datasheet.

Add the macro AIC32X4_DIV_MAX to present the 128 and return 0 if failing
to read the value of register.

Signed-off-by: Guiting Shen <aarongt.shen@gmail.com>
Link: https://lore.kernel.org/r/20230813125520.11067-1-aarongt.shen@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/tlv320aic32x4-clk.c
sound/soc/codecs/tlv320aic32x4.h

index c116e82..5c0a76a 100644 (file)
@@ -321,7 +321,7 @@ static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate,
        u8 divisor;
 
        divisor = DIV_ROUND_UP(parent_rate, rate);
-       if (divisor > 128)
+       if (divisor > AIC32X4_DIV_MAX)
                return -EINVAL;
 
        return regmap_update_bits(div->regmap, div->reg,
@@ -334,7 +334,7 @@ static int clk_aic32x4_div_determine_rate(struct clk_hw *hw,
        unsigned long divisor;
 
        divisor = DIV_ROUND_UP(req->best_parent_rate, req->rate);
-       if (divisor > 128)
+       if (divisor > AIC32X4_DIV_MAX)
                return -EINVAL;
 
        req->rate = DIV_ROUND_UP(req->best_parent_rate, divisor);
@@ -345,12 +345,18 @@ static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw,
                                                unsigned long parent_rate)
 {
        struct clk_aic32x4 *div = to_clk_aic32x4(hw);
-
        unsigned int val;
+       int err;
+
+       err = regmap_read(div->regmap, div->reg, &val);
+       if (err)
+               return 0;
 
-       regmap_read(div->regmap, div->reg, &val);
+       val &= AIC32X4_DIV_MASK;
+       if (!val)
+               val = AIC32X4_DIV_MAX;
 
-       return DIV_ROUND_UP(parent_rate, val & AIC32X4_DIV_MASK);
+       return DIV_ROUND_UP(parent_rate, val);
 }
 
 static const struct clk_ops aic32x4_div_ops = {
index 4de5bd9..d6101ce 100644 (file)
@@ -223,8 +223,9 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name);
 #define AIC32X4_REFPOWERUP_120MS       0x07
 
 /* Common mask and enable for all of the dividers */
-#define AIC32X4_DIVEN           BIT(7)
-#define AIC32X4_DIV_MASK        GENMASK(6, 0)
+#define AIC32X4_DIVEN                  BIT(7)
+#define AIC32X4_DIV_MASK               GENMASK(6, 0)
+#define AIC32X4_DIV_MAX                        128
 
 /* Clock Limits */
 #define AIC32X4_MAX_DOSR_FREQ          6200000