clk: si5351: Wait for bit clear after PLL reset
authorSascha Hauer <s.hauer@pengutronix.de>
Mon, 30 Nov 2020 09:10:33 +0000 (10:10 +0100)
committerStephen Boyd <sboyd@kernel.org>
Sat, 19 Dec 2020 23:49:54 +0000 (15:49 -0800)
Documentation states that SI5351_PLL_RESET_B and SI5351_PLL_RESET_A bits
are self clearing bits, so wait until they are cleared before
continuing.
This fixes a case when the clock doesn't come up properly after a PLL
reset. It worked properly when the frequency was below 900MHz, but with
900MHz it only works when we are waiting for the bit to clear.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Link: https://lore.kernel.org/r/20201130091033.1687-1-s.hauer@pengutronix.de
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
drivers/clk/clk-si5351.c

index 1e1702e609cbb006948859433986393690726ea9..57e4597cdf4c20eb87d56a5348098fdbbf9876a9 100644 (file)
@@ -902,6 +902,10 @@ static int _si5351_clkout_set_disable_state(
 static void _si5351_clkout_reset_pll(struct si5351_driver_data *drvdata, int num)
 {
        u8 val = si5351_reg_read(drvdata, SI5351_CLK0_CTRL + num);
+       u8 mask = val & SI5351_CLK_PLL_SELECT ? SI5351_PLL_RESET_B :
+                                                      SI5351_PLL_RESET_A;
+       unsigned int v;
+       int err;
 
        switch (val & SI5351_CLK_INPUT_MASK) {
        case SI5351_CLK_INPUT_XTAL:
@@ -909,9 +913,12 @@ static void _si5351_clkout_reset_pll(struct si5351_driver_data *drvdata, int num
                return;  /* pll not used, no need to reset */
        }
 
-       si5351_reg_write(drvdata, SI5351_PLL_RESET,
-                        val & SI5351_CLK_PLL_SELECT ? SI5351_PLL_RESET_B :
-                                                      SI5351_PLL_RESET_A);
+       si5351_reg_write(drvdata, SI5351_PLL_RESET, mask);
+
+       err = regmap_read_poll_timeout(drvdata->regmap, SI5351_PLL_RESET, v,
+                                !(v & mask), 0, 20000);
+       if (err < 0)
+               dev_err(&drvdata->client->dev, "Reset bit didn't clear\n");
 
        dev_dbg(&drvdata->client->dev, "%s - %s: pll = %d\n",
                __func__, clk_hw_get_name(&drvdata->clkout[num].hw),