diff options
author | 2020-11-30 10:10:33 +0100 | |
---|---|---|
committer | 2020-12-19 15:49:54 -0800 | |
commit | 5142cbcea324909be03b176540c0c2f3975922b4 (patch) | |
tree | 9c3b0cb6b31c484723535ac3112000ad066b831c /drivers | |
parent | Linux 5.10-rc1 (diff) | |
download | linux-5142cbcea324909be03b176540c0c2f3975922b4.tar.gz linux-5142cbcea324909be03b176540c0c2f3975922b4.tar.bz2 linux-5142cbcea324909be03b176540c0c2f3975922b4.zip |
clk: si5351: Wait for bit clear after PLL reset
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/clk-si5351.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c index 1e1702e609cb..57e4597cdf4c 100644 --- a/drivers/clk/clk-si5351.c +++ b/drivers/clk/clk-si5351.c @@ -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), |