示例#1
0
/**
 * omap2_dpll_round_rate - round a target rate for an OMAP DPLL
 * @clk: struct clk * for a DPLL
 * @target_rate: desired DPLL clock rate
 *
 * Given a DPLL and a desired target rate, round the target rate to a
 * possible, programmable rate for this DPLL.  Attempts to select the
 * minimum possible n.  Stores the computed (m, n) in the DPLL's
 * 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 *clk, unsigned long target_rate)
{
	int m, n, r, scaled_max_m;
	unsigned long scaled_rt_rp;
	unsigned long new_rate = 0;
	struct dpll_data *dd;

	if (!clk || !clk->dpll_data)
		return ~0;

	dd = clk->dpll_data;

	pr_debug("clock: %s: starting DPLL round_rate, target rate %ld\n",
		 clk->name, target_rate);

	scaled_rt_rp = DIV_ROUND_CLOSEST(target_rate,
			dd->clk_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++) {

		if (cpu_is_omap34xx()) {
			/* 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,
				    dd->clk_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;
}
示例#2
0
long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)
{
	int m, n, r, scaled_max_m;
	unsigned long scaled_rt_rp;
	unsigned long new_rate = 0;
	struct dpll_data *dd;

	if (!clk || !clk->dpll_data)
		return ~0;

	dd = clk->dpll_data;

	pr_debug("clock: %s: starting DPLL round_rate, target rate %ld\n",
		 clk->name, target_rate);

	scaled_rt_rp = target_rate / (dd->clk_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++) {

		
		r = _dpll_test_fint(clk, n);
		if (r == DPLL_FINT_UNDERFLOW)
			break;
		else if (r == DPLL_FINT_INVALID)
			continue;

		
		m = scaled_rt_rp * n;

		if (m > scaled_max_m)
			break;

		r = _dpll_test_mult(&m, n, &new_rate, target_rate,
				    dd->clk_ref->rate);

		
		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;
}
示例#3
0
/**
 * omap2_dpll_round_rate - round a target rate for an OMAP DPLL
 * @clk: struct clk * for a DPLL
 * @target_rate: desired DPLL clock rate
 *
 * Given a DPLL, a desired target rate, and a rate tolerance, round
 * the target rate to a possible, programmable rate for this DPLL.
 * Rate tolerance is assumed to be set by the caller before this
 * function is called.  Attempts to select the minimum possible n
 * within the tolerance to reduce power consumption.  Stores the
 * computed (m, n) in the DPLL's dpll_data structure so set_rate()
 * will not need to call this (expensive) function again.  Returns ~0
 * if the target rate cannot be rounded, either because the rate is
 * too low or because the rate tolerance is set too tightly; or the
 * rounded rate upon success.
 */
long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)
{
	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 / (dd->clk_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,
				    dd->clk_ref->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) - 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);

			/* We found good settings -- bail out now */
			if (min_e <= dd->rate_tolerance)
				break;
		}
	}

	if (min_e < 0) {
		pr_debug("clock: error: target rate or tolerance too low\n");
		return ~0;
	}

	dd->last_rounded_m = min_e_m;
	dd->last_rounded_n = min_e_n;
	dd->last_rounded_rate = _dpll_compute_new_rate(dd->clk_ref->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",
		 dd->last_rounded_rate, target_rate);

	return dd->last_rounded_rate;
}
示例#4
0
文件: clkt_dpll.c 项目: belucha/linux
/**
 * omap2_dpll_round_rate - round a target rate for an OMAP DPLL
 * @clk: struct clk * for a DPLL
 * @target_rate: desired DPLL clock rate
 *
 * Given a DPLL and a desired target rate, round the target rate to a
 * possible, programmable rate for this DPLL.  Attempts to select the
 * minimum possible n.  Stores the computed (m, n) in the DPLL's
 * 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;
	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)
		return ~0;

	dd = clk->dpll_data;

	if (dd->max_rate && target_rate > dd->max_rate)
		target_rate = dd->max_rate;

	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 %lu\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;

		/* 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 (delta == 0)
			break;
	}

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

	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;
}
示例#5
0
long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)
{
    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 / (dd->clk_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++) {


        r = _dpll_test_fint(clk, n);
        if (r == DPLL_FINT_UNDERFLOW)
            break;
        else if (r == DPLL_FINT_INVALID)
            continue;


        m = scaled_rt_rp * n;


        if (m > scaled_max_m)
            break;

        r = _dpll_test_mult(&m, n, &new_rate, target_rate,
                            dd->clk_ref->rate);


        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) - 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);


            if (min_e <= dd->rate_tolerance)
                break;
        }
    }

    if (min_e < 0) {
        pr_debug("clock: error: target rate or tolerance too low\n");
        return ~0;
    }

    dd->last_rounded_m = min_e_m;
    dd->last_rounded_n = min_e_n;
    dd->last_rounded_rate = _dpll_compute_new_rate(dd->clk_ref->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",
             dd->last_rounded_rate, target_rate);

    return dd->last_rounded_rate;
}
示例#6
0
/**
 * omap2_dpll_round_rate - round a target rate for an OMAP DPLL
 * @clk: struct clk * for a DPLL
 * @target_rate: desired DPLL clock rate
 *
 * Given a DPLL and a desired target rate, round the target rate to a
 * possible, programmable rate for this DPLL.  Attempts to select the
 * minimum possible n.  Stores the computed (m, n) in the DPLL's
 * 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 *clk, unsigned long target_rate)
{
	int m, n, r, scaled_max_m;
	unsigned long scaled_rt_rp;
	unsigned long new_rate = 0;
	struct dpll_data *dd;
	unsigned long bestrate = 0, diff, bestdiff = ULONG_MAX;
	int bestm = 0, bestn = 0;
	struct dpll_rate_list *rs, *rate_cache;

	if (!clk || !clk->dpll_data)
		return ~0;

	dd = clk->dpll_data;

	rate_cache = dd->rate_cache;
	for (rs = rate_cache; rs; rs = rs->next)
		if (rs->target_rate == target_rate) {
			dd->last_rounded_m = rs->m;
			dd->last_rounded_n = rs->n;
			dd->last_rounded_rate = rs->actual_rate;
			return rs->actual_rate;
		}

	pr_debug("clock: %s: starting DPLL round_rate, target rate %ld\n",
		 clk->name, target_rate);

	scaled_rt_rp = target_rate / (dd->clk_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,
				    dd->clk_ref->rate);

		/* m can't be set low enough for this n - try with a larger n */
		if (r == DPLL_MULT_UNDERFLOW)
			continue;

#ifdef DEBUG
		pr_err("clock: target=%ld %s: m = %d: n = %d: new_rate = %ld\n",
			 target_rate, clk->name, m, n, new_rate);
#endif

		if (target_rate > new_rate)
			diff = target_rate - new_rate;
		else
			diff = new_rate - target_rate;
		if (diff < bestdiff) {
			bestm = m;
			bestn = n;
			bestrate = new_rate;
			bestdiff = diff;
		}
		if (new_rate == target_rate)
			break;
	}
	/*
	 * The following if verifies that the new frequency is within 0.01% of
	 * the target frequency.
	 */
	if (bestdiff < (ULONG_MAX / 10000) &&
				      ((bestdiff * 10000) / target_rate) < 1) {
		dd->last_rounded_m = bestm;
		dd->last_rounded_n = bestn;
		dd->last_rounded_rate = bestrate;
		rs = kzalloc(sizeof (struct dpll_rate_list), GFP_ATOMIC);
		if (rs) {
			rs->m = bestm;
			rs->n = bestn;
			rs->target_rate = target_rate;
			rs->actual_rate = bestrate;
			if (rate_cache == dd->rate_cache) {
				rs->next = dd->rate_cache;
				dd->rate_cache = rs;
			} else
				kzfree(rs);
		}
		return bestrate;
	} else
		return 0;
}