clk: g12a/g12b: fix 32bit set mpll clk overflow [1/1]
authorShunzhou Jiang <shunzhou.jiang@amlogic.com>
Fri, 16 Nov 2018 07:54:52 +0000 (15:54 +0800)
committerJianxin Pan <jianxin.pan@amlogic.com>
Mon, 19 Nov 2018 12:23:28 +0000 (04:23 -0800)
PD#SWPL-1933

Problem:
32bit system clk overflow

Solution:
let mpll clock not overflow

Verify:
g12b

Change-Id: Ie1c7c611e637776348bb35a3e0c1624cee57716f
Signed-off-by: shunzhou.jiang <shunzhou.jiang@amlogic.com>
drivers/amlogic/clk/g12a/g12a_clk-mpll.c

index 1d62f34..abd74ea 100644 (file)
@@ -28,7 +28,7 @@
 #include "../clkc.h"
 /* #undef pr_debug */
 /* #define pr_debug pr_info */
-#define SDM_MAX 16384
+#define SDM_MAX 16384ULL
 #define MAX_RATE       500000000
 #define MIN_RATE       3920000
 
@@ -87,6 +87,7 @@ static int mpll_set_rate(struct clk_hw *hw, unsigned long rate,
        struct parm *p;
        unsigned long reg, sdm, n2;
        unsigned long flags = 0;
+       uint64_t rate64 = parent_rate;
 
        if ((rate > MAX_RATE) || (rate < MIN_RATE)) {
                pr_err("Err: can not set rate to %lu!\n", rate);
@@ -98,8 +99,12 @@ static int mpll_set_rate(struct clk_hw *hw, unsigned long rate,
                spin_lock_irqsave(mpll->lock, flags);
 
        /* calculate new n2 and sdm */
-       n2 = parent_rate / rate;
-       sdm = DIV_ROUND_UP((parent_rate - n2 * rate) * SDM_MAX, rate);
+       do_div(rate64, rate);
+       n2 = rate64;
+
+       rate64 = (parent_rate - n2 * rate) * SDM_MAX + rate - 1;
+       do_div(rate64, rate);
+       sdm = rate64;
        if (sdm >= SDM_MAX)
                sdm = SDM_MAX - 1;