summaryrefslogtreecommitdiffstats
path: root/drivers/clk/bcm
diff options
context:
space:
mode:
authorLori Hikichi <lori.hikichi@broadcom.com>2017-08-14 21:00:39 +0200
committerStephen Boyd <sboyd@codeaurora.org>2017-12-28 23:53:34 +0100
commit85151a6b0b331f7bc4d9534d6138bfdd3e206b0d (patch)
tree641aa0820acb441ee4a6633527fea365b9a5885f /drivers/clk/bcm
parentclk: iproc: Allow iproc pll to runtime calculate vco parameters (diff)
downloadlinux-85151a6b0b331f7bc4d9534d6138bfdd3e206b0d.tar.xz
linux-85151a6b0b331f7bc4d9534d6138bfdd3e206b0d.zip
clk: iproc: Fix error in the pll post divider rate calculation
The pll post divider code was using DIV_ROUND_UP when determining the divider value best suited to produce the target frequency. Using DIV_ROUND_CLOSEST will give us better divider values when the division results in a small remainder. Also, change the post divider clock over to the determine_rate api instead of round_rate. Signed-off-by: Simran Rai <ssimran@broadcom.com> Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Diffstat (limited to 'drivers/clk/bcm')
-rw-r--r--drivers/clk/bcm/clk-iproc-pll.c33
1 files changed, 17 insertions, 16 deletions
diff --git a/drivers/clk/bcm/clk-iproc-pll.c b/drivers/clk/bcm/clk-iproc-pll.c
index 9514ecf319b0..7df010b2edcd 100644
--- a/drivers/clk/bcm/clk-iproc-pll.c
+++ b/drivers/clk/bcm/clk-iproc-pll.c
@@ -602,25 +602,26 @@ static unsigned long iproc_clk_recalc_rate(struct clk_hw *hw,
return clk->rate;
}
-static long iproc_clk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int iproc_clk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
- unsigned int div;
+ unsigned int bestdiv;
- if (rate == 0 || *parent_rate == 0)
+ if (req->rate == 0)
return -EINVAL;
+ if (req->rate == req->best_parent_rate)
+ return 0;
- if (rate == *parent_rate)
- return *parent_rate;
+ bestdiv = DIV_ROUND_CLOSEST(req->best_parent_rate, req->rate);
+ if (bestdiv < 2)
+ req->rate = req->best_parent_rate;
- div = DIV_ROUND_UP(*parent_rate, rate);
- if (div < 2)
- return *parent_rate;
+ if (bestdiv > 256)
+ bestdiv = 256;
- if (div > 256)
- div = 256;
+ req->rate = req->best_parent_rate / bestdiv;
- return *parent_rate / div;
+ return 0;
}
static int iproc_clk_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -635,10 +636,10 @@ static int iproc_clk_set_rate(struct clk_hw *hw, unsigned long rate,
if (rate == 0 || parent_rate == 0)
return -EINVAL;
+ div = DIV_ROUND_CLOSEST(parent_rate, rate);
if (ctrl->flags & IPROC_CLK_MCLK_DIV_BY_2)
- div = DIV_ROUND_UP(parent_rate, rate * 2);
- else
- div = DIV_ROUND_UP(parent_rate, rate);
+ div /= 2;
+
if (div > 256)
return -EINVAL;
@@ -662,7 +663,7 @@ static const struct clk_ops iproc_clk_ops = {
.enable = iproc_clk_enable,
.disable = iproc_clk_disable,
.recalc_rate = iproc_clk_recalc_rate,
- .round_rate = iproc_clk_round_rate,
+ .determine_rate = iproc_clk_determine_rate,
.set_rate = iproc_clk_set_rate,
};