Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0a263444 authored by Paul Walmsley's avatar Paul Walmsley
Browse files

ARM: OMAP2+: clock: allow omap2_dpll_round_rate() to round to next-lowest rate



Change the behavior of omap2_dpll_round_rate() to round to either the
exact rate requested, or the next lowest rate that the clock is able to
provide.

This is not an ideal fix, but is intended to provide a relatively safe
way for drivers to set PLL rates, until a better solution can be
implemented.

For the time being, omap3_noncore_dpll_set_rate() is still allowed to
set its rate to something other than what the caller requested; but will
warn when this occurs.

Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>
Cc: Mike Turquette <mturquette@linaro.org>
Signed-off-by: default avatarPaul Walmsley <paul@pwsan.com>
parent a497c3ba
Loading
Loading
Loading
Loading
+21 −7
Original line number Diff line number Diff line
@@ -293,10 +293,13 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
{
	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
	int m, n, r, scaled_max_m;
	int min_delta_m = INT_MAX, min_delta_n = INT_MAX;
	unsigned long scaled_rt_rp;
	unsigned long new_rate = 0;
	struct dpll_data *dd;
	unsigned long ref_rate;
	long delta;
	long prev_min_delta = LONG_MAX;
	const char *clk_name;

	if (!clk || !clk->dpll_data)
@@ -342,23 +345,34 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
		if (r == DPLL_MULT_UNDERFLOW)
			continue;

		/* skip rates above our target rate */
		delta = target_rate - new_rate;
		if (delta < 0)
			continue;

		if (delta < prev_min_delta) {
			prev_min_delta = delta;
			min_delta_m = m;
			min_delta_n = n;
		}

		pr_debug("clock: %s: m = %d: n = %d: new_rate = %lu\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;
		if (delta == 0)
			break;
	}
	}

	if (target_rate != new_rate) {
	if (prev_min_delta == LONG_MAX) {
		pr_debug("clock: %s: cannot round to rate %lu\n",
			 clk_name, target_rate);
		return ~0;
	}

	return target_rate;
	dd->last_rounded_m = min_delta_m;
	dd->last_rounded_n = min_delta_n;
	dd->last_rounded_rate = target_rate - prev_min_delta;

	return dd->last_rounded_rate;
}
+11 −2
Original line number Diff line number Diff line
@@ -478,6 +478,7 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
{
	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
	struct clk *new_parent = NULL;
	unsigned long rrate;
	u16 freqsel = 0;
	struct dpll_data *dd;
	int ret;
@@ -505,8 +506,16 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
		__clk_prepare(dd->clk_ref);
		clk_enable(dd->clk_ref);

		if (dd->last_rounded_rate != rate)
			rate = __clk_round_rate(hw->clk, rate);
		/* XXX this check is probably pointless in the CCF context */
		if (dd->last_rounded_rate != rate) {
			rrate = __clk_round_rate(hw->clk, rate);
			if (rrate != rate) {
				pr_warn("%s: %s: final rate %lu does not match desired rate %lu\n",
					__func__, __clk_get_name(hw->clk),
					rrate, rate);
				rate = rrate;
			}
		}

		if (dd->last_rounded_rate == 0)
			return -EINVAL;