#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/clk.h>
-#include <linux/bitops.h>
#include <linux/io.h>
+#include <linux/bitops.h>
#include <mach/clock.h>
#include <mach/clockdomain.h>
#define DPLL_MIN_DIVIDER 1
/* Possible error results from _dpll_test_mult */
-#define DPLL_MULT_UNDERFLOW (1 << 0)
+#define DPLL_MULT_UNDERFLOW -1
/*
* Scale factor to mitigate roundoff errors in DPLL rate rounding.
unsigned long target_rate,
unsigned long parent_rate)
{
- int flags = 0, carry = 0;
+ int r = 0, carry = 0;
/* Unscale m and round if necessary */
if (*m % DPLL_SCALE_FACTOR >= DPLL_ROUNDING_VAL)
if (*m < DPLL_MIN_MULTIPLIER) {
*m = DPLL_MIN_MULTIPLIER;
*new_rate = 0;
- flags = DPLL_MULT_UNDERFLOW;
+ r = DPLL_MULT_UNDERFLOW;
}
if (*new_rate == 0)
*new_rate = _dpll_compute_new_rate(parent_rate, *m, n);
- return flags;
+ return r;
}
/**
int m, n, r, e, scaled_max_m;
unsigned long scaled_rt_rp, new_rate;
int min_e = -1, min_e_m = -1, min_e_n = -1;
+ struct dpll_data *dd;
if (!clk || !clk->dpll_data)
return ~0;
+ dd = clk->dpll_data;
+
pr_debug("clock: starting DPLL round_rate for clock %s, target rate "
"%ld\n", clk->name, target_rate);
scaled_rt_rp = target_rate / (clk->parent->rate / DPLL_SCALE_FACTOR);
- scaled_max_m = clk->dpll_data->max_multiplier * DPLL_SCALE_FACTOR;
+ scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR;
- clk->dpll_data->last_rounded_rate = 0;
+ dd->last_rounded_rate = 0;
- for (n = clk->dpll_data->max_divider; n >= DPLL_MIN_DIVIDER; n--) {
+ for (n = DPLL_MIN_DIVIDER; n <= dd->max_divider; n++) {
/* Compute the scaled DPLL multiplier, based on the divider */
m = scaled_rt_rp * n;
/*
- * Since we're counting n down, a m overflow means we can
- * can immediately skip to the next 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)
- continue;
+ break;
r = _dpll_test_mult(&m, n, &new_rate, target_rate,
clk->parent->rate);
+ /* m can't be set low enough for this n - try with a larger n */
+ if (r == DPLL_MULT_UNDERFLOW)
+ continue;
+
e = target_rate - new_rate;
pr_debug("clock: n = %d: m = %d: rate error is %d "
"(new_rate = %ld)\n", n, m, e, new_rate);
if (min_e == -1 ||
- min_e >= (int)(abs(e) - clk->dpll_data->rate_tolerance)) {
+ min_e >= (int)(abs(e) - dd->rate_tolerance)) {
min_e = e;
min_e_m = m;
min_e_n = n;
pr_debug("clock: found new least error %d\n", min_e);
- }
- /*
- * Since we're counting n down, a m underflow means we
- * can bail out completely (since as n decreases in
- * the next iteration, there's no way that m can
- * increase beyond the current m)
- */
- if (r & DPLL_MULT_UNDERFLOW)
- break;
+ /* We found good settings -- bail out now */
+ if (min_e <= clk->dpll_data->rate_tolerance)
+ break;
+ }
}
if (min_e < 0) {
return ~0;
}
- clk->dpll_data->last_rounded_m = min_e_m;
- clk->dpll_data->last_rounded_n = min_e_n;
- clk->dpll_data->last_rounded_rate =
- _dpll_compute_new_rate(clk->parent->rate, min_e_m, min_e_n);
+ dd->last_rounded_m = min_e_m;
+ dd->last_rounded_n = min_e_n;
+ dd->last_rounded_rate = _dpll_compute_new_rate(clk->parent->rate,
+ min_e_m, min_e_n);
pr_debug("clock: final least error: e = %d, m = %d, n = %d\n",
min_e, min_e_m, min_e_n);
pr_debug("clock: final rate: %ld (target rate: %ld)\n",
- clk->dpll_data->last_rounded_rate, target_rate);
+ dd->last_rounded_rate, target_rate);
- return clk->dpll_data->last_rounded_rate;
+ return dd->last_rounded_rate;
}
/*-------------------------------------------------------------------------