Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: mmp: frac: Do not lose last 4 digits of precision

While calculating the output rate of a fractional divider clock, the
value is divided and multipled by 10000, discarding the least
significant digits -- presumably to fit the intermediate value within 32
bits.

The precision we're losing is, however, not insignificant for things like
I2S clock. Maybe also elsewhere, now that since commit ea56ad60260e ("clk:
mmp2: Stop pretending PLL outputs are constant") the parent rates are more
precise and no longer rounded to 10000s.

Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
Link: https://lkml.kernel.org/r/20200519224151.2074597-2-lkundrak@v3.sk
Signed-off-by: Stephen Boyd <sboyd@kernel.org>

authored by

Lubomir Rintel and committed by
Stephen Boyd
06030c4e 8f3d9f35

+16 -8
+16 -8
drivers/clk/mmp/clk-frac.c
··· 28 28 unsigned long *prate) 29 29 { 30 30 struct mmp_clk_factor *factor = to_clk_factor(hw); 31 - unsigned long rate = 0, prev_rate; 31 + u64 rate = 0, prev_rate; 32 32 int i; 33 33 34 34 for (i = 0; i < factor->ftbl_cnt; i++) { 35 35 prev_rate = rate; 36 - rate = (((*prate / 10000) * factor->ftbl[i].den) / 37 - (factor->ftbl[i].num * factor->masks->factor)) * 10000; 36 + rate = *prate; 37 + rate *= factor->ftbl[i].den; 38 + do_div(rate, factor->ftbl[i].num * factor->masks->factor); 39 + 38 40 if (rate > drate) 39 41 break; 40 42 } ··· 56 54 struct mmp_clk_factor *factor = to_clk_factor(hw); 57 55 struct mmp_clk_factor_masks *masks = factor->masks; 58 56 unsigned int val, num, den; 57 + u64 rate; 59 58 60 59 val = readl_relaxed(factor->base); 61 60 ··· 69 66 if (!den) 70 67 return 0; 71 68 72 - return (((parent_rate / 10000) * den) / 73 - (num * factor->masks->factor)) * 10000; 69 + rate = parent_rate; 70 + rate *= den; 71 + do_div(rate, num * factor->masks->factor); 72 + 73 + return rate; 74 74 } 75 75 76 76 /* Configures new clock rate*/ ··· 84 78 struct mmp_clk_factor_masks *masks = factor->masks; 85 79 int i; 86 80 unsigned long val; 87 - unsigned long rate = 0; 88 81 unsigned long flags = 0; 82 + u64 rate = 0; 89 83 90 84 for (i = 0; i < factor->ftbl_cnt; i++) { 91 - rate = (((prate / 10000) * factor->ftbl[i].den) / 92 - (factor->ftbl[i].num * factor->masks->factor)) * 10000; 85 + rate = prate; 86 + rate *= factor->ftbl[i].den; 87 + do_div(rate, factor->ftbl[i].num * factor->masks->factor); 88 + 93 89 if (rate > drate) 94 90 break; 95 91 }