diff mbox series

clk: si5351: Wait for bit clear after PLL reset

Message ID 20201021143026.406-1-s.hauer@pengutronix.de (mailing list archive)
State Superseded, archived
Headers show
Series clk: si5351: Wait for bit clear after PLL reset | expand

Commit Message

Sascha Hauer Oct. 21, 2020, 2:30 p.m. UTC
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>
---
 drivers/clk/clk-si5351.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

Comments

Sascha Hauer Nov. 5, 2020, 3:40 p.m. UTC | #1
Hi All,

Any feedback to this one? It fixes a real issue here.

Sascha


On Wed, Oct 21, 2020 at 04:30:26PM +0200, Sascha Hauer wrote:
> 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>
> ---
>  drivers/clk/clk-si5351.c | 13 ++++++++++---
>  1 file 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),
> -- 
> 2.20.1
> 
>
diff mbox series

Patch

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),