From 7626cbdf1704a15b4ea54095baa5bfdc5ad9cb29 Mon Sep 17 00:00:00 2001
From: Afzal Mohammed <>
Date: Mon, 21 Jan 2013 18:24:00 +0530
Subject: [PATCH 08/51] ARM: OMAP2+: dpll: round rate to closest value

Currently round rate function would return proper rate iff requested
rate exactly matches the PLL lockable rate. This causes set_rate to
fail if exact rate could not be set. Instead round rate may return
closest rate possible (less than the requested). And if any user is
badly in need of exact rate, then return value of round rate could
be used to decide whether to invoke set rate or not.

Modify round rate so that it return closest possible rate.

This was required to get display working on am335x. Without this
display rate could not be set (taking help of SET_RATE_PARENT). Couple
of the downstream clocks of display PLL are basic clock dividers and
they do MULT_ROUND_UP before requesting rate on PLL causing values
that mostly could not be locked by PLL. And even otherwise, if
requested rate for a particular pixel clock could not be satisfied by
PLL, display would not work. This change will resolve the issue.

Signed-off-by: Afzal Mohammed <>
 arch/arm/mach-omap2/clkt_dpll.c |   12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/arch/arm/mach-omap2/clkt_dpll.c
index 924c230..15e6d41 100644
--- a/arch/arm/mach-omap2/clkt_dpll.c
+++ b/arch/arm/mach-omap2/clkt_dpll.c
@@ -345,20 +345,22 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
 		pr_debug("clock: %s: m = %d: n = %d: new_rate = %ld\n",
 			 clk_name, m, n, new_rate);
-		if (target_rate == new_rate) {
+		if ((new_rate <= target_rate) &&
+		    (new_rate > dd->last_rounded_rate)) {
 			dd->last_rounded_m = m;
 			dd->last_rounded_n = n;
-			dd->last_rounded_rate = target_rate;
-			break;
+			dd->last_rounded_rate = new_rate;
+			if (new_rate == target_rate)
+				break;
-	if (target_rate != new_rate) {
+	if (!dd->last_rounded_rate) {
 		pr_debug("clock: %s: cannot round to rate %ld\n",
 			 clk_name, target_rate);
 		return ~0;
-	return target_rate;
+	return dd->last_rounded_rate;