4.14-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Paul Cercueil <p...@crapouillou.net>

commit bc5d922c93491878c44c9216e9d227c7eeb81d7f upstream.

Take a parent rate of 180 MHz, and a requested rate of 4.285715 MHz.
This results in a theorical divider of 41.999993 which is then rounded
up to 42. The .round_rate function would then return (180 MHz / 42) as
the clock, rounded down, so 4.285714 MHz.

Calling clk_set_rate on 4.285714 MHz would round the rate again, and
give a theorical divider of 42,0000028, now rounded up to 43, and the
rate returned would be (180 MHz / 43) which is 4.186046 MHz, aka. not
what we requested.

Fix this by rounding up the divisions.

Signed-off-by: Paul Cercueil <p...@crapouillou.net>
Tested-by: Maarten ter Huurne <maar...@treewalker.org>
Cc: <sta...@vger.kernel.org>
Signed-off-by: Stephen Boyd <sb...@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>

---
 drivers/clk/ingenic/cgu.c |   10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -364,16 +364,16 @@ ingenic_clk_round_rate(struct clk_hw *hw
        struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
        struct ingenic_cgu *cgu = ingenic_clk->cgu;
        const struct ingenic_cgu_clk_info *clk_info;
-       long rate = *parent_rate;
+       unsigned int div = 1;
 
        clk_info = &cgu->clock_info[ingenic_clk->idx];
 
        if (clk_info->type & CGU_CLK_DIV)
-               rate /= ingenic_clk_calc_div(clk_info, *parent_rate, req_rate);
+               div = ingenic_clk_calc_div(clk_info, *parent_rate, req_rate);
        else if (clk_info->type & CGU_CLK_FIXDIV)
-               rate /= clk_info->fixdiv.div;
+               div = clk_info->fixdiv.div;
 
-       return rate;
+       return DIV_ROUND_UP(*parent_rate, div);
 }
 
 static int
@@ -393,7 +393,7 @@ ingenic_clk_set_rate(struct clk_hw *hw,
 
        if (clk_info->type & CGU_CLK_DIV) {
                div = ingenic_clk_calc_div(clk_info, parent_rate, req_rate);
-               rate = parent_rate / div;
+               rate = DIV_ROUND_UP(parent_rate, div);
 
                if (rate != req_rate)
                        return -EINVAL;


Reply via email to