summaryrefslogtreecommitdiffstats
path: root/drivers/clk/mxs
diff options
context:
space:
mode:
authorVictorien Vedrine <victorien.vedrine@ophrys.net>2015-08-31 10:45:07 +0200
committerStephen Boyd <sboyd@codeaurora.org>2015-10-01 15:24:34 -0700
commitd87574332cd669c8949b75e87e499a7478dffead (patch)
tree90dce79afe43232a64cf6f6941d00817565cfb85 /drivers/clk/mxs
parenta1c22a4be7983f64324e960f7ba373784c0c8289 (diff)
downloadlinux-d87574332cd669c8949b75e87e499a7478dffead.tar.bz2
clk:mxs: Fix bug on frequency divider
On drivers/clk/mxs/clk-frac.c, the function clk_frac_round_rate returned a bad result. The division before multiplication computes a wrong value ; the calculation is inverted to fix the problem. The second issue is that the exact rate have decimals and they are truncate. The consequence is that the function clk_frac_set_rate (which use the result of clk_frac_round_rate) computes a wrong value for the register (the rate generated can be closer to the desired rate). The correction is : if there is decimal to the result, it is rounded to the next larger integer. On drivers/clk/mxs/clk-frac.c, the function clk_frac_recalc_rate returned a bad result. The multiplication is made before the division to compute a correct value. Signed-off-by: Victorien Vedrine <victorien.vedrine@ophrys.net> Acked-by: Shawn Guo <shawnguo@kernel.org> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Diffstat (limited to 'drivers/clk/mxs')
-rw-r--r--drivers/clk/mxs/clk-frac.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/drivers/clk/mxs/clk-frac.c b/drivers/clk/mxs/clk-frac.c
index 73f0240569ac..f8dd10f6df3d 100644
--- a/drivers/clk/mxs/clk-frac.c
+++ b/drivers/clk/mxs/clk-frac.c
@@ -41,11 +41,13 @@ static unsigned long clk_frac_recalc_rate(struct clk_hw *hw,
{
struct clk_frac *frac = to_clk_frac(hw);
u32 div;
+ u64 tmp_rate;
div = readl_relaxed(frac->reg) >> frac->shift;
div &= (1 << frac->width) - 1;
- return (parent_rate >> frac->width) * div;
+ tmp_rate = (u64)parent_rate * div;
+ return tmp_rate >> frac->width;
}
static long clk_frac_round_rate(struct clk_hw *hw, unsigned long rate,
@@ -54,7 +56,7 @@ static long clk_frac_round_rate(struct clk_hw *hw, unsigned long rate,
struct clk_frac *frac = to_clk_frac(hw);
unsigned long parent_rate = *prate;
u32 div;
- u64 tmp;
+ u64 tmp, tmp_rate, result;
if (rate > parent_rate)
return -EINVAL;
@@ -67,7 +69,11 @@ static long clk_frac_round_rate(struct clk_hw *hw, unsigned long rate,
if (!div)
return -EINVAL;
- return (parent_rate >> frac->width) * div;
+ tmp_rate = (u64)parent_rate * div;
+ result = tmp_rate >> frac->width;
+ if ((result << frac->width) < tmp_rate)
+ result += 1;
+ return result;
}
static int clk_frac_set_rate(struct clk_hw *hw, unsigned long rate,