Path: csiph.com!news.mixmin.net!news.unit0.net!news.panservice.it!bofh.it!news.nic.it!robomod From: Keerthy Newsgroups: linux.kernel Subject: [PATCH] clk: ti: divider: Add the table parsing to get the best divider value Date: Fri, 02 Dec 2016 10:10:02 +0100 Message-ID: X-Mailer: git-send-email 1.9.1 MIME-Version: 1.0 Content-Type: text/plain Sender: robomod@news.nic.it List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Approved: robomod@news.nic.it Lines: 66 Organization: linux.* mail to news gateway X-Original-Cc: , , , , , X-Original-Date: Fri, 2 Dec 2016 14:35:43 +0530 X-Original-Message-ID: <1480669543-16197-1-git-send-email-j-keerthy@ti.com> X-Original-Sender: linux-kernel-owner@vger.kernel.org Xref: csiph.com linux.kernel:1534757 Currently the divider selection logic blindly divides the parent_rate by the clk rate and gives the divider value for the divider clocks which do not have the CLK_SET_RATE_PARENT flag set. Add the clk divider table parsing to get the closest divider available in the table provided via Device tree. The code is pretty much taken from: drivers/clk/clk-divider.c. and used here to fix up the best divider selection logic. Signed-off-by: Keerthy Reported-by: Richard Woodruff --- drivers/clk/ti/divider.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c index b4e5de1..6bb8778 100644 --- a/drivers/clk/ti/divider.c +++ b/drivers/clk/ti/divider.c @@ -140,6 +140,35 @@ static bool _is_valid_div(struct clk_divider *divider, unsigned int div) return true; } +static int _div_round_up(const struct clk_div_table *table, + unsigned long parent_rate, unsigned long rate) +{ + const struct clk_div_table *clkt; + int up = INT_MAX; + int div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); + + for (clkt = table; clkt->div; clkt++) { + if (clkt->div == div) + return clkt->div; + else if (clkt->div < div) + continue; + + if ((clkt->div - div) < (up - div)) + up = clkt->div; + } + + return up; +} + +static int _div_round(const struct clk_div_table *table, + unsigned long parent_rate, unsigned long rate) +{ + if (!table) + return DIV_ROUND_UP(parent_rate, rate); + + return _div_round_up(table, parent_rate, rate); +} + static int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate) { @@ -155,7 +184,7 @@ static int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { parent_rate = *best_parent_rate; - bestdiv = DIV_ROUND_UP(parent_rate, rate); + bestdiv = _div_round(divider->table, parent_rate, rate); bestdiv = bestdiv == 0 ? 1 : bestdiv; bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; return bestdiv; -- 1.9.1