The fractional part of the rk3036-style PLL rate is divided by
postdiv1 twice instead of by both postdiv1 and postdiv2. The integer
part also loses precision by calculating in MHz before converting to Hz.

Calculate both parts in Hz using u64 arithmetic and apply post-dividers
on the combined integer and fractional parts. This also closely matches
the Linux implementation.

Fixes: bbda2ed5840c ("rockchip: clk: pll: add common pll setting funcs")
Signed-off-by: Jonas Karlman <[email protected]>
---
Changes in v2:
- Change implementation to closer match Linux implementation
- Update commit message
- Add fixes tag
---
 drivers/clk/rockchip/clk_pll.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/clk/rockchip/clk_pll.c b/drivers/clk/rockchip/clk_pll.c
index f677525bba22..74b7ff5faa03 100644
--- a/drivers/clk/rockchip/clk_pll.c
+++ b/drivers/clk/rockchip/clk_pll.c
@@ -371,7 +371,7 @@ static ulong rk3036_pll_get_rate(struct rockchip_pll_clock 
*pll,
 {
        u32 refdiv, fbdiv, postdiv1, postdiv2, dsmpd, frac;
        u32 con = 0, shift, mask;
-       ulong rate;
+       u64 rate;
        int mode;
 
        con = readl(base + pll->mode_offset);
@@ -403,17 +403,18 @@ static ulong rk3036_pll_get_rate(struct 
rockchip_pll_clock *pll,
                con = readl(base + pll->con_offset + 0x8);
                frac = (con & RK3036_PLLCON2_FRAC_MASK) >>
                        RK3036_PLLCON2_FRAC_SHIFT;
-               rate = (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000;
+               rate = OSC_HZ * (u64)fbdiv;
+               do_div(rate, refdiv);
                if (dsmpd == 0) {
                        u64 frac_rate = OSC_HZ * (u64)frac;
 
                        do_div(frac_rate, refdiv);
                        frac_rate >>= 24;
-                       do_div(frac_rate, postdiv1);
-                       do_div(frac_rate, postdiv1);
                        rate += frac_rate;
                }
-               return rate;
+               do_div(rate, postdiv1);
+               do_div(rate, postdiv2);
+               return (ulong)rate;
        case RKCLK_PLL_MODE_DEEP:
        default:
                return 32768;
-- 
2.55.0

Reply via email to