Re: [PATCH 2/2] clk: Add fractional scale clock support
From: Hoan Tran <hidden>
Date: 2016-06-17 16:30:26
Also in:
linux-clk, lkml
Hi Geert, On Thu, Jun 16, 2016 at 11:43 PM, Geert Uytterhoeven [off-list ref] wrote:
On Fri, Jun 17, 2016 at 1:40 AM, Hoan Tran [off-list ref] wrote:quoted
This patch adds fractional scale clock support. Fractional scale clock is implemented for a single register field. Output rate = parent_rate * scale / denominator For example, for 1 / 8 fractional scale, denominator will be 8 and scale will be computed and programmed accordingly. Signed-off-by: Hoan Tran <redacted> Signed-off-by: Loc Ho <redacted>quoted
--- /dev/null +++ b/drivers/clk/clk-fractional-scale.cquoted
+static long clk_fs_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk_fractional_scale *fd = to_clk_sf(hw); + u64 ret, scale; + + if (!rate || rate >= *parent_rate) + return *parent_rate; + + /* freq = parent_rate * scaler / denom */ + ret = rate * fd->denom;Can this overflow? No, because fd->denom is u64. But if fd->denom is changed to u32, it needs a cast to u64 here.quoted
+ scale = ret / *parent_rate;As detected by the kbuild test robot, this should use do_div().
Yes, my mistake. I'll fix it.
quoted
+ + ret = (u64) *parent_rate * scale; + do_div(ret, fd->denom); + + return ret; +} + +static int clk_fs_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_fractional_scale *fd = to_clk_sf(hw); + unsigned long flags = 0; + u64 scale, ret; + u32 val; + + /* + * Compute the scaler: + * + * freq = parent_rate * scaler / denom, or + * scaler = freq * denom / parent_rate + */ + ret = rate * fd->denom;Can this overflow? No, because fd->denom is u64. But if fd->denom is changed to u32, it needs a cast to u64 here.quoted
+ scale = ret / (u64)parent_rate;Don't cast the divider to u64, as this will turn a 64-by-32 division into a 64-by-64 division. As detected by the kbuild test robot, this should use do_div().
Will fix it. Thanks Hoan
quoted
--- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.hquoted
+struct clk_fractional_scale { + struct clk_hw hw; + void __iomem *reg; + u8 shift; + u32 mask; + u64 denom;u64 sounds overkill to me, but it looks like that was done to avoid overflow in the multiplications?quoted
+ u32 flags; + spinlock_t *lock; +};Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds