Skip to content

Commit

Permalink
clk: si5341: Avoid divide errors due to bogus register contents
Browse files Browse the repository at this point in the history
[ Upstream commit 78f6f40 ]

If the Si5341 is being initially programmed and has no stored NVM
configuration, some of the register contents may contain unexpected
values, such as zeros, which could cause divide by zero errors during
driver initialization. Trap errors caused by zero registers or zero clock
rates which could result in divide errors later in the code.

Fixes: 3044a86 ("clk: Add Si5341/Si5340 driver")
Signed-off-by: Robert Hancock <robert.hancock@calian.com>
Link: https://lore.kernel.org/r/20210325192643.2190069-4-robert.hancock@calian.com
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
robhancocksed authored and gregkh committed Jul 14, 2021
1 parent 91a1de1 commit f09f20d
Showing 1 changed file with 13 additions and 2 deletions.
15 changes: 13 additions & 2 deletions drivers/clk/clk-si5341.c
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,9 @@ static unsigned long si5341_synth_clk_recalc_rate(struct clk_hw *hw,
SI5341_SYNTH_N_NUM(synth->index), &n_num, &n_den);
if (err < 0)
return err;
/* Check for bogus/uninitialized settings */
if (!n_num || !n_den)
return 0;

/*
* n_num and n_den are shifted left as much as possible, so to prevent
Expand Down Expand Up @@ -807,6 +810,9 @@ static long si5341_output_clk_round_rate(struct clk_hw *hw, unsigned long rate,
{
unsigned long r;

if (!rate)
return 0;

r = *parent_rate >> 1;

/* If rate is an even divisor, no changes to parent required */
Expand Down Expand Up @@ -835,11 +841,16 @@ static int si5341_output_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_si5341_output *output = to_clk_si5341_output(hw);
/* Frequency divider is (r_div + 1) * 2 */
u32 r_div = (parent_rate / rate) >> 1;
u32 r_div;
int err;
u8 r[3];

if (!rate)
return -EINVAL;

/* Frequency divider is (r_div + 1) * 2 */
r_div = (parent_rate / rate) >> 1;

if (r_div <= 1)
r_div = 0;
else if (r_div >= BIT(24))
Expand Down

0 comments on commit f09f20d

Please sign in to comment.