Ejemplo n.º 1
0
Archivo: gate.c Proyecto: 168519/linux
/**
 * omap36xx_gate_clk_enable_with_hsdiv_restore - enable clocks suffering
 *         from HSDivider PWRDN problem Implements Errata ID: i556.
 * @clk: DPLL output struct clk
 *
 * 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck,
 * dpll4_m5_ck & dpll4_m6_ck dividers gets loaded with reset
 * valueafter their respective PWRDN bits are set.  Any dummy write
 * (Any other value different from the Read value) to the
 * corresponding CM_CLKSEL register will refresh the dividers.
 */
static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *clk)
{
	struct clk_divider *parent;
	struct clk_hw *parent_hw;
	u32 dummy_v, orig_v;
	int ret;

	/* Clear PWRDN bit of HSDIVIDER */
	ret = omap2_dflt_clk_enable(clk);

	/* Parent is the x2 node, get parent of parent for the m2 div */
	parent_hw = __clk_get_hw(__clk_get_parent(__clk_get_parent(clk->clk)));
	parent = to_clk_divider(parent_hw);

	/* Restore the dividers */
	if (!ret) {
		orig_v = ti_clk_ll_ops->clk_readl(parent->reg);
		dummy_v = orig_v;

		/* Write any other value different from the Read value */
		dummy_v ^= (1 << parent->shift);
		ti_clk_ll_ops->clk_writel(dummy_v, parent->reg);

		/* Write the original divider */
		ti_clk_ll_ops->clk_writel(orig_v, parent->reg);
	}

	return ret;
}
Ejemplo n.º 2
0
static int clk_ddr_set_rate(struct clk_hw *hw, unsigned long rate,
		unsigned long parent_rate)
{
	struct clk *parent = __clk_get_parent(hw->clk);
	struct clk *grand_p = __clk_get_parent(parent);


	/* Do nothing before ddr init */
	if (!ddr_change_freq)
		return 0;

	if (IS_ERR_OR_NULL(parent) || IS_ERR_OR_NULL(grand_p)) {
		clk_err("fail to get parent or grand_parent!\n");
		return -EINVAL;
	}

	clk_debug("%s: will set rate = %lu\n", __func__, rate);

	/* Func provided by ddr driver */
	ddr_change_freq(rate/MHZ);

	parent->rate = parent->ops->recalc_rate(parent->hw,
			__clk_get_rate(grand_p));

	return 0;
}
Ejemplo n.º 3
0
static int clkout_clksel_set_rate(struct clk_hw *hw, unsigned long rate,
				unsigned long parent_rate)
{
	struct clk_hw_clkout *clkout_clk = to_clk_hw_clkout(hw);
	struct clk_hw_omap *omap_clk = to_clk_hw_omap(hw);
	struct clkout_match *m = &clkout_clk->match;
	struct clk *clk = hw->clk;
	int ret;
	u32 v;

	ret = clkout_find_match(hw, rate, m);
	if (ret != 0)
		return ret;

	/* have to be exact now */
	if (rate != m->best_rate) {
		pr_err("%s: Failed to find exact rate %lu (was %lu)\n",
				__func__, rate, m->best_rate);
		return -EINVAL;
	}

	/* switch parent */
	if (m->best_clks->parent != __clk_get_parent(clk)) {
		__clk_set_parent(clk, m->best_clks->parent);
		__clk_reparent(clk, m->best_clks->parent);
		parent_rate = __clk_get_rate(__clk_get_parent(clk));
	}

	/* we need to write the new value */
	if (omap_clk->clksel_reg != clkout_clk->div_reg) {
		v = __raw_readl(omap_clk->clksel_reg);
		v &= ~omap_clk->clksel_mask;
		v |= m->best_clkr->val << __ffs(omap_clk->clksel_mask);
		__raw_writel(v, omap_clk->clksel_reg);
		v = __raw_readl(omap_clk->clksel_reg);	/* OCP barrier */

		v = __raw_readl(clkout_clk->div_reg);
		v &= ~clkout_clk->div_mask;
		v |= m->best_clkd->val << __ffs(clkout_clk->div_mask);
		__raw_writel(v, clkout_clk->div_reg);
		v = __raw_readl(clkout_clk->div_reg);	/* OCP barrier */
	} else {
		v = __raw_readl(omap_clk->clksel_reg);
		v &= ~(omap_clk->clksel_mask | clkout_clk->div_mask);
		v |= (m->best_clkr->val << __ffs(omap_clk->clksel_mask)) |
		     (m->best_clkd->val << __ffs(clkout_clk->div_mask));
		__raw_writel(v, omap_clk->clksel_reg);
		v = __raw_readl(omap_clk->clksel_reg);	/* OCP barrier */
	}

	return ret;
}
Ejemplo n.º 4
0
/**
 * omap36xx_pwrdn_clk_enable_with_hsdiv_restore - enable clocks suffering
 *         from HSDivider PWRDN problem Implements Errata ID: i556.
 * @clk: DPLL output struct clk
 *
 * 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck,
 * dpll4_m5_ck & dpll4_m6_ck dividers gets loaded with reset
 * valueafter their respective PWRDN bits are set.  Any dummy write
 * (Any other value different from the Read value) to the
 * corresponding CM_CLKSEL register will refresh the dividers.
 */
int omap36xx_pwrdn_clk_enable_with_hsdiv_restore(struct clk_hw *clk)
{
	struct clk_divider *parent;
	struct clk_hw *parent_hw;
	u32 dummy_v, orig_v;
	struct clk_hw_omap *omap_clk = to_clk_hw_omap(clk);
	int ret;

	/* Clear PWRDN bit of HSDIVIDER */
	ret = omap2_dflt_clk_enable(clk);

	parent_hw = __clk_get_hw(__clk_get_parent(clk->clk));
	parent = to_clk_divider(parent_hw);

	/* Restore the dividers */
	if (!ret) {
		orig_v = omap2_clk_readl(omap_clk, parent->reg);
		dummy_v = orig_v;

		/* Write any other value different from the Read value */
		dummy_v ^= (1 << parent->shift);
		omap2_clk_writel(dummy_v, omap_clk, parent->reg);

		/* Write the original divider */
		omap2_clk_writel(orig_v, omap_clk, parent->reg);
	}

	return ret;
}
Ejemplo n.º 5
0
/*
 * FIXME - setting the parent every time .prepare is invoked is inefficient.
 * This is better handled by a dedicated clock tree configuration mechanism at
 * init-time.  Revisit this later when such a mechanism exists
 */
static int clk_sp810_timerclken_prepare(struct clk_hw *hw)
{
	struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw);
	struct clk_sp810 *sp810 = timerclken->sp810;
	struct clk *old_parent = __clk_get_parent(hw->clk);
	struct clk *new_parent;

	if (!sp810->refclk)
		sp810->refclk = of_clk_get(sp810->node, sp810->refclk_index);

	if (!sp810->timclk)
		sp810->timclk = of_clk_get(sp810->node, sp810->timclk_index);

	if (WARN_ON(IS_ERR(sp810->refclk) || IS_ERR(sp810->timclk)))
		return -ENOENT;

	/* Select fastest parent */
	if (clk_get_rate(sp810->refclk) > clk_get_rate(sp810->timclk))
		new_parent = sp810->refclk;
	else
		new_parent = sp810->timclk;

	/* Switch the parent if necessary */
	if (old_parent != new_parent) {
		clk_prepare(new_parent);
		clk_set_parent(hw->clk, new_parent);
		clk_unprepare(old_parent);
	}

	return 0;
}
Ejemplo n.º 6
0
/**
 * _clksel_to_divisor() - turn clksel field value into integer divider
 * @clk: OMAP struct clk to use
 * @field_val: register field value to find
 *
 * Given a struct clk of a rate-selectable clksel clock, and a register field
 * value to search for, find the corresponding clock divisor.  The register
 * field value should be pre-masked and shifted down so the LSB is at bit 0
 * before calling.  Returns 0 on error or returns the actual integer divisor
 * upon success.
 */
static u32 _clksel_to_divisor(struct clk *clk, u32 field_val)
{
	const struct clksel *clks;
	const struct clksel_rate *clkr;
	struct clk *parent;

	parent = __clk_get_parent(clk);
	clks = _get_clksel_by_parent(clk, parent);
	if (!clks)
		return 0;

	for (clkr = clks->rates; clkr->div; clkr++) {
		if (!(clkr->flags & cpu_mask))
			continue;

		if (clkr->val == field_val)
			break;
	}

	if (!clkr->div) {
		/* This indicates a data error */
		WARN(1, "clock: %s: could not find fieldval %d for parent %s\n",
		     __clk_get_name(clk), field_val, __clk_get_name(parent));
		return 0;
	}

	return clkr->div;
}
Ejemplo n.º 7
0
/**
 * _divisor_to_clksel() - turn clksel integer divisor into a field value
 * @clk: OMAP struct clk to use
 * @div: integer divisor to search for
 *
 * Given a struct clk of a rate-selectable clksel clock, and a clock
 * divisor, find the corresponding register field value.  Returns the
 * register field value _before_ left-shifting (i.e., LSB is at bit
 * 0); or returns 0xFFFFFFFF (~0) upon error.
 */
static u32 _divisor_to_clksel(struct clk *clk, u32 div)
{
	const struct clksel *clks;
	const struct clksel_rate *clkr;
	struct clk *parent;

	/* should never happen */
	WARN_ON(div == 0);

	parent = __clk_get_parent(clk);
	clks = _get_clksel_by_parent(clk, parent);
	if (!clks)
		return ~0;

	for (clkr = clks->rates; clkr->div; clkr++) {
		if (!(clkr->flags & cpu_mask))
			continue;

		if (clkr->div == div)
			break;
	}

	if (!clkr->div) {
		pr_err("clock: %s: could not find divisor %d for parent %s\n",
		       __clk_get_name(clk), div, __clk_get_name(parent));
		return ~0;
	}

	return clkr->val;
}
Ejemplo n.º 8
0
/**
 * omap36xx_pwrdn_clk_enable_with_hsdiv_restore - enable clocks suffering
 *         from HSDivider PWRDN problem Implements Errata ID: i556.
 * @clk: DPLL output struct clk
 *
 * 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck,
 * dpll4_m5_ck & dpll4_m6_ck dividers gets loaded with reset
 * valueafter their respective PWRDN bits are set.  Any dummy write
 * (Any other value different from the Read value) to the
 * corresponding CM_CLKSEL register will refresh the dividers.
 */
int omap36xx_pwrdn_clk_enable_with_hsdiv_restore(struct clk_hw *clk)
{
	struct clk_hw_omap *parent;
	struct clk_hw *parent_hw;
	u32 dummy_v, orig_v, clksel_shift;
	int ret;

	/* Clear PWRDN bit of HSDIVIDER */
	ret = omap2_dflt_clk_enable(clk);

	parent_hw = __clk_get_hw(__clk_get_parent(clk->clk));
	parent = to_clk_hw_omap(parent_hw);

	/* Restore the dividers */
	if (!ret) {
		clksel_shift = __ffs(parent->clksel_mask);
		orig_v = __raw_readl(parent->clksel_reg);
		dummy_v = orig_v;

		/* Write any other value different from the Read value */
		dummy_v ^= (1 << clksel_shift);
		__raw_writel(dummy_v, parent->clksel_reg);

		/* Write the original divider */
		__raw_writel(orig_v, parent->clksel_reg);
	}

	return ret;
}
Ejemplo n.º 9
0
Archivo: dpll3xxx.c Proyecto: 01org/prd
/**
 * omap3_noncore_dpll_set_rate - set rate for a DPLL clock
 * @hw: pointer to the clock to set parent for
 * @rate: target rate for the clock
 * @parent_rate: rate of the parent clock
 *
 * Sets rate for a DPLL clock. First checks if the clock parent is
 * reference clock (in bypass mode, the rate of the clock can't be
 * changed) and proceeds with the rate change operation. Returns 0
 * with success, negative error value otherwise.
 */
int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
				unsigned long parent_rate)
{
	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
	struct dpll_data *dd;
	u16 freqsel = 0;
	int ret;

	if (!hw || !rate)
		return -EINVAL;

	dd = clk->dpll_data;
	if (!dd)
		return -EINVAL;

	if (__clk_get_hw(__clk_get_parent(hw->clk)) !=
	    __clk_get_hw(dd->clk_ref))
		return -EINVAL;

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

	/* Freqsel is available only on OMAP343X devices */
	if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) {
		freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n);
		WARN_ON(!freqsel);
	}

	pr_debug("%s: %s: set rate: locking rate to %lu.\n", __func__,
		 __clk_get_name(hw->clk), rate);

	ret = omap3_noncore_dpll_program(clk, freqsel);

	return ret;
}
Ejemplo n.º 10
0
/**
 * omap2_clksel_set_parent() - change a clock's parent clock
 * @clk: struct clk * of the child clock
 * @new_parent: struct clk * of the new parent clock
 *
 * This function is intended to be called only by the clock framework.
 * Change the parent clock of clock @clk to @new_parent.  This is
 * intended to be used while @clk is disabled.  This function does not
 * currently check the usecount of the clock, so if multiple drivers
 * are using the clock, and the parent is changed, they will all be
 * affected without any notification.  Returns -EINVAL upon error, or
 * 0 upon success.
 */
int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent)
{
	u32 field_val = 0;
	u32 parent_div;

	if (!clk->clksel || !clk->clksel_mask)
		return -EINVAL;

	parent_div = _get_div_and_fieldval(new_parent, clk, &field_val);
	if (!parent_div)
		return -EINVAL;

	_write_clksel_reg(clk, field_val);

	clk_reparent(clk, new_parent);

	/* CLKSEL clocks follow their parents' rates, divided by a divisor */
	clk->rate = __clk_get_rate(new_parent);

	if (parent_div > 0)
		__clk_get_rate(clk) /= parent_div;

	pr_debug("clock: %s: set parent to %s (new rate %ld)\n",
		 __clk_get_name(clk),
		 __clk_get_name(__clk_get_parent(clk)),
		 __clk_get_rate(clk));

	return 0;
}
Ejemplo n.º 11
0
/**
 * omap3_noncore_dpll_enable - instruct a DPLL to enter bypass or lock mode
 * @clk: pointer to a DPLL struct clk
 *
 * Instructs a non-CORE DPLL to enable, e.g., to enter bypass or lock.
 * The choice of modes depends on the DPLL's programmed rate: if it is
 * the same as the DPLL's parent clock, it will enter bypass;
 * otherwise, it will enter lock.  This code will wait for the DPLL to
 * indicate readiness before returning, unless the DPLL takes too long
 * to enter the target state.  Intended to be used as the struct clk's
 * enable function.  If DPLL3 was passed in, or the DPLL does not
 * support low-power stop, or if the DPLL took too long to enter
 * bypass or lock, return -EINVAL; otherwise, return 0.
 */
int omap3_noncore_dpll_enable(struct clk_hw *hw)
{
	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
	int r;
	struct dpll_data *dd;
	struct clk *parent;

	dd = clk->dpll_data;
	if (!dd)
		return -EINVAL;

	if (clk->clkdm) {
		r = clkdm_clk_enable(clk->clkdm, hw->clk);
		if (r) {
			WARN(1,
			     "%s: could not enable %s's clockdomain %s: %d\n",
			     __func__, __clk_get_name(hw->clk),
			     clk->clkdm->name, r);
			return r;
		}
	}

	parent = __clk_get_parent(hw->clk);

	if (__clk_get_rate(hw->clk) == __clk_get_rate(dd->clk_bypass)) {
		WARN_ON(parent != dd->clk_bypass);
		r = _omap3_noncore_dpll_bypass(clk);
	} else {
		WARN_ON(parent != dd->clk_ref);
		r = _omap3_noncore_dpll_lock(clk);
	}

	return r;
}
Ejemplo n.º 12
0
static long div_round_rate(struct clk_hw *hw, unsigned long rate,
			   unsigned long *parent_rate)
{
	struct div_clk *d = to_div_clk(hw);
	bool set_parent = __clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT;

	return __div_round_rate(&d->data, rate, __clk_get_parent(hw->clk),
				NULL, parent_rate, set_parent);
}
Ejemplo n.º 13
0
/**
 * omap2_clksel_round_rate_div() - find divisor for the given clock and rate
 * @clk: OMAP struct clk to use
 * @target_rate: desired clock rate
 * @new_div: ptr to where we should store the divisor
 *
 * Finds 'best' divider value in an array based on the source and target
 * rates.  The divider array must be sorted with smallest divider first.
 * This function is also used by the DPLL3 M2 divider code.
 *
 * Returns the rounded clock rate or returns 0xffffffff on error.
 */
u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
				u32 *new_div)
{
	unsigned long test_rate;
	const struct clksel *clks;
	const struct clksel_rate *clkr;
	u32 last_div = 0;
	struct clk *parent;
	unsigned long parent_rate;
	const char *clk_name;

	parent = __clk_get_parent(clk);
	parent_rate = __clk_get_rate(parent);
	clk_name = __clk_get_name(clk);

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

	pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n",
		 clk_name, target_rate);

	*new_div = 1;

	clks = _get_clksel_by_parent(clk, parent);
	if (!clks)
		return ~0;

	for (clkr = clks->rates; clkr->div; clkr++) {
		if (!(clkr->flags & cpu_mask))
			continue;

		/* Sanity check */
		if (clkr->div <= last_div)
			pr_err("clock: %s: clksel_rate table not sorted\n",
			       clk_name);

		last_div = clkr->div;

		test_rate = parent_rate / clkr->div;

		if (test_rate <= target_rate)
			break; /* found it */
	}

	if (!clkr->div) {
		pr_err("clock: %s: could not find divisor for target rate %ld for parent %s\n",
		       clk_name, target_rate, __clk_get_name(parent));
		return ~0;
	}

	*new_div = clkr->div;

	pr_debug("clock: new_div = %d, new_rate = %ld\n", *new_div,
		 (parent_rate / clkr->div));

	return parent_rate / clkr->div;
}
Ejemplo n.º 14
0
static int clk_core_set_rate(struct clk_hw *hw, unsigned long rate,
		unsigned long parent_rate)
{
	struct clk *parent = __clk_get_parent(hw->clk);
	struct clk *grand_p = __clk_get_parent(parent);
	int ret;

	if (IS_ERR_OR_NULL(parent) || IS_ERR_OR_NULL(grand_p)) {
		clk_err("fail to get parent or grand_parent!\n");
		return -EINVAL;
	}

	ret = parent->ops->set_rate(parent->hw, rate, __clk_get_rate(grand_p));
	parent->rate = parent->ops->recalc_rate(parent->hw,
			__clk_get_rate(grand_p));

	return ret;
}
Ejemplo n.º 15
0
static int clk_3288_i2s_set_rate(struct clk_hw *hw, unsigned long rate,
		unsigned long parent_rate)
{
	struct clk *parent = __clk_get_parent(hw->clk);
	struct clk *grand_p = __clk_get_parent(parent);


	if (IS_ERR_OR_NULL(parent) || IS_ERR_OR_NULL(grand_p)) {
		return 0;
	}

	if (parent->ops->set_rate) {
		parent->ops->set_rate(parent->hw, rate/2, __clk_get_rate(grand_p));
		parent->ops->set_rate(parent->hw, rate, __clk_get_rate(grand_p));
	}

	return 0;
}
Ejemplo n.º 16
0
long omap3_clkoutx2_round_rate(struct clk_hw *hw, unsigned long rate,
		unsigned long *prate)
{
	const struct dpll_data *dd;
	u32 v;
	struct clk_hw_omap *pclk = NULL;

	if (!*prate)
		return 0;

	pclk = omap3_find_clkoutx2_dpll(hw);

	if (!pclk)
		return 0;

	dd = pclk->dpll_data;

	/* TYPE J does not have a clkoutx2 */
	if (dd->flags & DPLL_J_TYPE) {
		*prate = __clk_round_rate(__clk_get_parent(pclk->hw.clk), rate);
		return *prate;
	}

	WARN_ON(!dd->enable_mask);

	v = omap2_clk_readl(pclk, dd->control_reg) & dd->enable_mask;
	v >>= __ffs(dd->enable_mask);

	/* If in bypass, the rate is fixed to the bypass rate*/
	if (v != OMAP3XXX_EN_DPLL_LOCKED)
		return *prate;

	if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
		unsigned long best_parent;

		best_parent = (rate / 2);
		*prate = __clk_round_rate(__clk_get_parent(hw->clk),
				best_parent);
	}

	return *prate * 2;
}
Ejemplo n.º 17
0
/**
 * _lookup_dco - Lookup DCO used by j-type DPLL
 * @clk: pointer to a DPLL struct clk
 * @dco: digital control oscillator selector
 * @m: DPLL multiplier to set
 * @n: DPLL divider to set
 *
 * See 36xx TRM section 3.5.3.3.3.2 "Type B DPLL (Low-Jitter)"
 *
 * XXX This code is not needed for 3430/AM35xx; can it be optimized
 * out in non-multi-OMAP builds for those chips?
 */
static void _lookup_dco(struct clk_hw_omap *clk, u8 *dco, u16 m, u8 n)
{
	unsigned long fint, clkinp; /* watch out for overflow */

	clkinp = __clk_get_rate(__clk_get_parent(clk->hw.clk));
	fint = (clkinp / n) * m;

	if (fint < 1000000000)
		*dco = 2;
	else
		*dco = 4;
}
Ejemplo n.º 18
0
static long clk_mux_with_evendiv_determine_rate(struct clk_hw *div_hw, unsigned long rate,
		unsigned long *best_parent_rate,
		struct clk **best_parent_p)
{
	struct clk *clk = div_hw->clk, *parent = NULL, *best_parent = NULL;
	int i, num_parents;
	unsigned long parent_rate = 0, best_prate = 0, best = 0, now = 0;


	parent = __clk_get_parent(clk);
	if(!parent){
		best = __clk_get_rate(clk);
		goto out;
	}

	/* if NO_REPARENT flag set, pass through to current parent */
	if (clk->flags & CLK_SET_RATE_NO_REPARENT) {
		best_prate = __clk_get_rate(parent);
		best = clk_div_round_rate_even(div_hw, rate, &best_prate);
		goto out;
	}

	/* find the parent that can provide the fastest rate <= rate */
	num_parents = clk->num_parents;
	for (i = 0; i < num_parents; i++) {
		parent = clk_get_parent_by_index(clk, i);
		if (!parent)
			continue;

		parent_rate = __clk_get_rate(parent);
		now = clk_div_round_rate_even(div_hw, rate, &parent_rate);

		if (now <= rate && now > best) {
			best_parent = parent;
			best_prate = parent_rate;
			best = now;
		}
	}

out:
	if(best_prate)
		*best_parent_rate = best_prate;

	if (best_parent)
		*best_parent_p = best_parent;

	clk_debug("clk name = %s, determine rate = %lu, best = %lu\n"
			"\tbest_parent name = %s, best_prate = %lu\n",
			clk->name, rate, best,
			__clk_get_name(*best_parent_p), *best_parent_rate);

	return best;
}
Ejemplo n.º 19
0
static long clk_core_determine_rate(struct clk_hw *hw, unsigned long rate,
		unsigned long *best_parent_rate,
		struct clk **best_parent_p)
{
	struct clk *parent = __clk_get_parent(hw->clk);

	if (IS_ERR_OR_NULL(parent)) {
		clk_err("fail to get parent!\n");
		return 0;
	}

	return clk_round_rate(parent, rate);
}
Ejemplo n.º 20
0
int s5p_spdif_set_rate(struct clk *clk, unsigned long rate)
{
    struct clk *pclk;
    int ret;

    pclk = __clk_get_parent(clk);
    if (IS_ERR(pclk))
        return -EINVAL;

    ret = pclk->ops->set_rate(pclk, rate);
    clk_put(pclk);

    return ret;
}
Ejemplo n.º 21
0
unsigned long s5p_spdif_get_rate(struct clk *clk)
{
    struct clk *pclk;
    int rate;

    pclk = __clk_get_parent(clk);
    if (IS_ERR(pclk))
        return -EINVAL;

    rate = pclk->ops->get_rate(pclk);
    clk_put(pclk);

    return rate;
}
Ejemplo n.º 22
0
static unsigned long clk_core_recalc_rate(struct clk_hw *hw,
		unsigned long parent_rate)
{
	/* As parent rate could be changed in clk_core.set_rate
	 * ops, the passing_in parent_rate may not be the newest
	 * and we should use the parent->rate instead. As a side
	 * effect, we should NOT directly set clk_core's parent
	 * (apll) rate, otherwise we will get a wrong recalc rate
	 * with clk_core_recalc_rate.
	 */
	struct clk *parent = __clk_get_parent(hw->clk);

	return clk_divider_recalc_rate(hw, __clk_get_rate(parent));
}
Ejemplo n.º 23
0
static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate,
				unsigned long *prate)
{
	struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);

	if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
		unsigned long best_parent;

		best_parent = (rate / fix->mult) * fix->div;
		*prate = __clk_round_rate(__clk_get_parent(hw->clk),
				best_parent);
	}

	return (*prate / fix->div) * fix->mult;
}
Ejemplo n.º 24
0
/**
 * omap2_clksel_recalc() - function ptr to pass via struct clk .recalc field
 * @clk: struct clk *
 *
 * This function is intended to be called only by the clock framework.
 * Each clksel clock should have its struct clk .recalc field set to this
 * function.  Returns the clock's current rate, based on its parent's rate
 * and its current divisor setting in the hardware.
 */
unsigned long omap2_clksel_recalc(struct clk *clk)
{
	unsigned long rate;
	u32 div = 0;
	struct clk *parent;

	div = _read_divisor(clk);
	if (div == 0)
		return __clk_get_rate(clk);

	parent = __clk_get_parent(clk);
	rate = __clk_get_rate(parent) / div;

	pr_debug("clock: %s: recalc'd rate is %ld (div %d)\n",
		 __clk_get_name(clk), rate, div);

	return rate;
}
Ejemplo n.º 25
0
/*
 * _dpll_test_fint - test whether an Fint value is valid for the DPLL
 * @clk: DPLL struct clk to test
 * @n: divider value (N) to test
 *
 * Tests whether a particular divider @n will result in a valid DPLL
 * internal clock frequency Fint. See the 34xx TRM 4.7.6.2 "DPLL Jitter
 * Correction".  Returns 0 if OK, -1 if the enclosing loop can terminate
 * (assuming that it is counting N upwards), or -2 if the enclosing loop
 * should skip to the next iteration (again assuming N is increasing).
 */
static int _dpll_test_fint(struct clk *clk, u8 n)
{
	struct dpll_data *dd;
	long fint, fint_min, fint_max;
	int ret = 0;

	dd = clk->dpll_data;

	/* DPLL divider must result in a valid jitter correction val */
	fint = __clk_get_rate(__clk_get_parent(clk)) / n;

	if (cpu_is_omap24xx()) {
		/* Should not be called for OMAP2, so warn if it is called */
		WARN(1, "No fint limits available for OMAP2!\n");
		return DPLL_FINT_INVALID;
	} else if (cpu_is_omap3430()) {
		fint_min = OMAP3430_DPLL_FINT_BAND1_MIN;
		fint_max = OMAP3430_DPLL_FINT_BAND2_MAX;
	} else if (dd->flags & DPLL_J_TYPE) {
		fint_min = OMAP3PLUS_DPLL_FINT_JTYPE_MIN;
		fint_max = OMAP3PLUS_DPLL_FINT_JTYPE_MAX;
	} else {
		fint_min = OMAP3PLUS_DPLL_FINT_MIN;
		fint_max = OMAP3PLUS_DPLL_FINT_MAX;
	}

	if (fint < fint_min) {
		pr_debug("rejecting n=%d due to Fint failure, lowering max_divider\n",
			 n);
		dd->max_divider = n;
		ret = DPLL_FINT_UNDERFLOW;
	} else if (fint > fint_max) {
		pr_debug("rejecting n=%d due to Fint failure, boosting min_divider\n",
			 n);
		dd->min_divider = n;
		ret = DPLL_FINT_INVALID;
	} else if (cpu_is_omap3430() && fint > OMAP3430_DPLL_FINT_BAND1_MAX &&
		   fint < OMAP3430_DPLL_FINT_BAND2_MIN) {
		pr_debug("rejecting n=%d due to Fint failure\n", n);
		ret = DPLL_FINT_INVALID;
	}

	return ret;
}
Ejemplo n.º 26
0
/**
 * omap2_init_clksel_parent() - set a clksel clk's parent field from the hdwr
 * @clk: OMAP clock struct ptr to use
 *
 * Given a pointer @clk to a source-selectable struct clk, read the
 * hardware register and determine what its parent is currently set
 * to.  Update @clk's .parent field with the appropriate clk ptr.  No
 * return value.
 */
void omap2_init_clksel_parent(struct clk *clk)
{
	const struct clksel *clks;
	const struct clksel_rate *clkr;
	u32 r, found = 0;
	struct clk *parent;
	const char *clk_name;

	if (!clk->clksel || !clk->clksel_mask)
		return;

	parent = __clk_get_parent(clk);
	clk_name = __clk_get_name(clk);

	r = __raw_readl(clk->clksel_reg) & clk->clksel_mask;
	r >>= __ffs(clk->clksel_mask);

	for (clks = clk->clksel; clks->parent && !found; clks++) {
		for (clkr = clks->rates; clkr->div && !found; clkr++) {
			if (!(clkr->flags & cpu_mask))
				continue;

			if (clkr->val == r) {
				if (parent != clks->parent) {
					pr_debug("clock: %s: inited parent to %s (was %s)\n",
						 clk_name,
						 __clk_get_name(clks->parent),
						 ((parent) ?
						  __clk_get_name(parent) :
						 "NULL"));
					clk_reparent(clk, clks->parent);
				};
				found = 1;
			}
		}
	}

	/* This indicates a data error */
	WARN(!found, "clock: %s: init parent: could not find regval %0x\n",
	     clk_name, r);

	return;
}
Ejemplo n.º 27
0
/**
 * _get_div_and_fieldval() - find the new clksel divisor and field value to use
 * @src_clk: planned new parent struct clk *
 * @clk: struct clk * that is being reparented
 * @field_val: pointer to a u32 to contain the register data for the divisor
 *
 * Given an intended new parent struct clk * @src_clk, and the struct
 * clk * @clk to the clock that is being reparented, find the
 * appropriate rate divisor for the new clock (returned as the return
 * value), and the corresponding register bitfield data to program to
 * reach that divisor (returned in the u32 pointed to by @field_val).
 * Returns 0 on error, or returns the newly-selected divisor upon
 * success (in this latter case, the corresponding register bitfield
 * value is passed back in the variable pointed to by @field_val)
 */
static u8 _get_div_and_fieldval(struct clk *src_clk, struct clk *clk,
				u32 *field_val)
{
	const struct clksel *clks;
	const struct clksel_rate *clkr, *max_clkr = NULL;
	u8 max_div = 0;

	clks = _get_clksel_by_parent(clk, src_clk);
	if (!clks)
		return 0;

	/*
	 * Find the highest divisor (e.g., the one resulting in the
	 * lowest rate) to use as the default.  This should avoid
	 * clock rates that are too high for the device.  XXX A better
	 * solution here would be to try to determine if there is a
	 * divisor matching the original clock rate before the parent
	 * switch, and if it cannot be found, to fall back to the
	 * highest divisor.
	 */
	for (clkr = clks->rates; clkr->div; clkr++) {
		if (!(clkr->flags & cpu_mask))
			continue;

		if (clkr->div > max_div) {
			max_div = clkr->div;
			max_clkr = clkr;
		}
	}

	if (max_div == 0) {
		/* This indicates an error in the clksel data */
		WARN(1, "clock: %s: could not find divisor for parent %s\n",
		     __clk_get_name(clk),
		     __clk_get_name(__clk_get_parent(src_clk)));
		return 0;
	}

	*field_val = max_clkr->val;

	return max_div;
}
Ejemplo n.º 28
0
/*
 * _dpll_test_fint - test whether an Fint value is valid for the DPLL
 * @clk: DPLL struct clk to test
 * @n: divider value (N) to test
 *
 * Tests whether a particular divider @n will result in a valid DPLL
 * internal clock frequency Fint. See the 34xx TRM 4.7.6.2 "DPLL Jitter
 * Correction".  Returns 0 if OK, -1 if the enclosing loop can terminate
 * (assuming that it is counting N upwards), or -2 if the enclosing loop
 * should skip to the next iteration (again assuming N is increasing).
 */
static int _dpll_test_fint(struct clk_hw_omap *clk, unsigned int n)
{
	struct dpll_data *dd;
	long fint, fint_min, fint_max;
	int ret = 0;

	dd = clk->dpll_data;

	/* DPLL divider must result in a valid jitter correction val */
	fint = __clk_get_rate(__clk_get_parent(clk->hw.clk)) / n;

	if (dd->flags & DPLL_J_TYPE) {
		fint_min = OMAP3PLUS_DPLL_FINT_JTYPE_MIN;
		fint_max = OMAP3PLUS_DPLL_FINT_JTYPE_MAX;
	} else {
		fint_min = ti_clk_features.fint_min;
		fint_max = ti_clk_features.fint_max;
	}

	if (!fint_min || !fint_max) {
		WARN(1, "No fint limits available!\n");
		return DPLL_FINT_INVALID;
	}

	if (fint < ti_clk_features.fint_min) {
		pr_debug("rejecting n=%d due to Fint failure, lowering max_divider\n",
			 n);
		dd->max_divider = n;
		ret = DPLL_FINT_UNDERFLOW;
	} else if (fint > ti_clk_features.fint_max) {
		pr_debug("rejecting n=%d due to Fint failure, boosting min_divider\n",
			 n);
		dd->min_divider = n;
		ret = DPLL_FINT_INVALID;
	} else if (fint > ti_clk_features.fint_band1_max &&
		   fint < ti_clk_features.fint_band2_min) {
		pr_debug("rejecting n=%d due to Fint failure\n", n);
		ret = DPLL_FINT_INVALID;
	}

	return ret;
}
Ejemplo n.º 29
0
/**
 * _lookup_sddiv - Calculate sigma delta divider for j-type DPLL
 * @clk: pointer to a DPLL struct clk
 * @sd_div: target sigma-delta divider
 * @m: DPLL multiplier to set
 * @n: DPLL divider to set
 *
 * See 36xx TRM section 3.5.3.3.3.2 "Type B DPLL (Low-Jitter)"
 *
 * XXX This code is not needed for 3430/AM35xx; can it be optimized
 * out in non-multi-OMAP builds for those chips?
 */
static void _lookup_sddiv(struct clk_hw_omap *clk, u8 *sd_div, u16 m, u8 n)
{
	unsigned long clkinp, sd; /* watch out for overflow */
	int mod1, mod2;

	clkinp = __clk_get_rate(__clk_get_parent(clk->hw.clk));

	/*
	 * target sigma-delta to near 250MHz
	 * sd = ceil[(m/(n+1)) * (clkinp_MHz / 250)]
	 */
	clkinp /= 100000; /* shift from MHz to 10*Hz for 38.4 and 19.2 */
	mod1 = (clkinp * m) % (250 * n);
	sd = (clkinp * m) / (250 * n);
	mod2 = sd % 10;
	sd /= 10;

	if (mod1 || mod2)
		sd++;
	*sd_div = sd;
}
Ejemplo n.º 30
0
/**
 * omap3_clkoutx2_recalc - recalculate DPLL X2 output virtual clock rate
 * @clk: DPLL output struct clk
 *
 * Using parent clock DPLL data, look up DPLL state.  If locked, set our
 * rate to the dpll_clk * 2; otherwise, just use dpll_clk.
 */
unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
				    unsigned long parent_rate)
{
	const struct dpll_data *dd;
	unsigned long rate;
	u32 v;
	struct clk_hw_omap *pclk = NULL;
	struct clk *parent;

	/* Walk up the parents of clk, looking for a DPLL */
	do {
		do {
			parent = __clk_get_parent(hw->clk);
			hw = __clk_get_hw(parent);
		} while (hw && (__clk_get_flags(hw->clk) & CLK_IS_BASIC));
		if (!hw)
			break;
		pclk = to_clk_hw_omap(hw);
	} while (pclk && !pclk->dpll_data);

	/* clk does not have a DPLL as a parent?  error in the clock data */
	if (!pclk) {
		WARN_ON(1);
		return 0;
	}

	dd = pclk->dpll_data;

	WARN_ON(!dd->enable_mask);

	v = __raw_readl(dd->control_reg) & dd->enable_mask;
	v >>= __ffs(dd->enable_mask);
	if ((v != OMAP3XXX_EN_DPLL_LOCKED) || (dd->flags & DPLL_J_TYPE))
		rate = parent_rate;
	else
		rate = parent_rate * 2;
	return rate;
}