|
@@ -285,3 +285,80 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk)
|
|
* possible, programmable rate for this DPLL. Attempts to select the
|
|
* possible, programmable rate for this DPLL. Attempts to select the
|
|
* minimum possible n. Stores the computed (m, n) in the DPLL's
|
|
* minimum possible n. Stores the computed (m, n) in the DPLL's
|
|
* dpll_data structure so set_rate() will not need to call this
|
|
* dpll_data structure so set_rate() will not need to call this
|
|
|
|
+ * (expensive) function again. Returns ~0 if the target rate cannot
|
|
|
|
+ * be rounded, or the rounded rate upon success.
|
|
|
|
+ */
|
|
|
|
+long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
|
|
|
|
+ unsigned long *parent_rate)
|
|
|
|
+{
|
|
|
|
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
|
|
|
|
+ int m, n, r, scaled_max_m;
|
|
|
|
+ unsigned long scaled_rt_rp;
|
|
|
|
+ unsigned long new_rate = 0;
|
|
|
|
+ struct dpll_data *dd;
|
|
|
|
+ unsigned long ref_rate;
|
|
|
|
+ const char *clk_name;
|
|
|
|
+
|
|
|
|
+ if (!clk || !clk->dpll_data)
|
|
|
|
+ return ~0;
|
|
|
|
+
|
|
|
|
+ dd = clk->dpll_data;
|
|
|
|
+
|
|
|
|
+ ref_rate = __clk_get_rate(dd->clk_ref);
|
|
|
|
+ clk_name = __clk_get_name(hw->clk);
|
|
|
|
+ pr_debug("clock: %s: starting DPLL round_rate, target rate %ld\n",
|
|
|
|
+ clk_name, target_rate);
|
|
|
|
+
|
|
|
|
+ scaled_rt_rp = target_rate / (ref_rate / DPLL_SCALE_FACTOR);
|
|
|
|
+ scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR;
|
|
|
|
+
|
|
|
|
+ dd->last_rounded_rate = 0;
|
|
|
|
+
|
|
|
|
+ for (n = dd->min_divider; n <= dd->max_divider; n++) {
|
|
|
|
+
|
|
|
|
+ /* Is the (input clk, divider) pair valid for the DPLL? */
|
|
|
|
+ r = _dpll_test_fint(clk, n);
|
|
|
|
+ if (r == DPLL_FINT_UNDERFLOW)
|
|
|
|
+ break;
|
|
|
|
+ else if (r == DPLL_FINT_INVALID)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ /* Compute the scaled DPLL multiplier, based on the divider */
|
|
|
|
+ m = scaled_rt_rp * n;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Since we're counting n up, a m overflow means we
|
|
|
|
+ * can bail out completely (since as n increases in
|
|
|
|
+ * the next iteration, there's no way that m can
|
|
|
|
+ * increase beyond the current m)
|
|
|
|
+ */
|
|
|
|
+ if (m > scaled_max_m)
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ r = _dpll_test_mult(&m, n, &new_rate, target_rate,
|
|
|
|
+ ref_rate);
|
|
|
|
+
|
|
|
|
+ /* m can't be set low enough for this n - try with a larger n */
|
|
|
|
+ if (r == DPLL_MULT_UNDERFLOW)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ pr_debug("clock: %s: m = %d: n = %d: new_rate = %ld\n",
|
|
|
|
+ clk_name, m, n, new_rate);
|
|
|
|
+
|
|
|
|
+ if (target_rate == new_rate) {
|
|
|
|
+ dd->last_rounded_m = m;
|
|
|
|
+ dd->last_rounded_n = n;
|
|
|
|
+ dd->last_rounded_rate = target_rate;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (target_rate != new_rate) {
|
|
|
|
+ pr_debug("clock: %s: cannot round to rate %ld\n",
|
|
|
|
+ clk_name, target_rate);
|
|
|
|
+ return ~0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return target_rate;
|
|
|
|
+}
|
|
|
|
+
|