void clk_disable(struct clk *clk)
{
	unsigned long flags;

	if (!clk)
		return;

	spin_lock_irqsave(&clk->lock, flags);
	if (WARN(clk->count == 0, "%s is unbalanced", clk->dbg_name))
		goto out;
	if (clk->count == 1) {
		struct clk *parent = clk_get_parent(clk);

		if (clk->ops->disable)
			clk->ops->disable(clk);
		unvote_rate_vdd(clk, clk->rate);

		if (!(clk->flags&CLKFLAG_IGNORE)) {	/*added by htc for clock debugging*/
			clk_disable(clk->depends);
			clk_disable(parent);
			/*added by htc for clock debugging*/
			spin_lock(&clk_enable_list_lock);
			list_del(&clk->enable_list);
			spin_unlock(&clk_enable_list_lock);
		}
	}
	clk->count--;
out:
	spin_unlock_irqrestore(&clk->lock, flags);
}
/*
 * Standard clock functions defined in include/linux/clk.h
 */
int clk_enable(struct clk *clk)
{
	int ret = 0;
	unsigned long flags;
	struct clk *parent;

	if (!clk)
		return 0;

	spin_lock_irqsave(&clk->lock, flags);
	if (clk->count == 0) {
		parent = clk_get_parent(clk);
		if (!(clk->flags&CLKFLAG_IGNORE)) {
			ret = clk_enable(parent);
			if (ret)
				goto err_enable_parent;
			ret = clk_enable(clk->depends);
			if (ret)
				goto err_enable_depends;
		}
		ret = vote_rate_vdd(clk, clk->rate);
		if (ret)
			goto err_vote_vdd;
		if (clk->ops->enable)
			ret = clk->ops->enable(clk);
		if (ret)
			goto err_enable_clock;

		/*added by htc for clock debugging*/
		if (!(clk->flags&CLKFLAG_IGNORE)) {
			spin_lock(&clk_enable_list_lock);
			list_add(&clk->enable_list, &clk_enable_list);
			spin_unlock(&clk_enable_list_lock);
		}
	} else if (clk->flags & CLKFLAG_HANDOFF_RATE) {
		/*
		 * The clock was already enabled by handoff code so there is no
		 * need to enable it again here. Clearing the handoff flag will
		 * prevent the lateinit handoff code from disabling the clock if
		 * a client driver still has it enabled.
		 */
		clk->flags &= ~CLKFLAG_HANDOFF_RATE;
		goto out;
	}
	clk->count++;
out:
	spin_unlock_irqrestore(&clk->lock, flags);

	return 0;

err_enable_clock:
	unvote_rate_vdd(clk, clk->rate);
err_vote_vdd:
	clk_disable(clk->depends);
err_enable_depends:
	clk_disable(parent);
err_enable_parent:
	spin_unlock_irqrestore(&clk->lock, flags);
	return ret;
}
Exemple #3
0
void clk_disable(struct clk *clk)
{
	unsigned long flags;

	if (!clk)
		return;

	spin_lock_irqsave(&clk->lock, flags);
	if (WARN(clk->count == 0, "%s is unbalanced", clk->dbg_name))
		goto out;
	if (clk->count == 1) {
		struct clk *parent = clk_get_parent(clk);

		if (clk->ops->disable) {
			clk->ops->disable(clk);
			clk_log_map_disable(clk);
		}
		unvote_rate_vdd(clk, clk->rate);
		clk_disable(clk->depends);
		clk_disable(parent);
	}
	clk->count--;
out:
	spin_unlock_irqrestore(&clk->lock, flags);
}
Exemple #4
0
void clk_disable(struct clk *clk)
{
	unsigned long flags;

	if (IS_ERR_OR_NULL(clk))
		return;

	spin_lock_irqsave(&clk->lock, flags);
	if (WARN(!clk->warned && !clk->prepare_count,
				"%s: Never called prepare or calling disable "
				"after unprepare\n",
				clk->dbg_name))
		clk->warned = true;
	if (WARN(clk->count == 0, "%s is unbalanced", clk->dbg_name))
		goto out;
	if (clk->count == 1) {
		struct clk *parent = clk_get_parent(clk);

		trace_clock_disable(clk->dbg_name, 0, smp_processor_id());
		if (clk->ops->disable)
			clk->ops->disable(clk);
		unvote_rate_vdd(clk, clk->rate);
		clk_disable(clk->depends);
		clk_disable(parent);
	}
	clk->count--;
out:
	spin_unlock_irqrestore(&clk->lock, flags);
}
Exemple #5
0
/*
 * Standard clock functions defined in include/linux/clk.h
 */
int clk_enable(struct clk *clk)
{
	int ret = 0;
	unsigned long flags;
	struct clk *parent;

	if (!clk)
		return 0;
	if (IS_ERR(clk))
		return -EINVAL;

	spin_lock_irqsave(&clk->lock, flags);
	if (WARN(!clk->warned && !clk->prepare_count,
				"%s: Don't call enable on unprepared clocks\n",
				clk->dbg_name))
		clk->warned = true;
	if (clk->count == 0) {
		parent = clk_get_parent(clk);

		ret = clk_enable(parent);
		if (ret)
			goto err_enable_parent;
		ret = clk_enable(clk->depends);
		if (ret)
			goto err_enable_depends;

		ret = vote_rate_vdd(clk, clk->rate);
		if (ret)
			goto err_vote_vdd;
		trace_clock_enable(clk->dbg_name, 1, smp_processor_id());
		if (clk->ops->enable)
			ret = clk->ops->enable(clk);
		if (ret)
			goto err_enable_clock;
	} else if (clk->flags & CLKFLAG_HANDOFF_RATE) {
		/*
		 * The clock was already enabled by handoff code so there is no
		 * need to enable it again here. Clearing the handoff flag will
		 * prevent the lateinit handoff code from disabling the clock if
		 * a client driver still has it enabled.
		 */
		clk->flags &= ~CLKFLAG_HANDOFF_RATE;
		goto out;
	}
	clk->count++;
out:
	spin_unlock_irqrestore(&clk->lock, flags);

	return 0;

err_enable_clock:
	unvote_rate_vdd(clk, clk->rate);
err_vote_vdd:
	clk_disable(clk->depends);
err_enable_depends:
	clk_disable(parent);
err_enable_parent:
	spin_unlock_irqrestore(&clk->lock, flags);
	return ret;
}
Exemple #6
0
int clk_set_rate(struct clk *clk, unsigned long rate)
{
	unsigned long start_rate, flags;
	int rc;

	if (IS_ERR_OR_NULL(clk))
		return -EINVAL;

	if (!clk->ops->set_rate)
		return -ENOSYS;

	spin_lock_irqsave(&clk->lock, flags);
	trace_clock_set_rate(clk->dbg_name, rate, smp_processor_id());
	if (clk->count) {
		start_rate = clk->rate;
		/* Enforce vdd requirements for target frequency. */
		rc = vote_rate_vdd(clk, rate);
		if (rc)
			goto err_vote_vdd;
		rc = clk->ops->set_rate(clk, rate);
		if (rc)
			goto err_set_rate;
		/* Release vdd requirements for starting frequency. */
		unvote_rate_vdd(clk, start_rate);
	} else {
		rc = clk->ops->set_rate(clk, rate);
	}

	if (!rc)
		clk->rate = rate;

	spin_unlock_irqrestore(&clk->lock, flags);
	return rc;

err_set_rate:
	unvote_rate_vdd(clk, rate);
err_vote_vdd:
	spin_unlock_irqrestore(&clk->lock, flags);
	return rc;
}
static int _clk_set_rate(struct clk *clk, unsigned long rate,
			 int (*set_fn)(struct clk *, unsigned long))
{
	unsigned long start_rate, flags;
	int rc;

	if (!set_fn)
		return -ENOSYS;

	spin_lock_irqsave(&clk->lock, flags);
	if (clk->count) {
		start_rate = clk->rate;
		/* Enforce vdd requirements for target frequency. */
		rc = vote_rate_vdd(clk, rate);
		if (rc)
			goto err_vote_vdd;
		rc = set_fn(clk, rate);
		if (rc)
			goto err_set_rate;
		/* Release vdd requirements for starting frequency. */
		unvote_rate_vdd(clk, start_rate);
	} else {
		rc = set_fn(clk, rate);
	}

	if (!rc)
		clk->rate = rate;

	spin_unlock_irqrestore(&clk->lock, flags);
	return rc;

err_set_rate:
	unvote_rate_vdd(clk, rate);
err_vote_vdd:
	spin_unlock_irqrestore(&clk->lock, flags);
	return rc;
}