示例#1
0
static int mux_set_rate(struct clk *c, unsigned long rate)
{
	struct mux_clk *mux = to_mux_clk(c);
	struct clk *new_parent = NULL;
	int rc = 0, i;
	unsigned long new_par_curr_rate;
	unsigned long flags;

	for (i = 0; i < mux->num_parents; i++) {
		if (clk_round_rate(mux->parents[i].src, rate) == rate) {
			new_parent = mux->parents[i].src;
			break;
		}
	}
	if (new_parent == NULL)
		return -EINVAL;

	/*
	 * Switch to safe parent since the old and new parent might be the
	 * same and the parent might temporarily turn off while switching
	 * rates.
	 */
	if (mux->safe_sel >= 0) {
		/*
		 * Some mux implementations might switch to/from a low power
		 * parent as part of their disable/enable ops. Grab the
		 * enable lock to avoid racing with these implementations.
		 */
		spin_lock_irqsave(&c->lock, flags);
		rc = mux->ops->set_mux_sel(mux, mux->safe_sel);
		spin_unlock_irqrestore(&c->lock, flags);
	}
	if (rc)
		return rc;

	new_par_curr_rate = clk_get_rate(new_parent);
	rc = clk_set_rate(new_parent, rate);
	if (rc)
		goto set_rate_fail;

	rc = mux_set_parent(c, new_parent);
	if (rc)
		goto set_par_fail;

	return 0;

set_par_fail:
	clk_set_rate(new_parent, new_par_curr_rate);
set_rate_fail:
	WARN(mux->ops->set_mux_sel(mux,
		parent_to_src_sel(mux->parents, mux->num_parents, c->parent)),
		"Set rate failed for %s. Also in bad state!\n", c->dbg_name);
	return rc;
}
static int mux_set_rate(struct clk *c, unsigned long rate)
{
	struct mux_clk *mux = to_mux_clk(c);
	struct clk *new_parent = NULL;
	int rc = 0, i;
	unsigned long new_par_curr_rate;
	unsigned long flags;

	for (i = 0; i < mux->num_parents; i++) {
		if (clk_round_rate(mux->parents[i].src, rate) == rate) {
			new_parent = mux->parents[i].src;
			break;
		}
	}
	if (new_parent == NULL)
		return -EINVAL;

	if (mux->safe_sel >= 0) {
		spin_lock_irqsave(&c->lock, flags);
		rc = mux->ops->set_mux_sel(mux, mux->safe_sel);
		spin_unlock_irqrestore(&c->lock, flags);
	}
	if (rc)
		return rc;

	new_par_curr_rate = clk_get_rate(new_parent);
	rc = clk_set_rate(new_parent, rate);
	if (rc)
		goto set_rate_fail;

	rc = mux_set_parent(c, new_parent);
	if (rc)
		goto set_par_fail;

	return 0;

set_par_fail:
	clk_set_rate(new_parent, new_par_curr_rate);
set_rate_fail:
	WARN(mux->ops->set_mux_sel(mux,
		parent_to_src_sel(mux->parents, mux->num_parents, c->parent)),
		"Set rate failed for %s. Also in bad state!\n", c->dbg_name);
	return rc;
}
static int mux_set_rate(struct clk *c, unsigned long rate)
{
	struct mux_clk *mux = to_mux_clk(c);
	struct clk *new_parent = NULL;
	int rc = 0, i;
	unsigned long new_par_curr_rate;
	unsigned long flags;

#if defined(CONFIG_HTC_DEBUG_FOOTPRINT)
	set_acpuclk_footprint_by_clk(c, ACPU_BEFORE_SAFE_PARENT_INIT);
#endif

	for (i = 0; i < mux->num_parents && mux->try_get_rate; i++) {
		struct clk *p = mux->parents[i].src;
		if (p->rate == rate && clk_round_rate(p, rate) == rate) {
			new_parent = mux->parents[i].src;
			break;
		}
	}

	for (i = 0; i < mux->num_parents && !(!i && new_parent); i++) {
		if (clk_round_rate(mux->parents[i].src, rate) == rate) {
			new_parent = mux->parents[i].src;
			if (!mux->try_new_parent)
				break;
			if (mux->try_new_parent && new_parent != c->parent)
				break;
		}
	}

	if (new_parent == NULL)
		return -EINVAL;

#if defined(CONFIG_HTC_DEBUG_FOOTPRINT)
	set_acpuclk_footprint_by_clk(c, ACPU_BEFORE_SET_SAFE_RATE);
#endif

	if (mux->safe_sel >= 0 &&
		!(mux->try_new_parent && (new_parent != c->parent))) {
		if (mux->safe_freq) {
			rc = clk_set_rate(mux->safe_parent, mux->safe_freq);
			if (rc) {
				pr_err("Failed to set safe rate on %s\n",
					clk_name(mux->safe_parent));
				return rc;
			}
		}

		spin_lock_irqsave(&c->lock, flags);
		rc = mux->ops->set_mux_sel(mux, mux->safe_sel);
		spin_unlock_irqrestore(&c->lock, flags);
		if (rc)
			return rc;

	}

#if defined(CONFIG_HTC_DEBUG_FOOTPRINT)
	set_acpuclk_footprint_by_clk(c, ACPU_BEFORE_SET_PARENT_RATE);
#endif
	new_par_curr_rate = clk_get_rate(new_parent);
	rc = clk_set_rate(new_parent, rate);
	if (rc)
		goto set_rate_fail;

#if defined(CONFIG_HTC_DEBUG_FOOTPRINT)
	set_acpuclk_footprint_by_clk(c, ACPU_BEFORE_CLK_UNPREPARE);
#endif

	rc = mux_set_parent(c, new_parent);
	if (rc)
		goto set_par_fail;

#if defined(CONFIG_HTC_DEBUG_FOOTPRINT)
	set_acpuclk_cpu_freq_footprint_by_clk(FT_CUR_RATE, c, rate);
	set_acpuclk_l2_freq_footprint_by_clk(FT_CUR_RATE, c, rate);
#endif

#if defined(CONFIG_HTC_DEBUG_FOOTPRINT)
	set_acpuclk_footprint_by_clk(c, ACPU_BEFORE_RETURN);
#endif
	return 0;

set_par_fail:
#if defined(CONFIG_HTC_DEBUG_FOOTPRINT)
	set_acpuclk_footprint_by_clk(c, ACPU_BEFORE_ERR_CLK_UNPREPARE);
#endif
	clk_set_rate(new_parent, new_par_curr_rate);
set_rate_fail:
#if defined(CONFIG_HTC_DEBUG_FOOTPRINT)
	set_acpuclk_footprint_by_clk(c, ACPU_BEFORE_ERR_SET_PARENT_RATE);
#endif
	WARN(mux->ops->set_mux_sel(mux,
		mux_parent_to_src_sel(mux, c->parent)),
		"Set rate failed for %s. Also in bad state!\n", c->dbg_name);
#if defined(CONFIG_HTC_DEBUG_FOOTPRINT)
	set_acpuclk_footprint_by_clk(c, ACPU_BEFORE_ERR_RETURN);
#endif
	return rc;
}
static int mux_set_rate(struct clk *c, unsigned long rate)
{
	struct mux_clk *mux = to_mux_clk(c);
	struct clk *new_parent = NULL;
	int rc = 0, i;
	unsigned long new_par_curr_rate;
	unsigned long flags;

	/*
	 * Check if one of the possible parents is already at the requested
	 * rate.
	 */
	for (i = 0; i < mux->num_parents && mux->try_get_rate; i++) {
		struct clk *p = mux->parents[i].src;
		if (p->rate == rate && clk_round_rate(p, rate) == rate) {
			new_parent = mux->parents[i].src;
			break;
		}
	}

	for (i = 0; i < mux->num_parents && !(!i && new_parent); i++) {
		if (clk_round_rate(mux->parents[i].src, rate) == rate) {
			new_parent = mux->parents[i].src;
			if (!mux->try_new_parent)
				break;
			if (mux->try_new_parent && new_parent != c->parent)
				break;
		}
	}

	if (new_parent == NULL)
		return -EINVAL;

	/*
	 * Switch to safe parent since the old and new parent might be the
	 * same and the parent might temporarily turn off while switching
	 * rates. If the mux can switch between distinct sources safely
	 * (indicated by try_new_parent), and the new source is not the current
	 * parent, do not switch to the safe parent.
	 */
	if (mux->safe_sel >= 0 &&
		!(mux->try_new_parent && (new_parent != c->parent))) {
		/*
		 * The safe parent might be a clock with multiple sources;
		 * to select the "safe" source, set a safe frequency.
		 */
		if (mux->safe_freq) {
			rc = clk_set_rate(mux->safe_parent, mux->safe_freq);
			if (rc) {
				pr_err("Failed to set safe rate on %s\n",
					clk_name(mux->safe_parent));
				return rc;
			}
		}

		/*
		 * Some mux implementations might switch to/from a low power
		 * parent as part of their disable/enable ops. Grab the
		 * enable lock to avoid racing with these implementations.
		 */
		spin_lock_irqsave(&c->lock, flags);
		rc = mux->ops->set_mux_sel(mux, mux->safe_sel);
		spin_unlock_irqrestore(&c->lock, flags);
		if (rc)
			return rc;

	}

	new_par_curr_rate = clk_get_rate(new_parent);
	rc = clk_set_rate(new_parent, rate);
	if (rc)
		goto set_rate_fail;

	rc = mux_set_parent(c, new_parent);
	if (rc)
		goto set_par_fail;

	return 0;

set_par_fail:
	clk_set_rate(new_parent, new_par_curr_rate);
set_rate_fail:
	WARN(mux->ops->set_mux_sel(mux,
		mux_parent_to_src_sel(mux, c->parent)),
		"Set rate failed for %s. Also in bad state!\n", c->dbg_name);
	return rc;
}