Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 74b48999 authored by Stephen Boyd's avatar Stephen Boyd
Browse files

Merge branches 'clk-qcom-alpha-pll', 'clk-check-ops-ptr', 'clk-protect-rate'...

Merge branches 'clk-qcom-alpha-pll', 'clk-check-ops-ptr', 'clk-protect-rate' and 'clk-omap' into clk-next

* clk-qcom-alpha-pll:
  clk: qcom: add read-only alpha pll post divider operations
  clk: qcom: support for 2 bit PLL post divider
  clk: qcom: support Brammo type Alpha PLL
  clk: qcom: support Huayra type Alpha PLL
  clk: qcom: support for dynamic updating the PLL
  clk: qcom: support for alpha mode configuration
  clk: qcom: flag for 64 bit CONFIG_CTL
  clk: qcom: fix 16 bit alpha support calculation
  clk: qcom: support for alpha pll properties

* clk-check-ops-ptr:
  clk: check ops pointer on clock register

* clk-protect-rate:
  clk: fix set_rate_range when current rate is out of range
  clk: add clk_rate_exclusive api
  clk: cosmetic changes to clk_summary debugfs entry
  clk: add clock protection mechanism to clk core
  clk: use round rate to bail out early in set_rate
  clk: rework calls to round and determine rate callbacks
  clk: add clk_core_set_phase_nolock function
  clk: take the prepare lock out of clk_core_set_parent
  clk: fix incorrect usage of ENOSYS

* clk-omap:
  clk: ti: Drop legacy clk-3xxx-legacy code
Loading
Loading
Loading
Loading
+435 −69
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ struct clk_core {
	bool			orphan;
	unsigned int		enable_count;
	unsigned int		prepare_count;
	unsigned int		protect_count;
	unsigned long		min_rate;
	unsigned long		max_rate;
	unsigned long		accuracy;
@@ -86,6 +87,7 @@ struct clk {
	const char *con_id;
	unsigned long min_rate;
	unsigned long max_rate;
	unsigned int exclusive_count;
	struct hlist_node clks_node;
};

@@ -170,6 +172,11 @@ static void clk_enable_unlock(unsigned long flags)
	spin_unlock_irqrestore(&enable_lock, flags);
}

static bool clk_core_rate_is_protected(struct clk_core *core)
{
	return core->protect_count;
}

static bool clk_core_is_prepared(struct clk_core *core)
{
	bool ret = false;
@@ -381,6 +388,11 @@ bool clk_hw_is_prepared(const struct clk_hw *hw)
	return clk_core_is_prepared(hw->core);
}

bool clk_hw_rate_is_protected(const struct clk_hw *hw)
{
	return clk_core_rate_is_protected(hw->core);
}

bool clk_hw_is_enabled(const struct clk_hw *hw)
{
	return clk_core_is_enabled(hw->core);
@@ -519,6 +531,139 @@ EXPORT_SYMBOL_GPL(__clk_mux_determine_rate_closest);

/***        clk api        ***/

static void clk_core_rate_unprotect(struct clk_core *core)
{
	lockdep_assert_held(&prepare_lock);

	if (!core)
		return;

	if (WARN_ON(core->protect_count == 0))
		return;

	if (--core->protect_count > 0)
		return;

	clk_core_rate_unprotect(core->parent);
}

static int clk_core_rate_nuke_protect(struct clk_core *core)
{
	int ret;

	lockdep_assert_held(&prepare_lock);

	if (!core)
		return -EINVAL;

	if (core->protect_count == 0)
		return 0;

	ret = core->protect_count;
	core->protect_count = 1;
	clk_core_rate_unprotect(core);

	return ret;
}

/**
 * clk_rate_exclusive_put - release exclusivity over clock rate control
 * @clk: the clk over which the exclusivity is released
 *
 * clk_rate_exclusive_put() completes a critical section during which a clock
 * consumer cannot tolerate any other consumer making any operation on the
 * clock which could result in a rate change or rate glitch. Exclusive clocks
 * cannot have their rate changed, either directly or indirectly due to changes
 * further up the parent chain of clocks. As a result, clocks up parent chain
 * also get under exclusive control of the calling consumer.
 *
 * If exlusivity is claimed more than once on clock, even by the same consumer,
 * the rate effectively gets locked as exclusivity can't be preempted.
 *
 * Calls to clk_rate_exclusive_put() must be balanced with calls to
 * clk_rate_exclusive_get(). Calls to this function may sleep, and do not return
 * error status.
 */
void clk_rate_exclusive_put(struct clk *clk)
{
	if (!clk)
		return;

	clk_prepare_lock();

	/*
	 * if there is something wrong with this consumer protect count, stop
	 * here before messing with the provider
	 */
	if (WARN_ON(clk->exclusive_count <= 0))
		goto out;

	clk_core_rate_unprotect(clk->core);
	clk->exclusive_count--;
out:
	clk_prepare_unlock();
}
EXPORT_SYMBOL_GPL(clk_rate_exclusive_put);

static void clk_core_rate_protect(struct clk_core *core)
{
	lockdep_assert_held(&prepare_lock);

	if (!core)
		return;

	if (core->protect_count == 0)
		clk_core_rate_protect(core->parent);

	core->protect_count++;
}

static void clk_core_rate_restore_protect(struct clk_core *core, int count)
{
	lockdep_assert_held(&prepare_lock);

	if (!core)
		return;

	if (count == 0)
		return;

	clk_core_rate_protect(core);
	core->protect_count = count;
}

/**
 * clk_rate_exclusive_get - get exclusivity over the clk rate control
 * @clk: the clk over which the exclusity of rate control is requested
 *
 * clk_rate_exlusive_get() begins a critical section during which a clock
 * consumer cannot tolerate any other consumer making any operation on the
 * clock which could result in a rate change or rate glitch. Exclusive clocks
 * cannot have their rate changed, either directly or indirectly due to changes
 * further up the parent chain of clocks. As a result, clocks up parent chain
 * also get under exclusive control of the calling consumer.
 *
 * If exlusivity is claimed more than once on clock, even by the same consumer,
 * the rate effectively gets locked as exclusivity can't be preempted.
 *
 * Calls to clk_rate_exclusive_get() should be balanced with calls to
 * clk_rate_exclusive_put(). Calls to this function may sleep.
 * Returns 0 on success, -EERROR otherwise
 */
int clk_rate_exclusive_get(struct clk *clk)
{
	if (!clk)
		return 0;

	clk_prepare_lock();
	clk_core_rate_protect(clk->core);
	clk->exclusive_count++;
	clk_prepare_unlock();

	return 0;
}
EXPORT_SYMBOL_GPL(clk_rate_exclusive_get);

static void clk_core_unprepare(struct clk_core *core)
{
	lockdep_assert_held(&prepare_lock);
@@ -905,10 +1050,9 @@ static int clk_disable_unused(void)
}
late_initcall_sync(clk_disable_unused);

static int clk_core_round_rate_nolock(struct clk_core *core,
static int clk_core_determine_round_nolock(struct clk_core *core,
					   struct clk_rate_request *req)
{
	struct clk_core *parent;
	long rate;

	lockdep_assert_held(&prepare_lock);
@@ -916,6 +1060,38 @@ static int clk_core_round_rate_nolock(struct clk_core *core,
	if (!core)
		return 0;

	/*
	 * At this point, core protection will be disabled if
	 * - if the provider is not protected at all
	 * - if the calling consumer is the only one which has exclusivity
	 *   over the provider
	 */
	if (clk_core_rate_is_protected(core)) {
		req->rate = core->rate;
	} else if (core->ops->determine_rate) {
		return core->ops->determine_rate(core->hw, req);
	} else if (core->ops->round_rate) {
		rate = core->ops->round_rate(core->hw, req->rate,
					     &req->best_parent_rate);
		if (rate < 0)
			return rate;

		req->rate = rate;
	} else {
		return -EINVAL;
	}

	return 0;
}

static void clk_core_init_rate_req(struct clk_core * const core,
				   struct clk_rate_request *req)
{
	struct clk_core *parent;

	if (WARN_ON(!core || !req))
		return;

	parent = core->parent;
	if (parent) {
		req->best_parent_hw = parent->hw;
@@ -924,22 +1100,32 @@ static int clk_core_round_rate_nolock(struct clk_core *core,
		req->best_parent_hw = NULL;
		req->best_parent_rate = 0;
	}
}

	if (core->ops->determine_rate) {
		return core->ops->determine_rate(core->hw, req);
	} else if (core->ops->round_rate) {
		rate = core->ops->round_rate(core->hw, req->rate,
					     &req->best_parent_rate);
		if (rate < 0)
			return rate;
static bool clk_core_can_round(struct clk_core * const core)
{
	if (core->ops->determine_rate || core->ops->round_rate)
		return true;

		req->rate = rate;
	} else if (core->flags & CLK_SET_RATE_PARENT) {
		return clk_core_round_rate_nolock(parent, req);
	} else {
		req->rate = core->rate;
	return false;
}

static int clk_core_round_rate_nolock(struct clk_core *core,
				      struct clk_rate_request *req)
{
	lockdep_assert_held(&prepare_lock);

	if (!core)
		return 0;

	clk_core_init_rate_req(core, req);

	if (clk_core_can_round(core))
		return clk_core_determine_round_nolock(core, req);
	else if (core->flags & CLK_SET_RATE_PARENT)
		return clk_core_round_rate_nolock(core->parent, req);

	req->rate = core->rate;
	return 0;
}

@@ -996,10 +1182,17 @@ long clk_round_rate(struct clk *clk, unsigned long rate)

	clk_prepare_lock();

	if (clk->exclusive_count)
		clk_core_rate_unprotect(clk->core);

	clk_core_get_boundaries(clk->core, &req.min_rate, &req.max_rate);
	req.rate = rate;

	ret = clk_core_round_rate_nolock(clk->core, &req);

	if (clk->exclusive_count)
		clk_core_rate_protect(clk->core);

	clk_prepare_unlock();

	if (ret)
@@ -1432,34 +1625,23 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core,
	clk_core_get_boundaries(core, &min_rate, &max_rate);

	/* find the closest rate and parent clk/rate */
	if (core->ops->determine_rate) {
	if (clk_core_can_round(core)) {
		struct clk_rate_request req;

		req.rate = rate;
		req.min_rate = min_rate;
		req.max_rate = max_rate;
		if (parent) {
			req.best_parent_hw = parent->hw;
			req.best_parent_rate = parent->rate;
		} else {
			req.best_parent_hw = NULL;
			req.best_parent_rate = 0;
		}

		ret = core->ops->determine_rate(core->hw, &req);
		clk_core_init_rate_req(core, &req);

		ret = clk_core_determine_round_nolock(core, &req);
		if (ret < 0)
			return NULL;

		best_parent_rate = req.best_parent_rate;
		new_rate = req.rate;
		parent = req.best_parent_hw ? req.best_parent_hw->core : NULL;
	} else if (core->ops->round_rate) {
		ret = core->ops->round_rate(core->hw, rate,
					    &best_parent_rate);
		if (ret < 0)
			return NULL;

		new_rate = ret;
		if (new_rate < min_rate || new_rate > max_rate)
			return NULL;
	} else if (!parent || !(core->flags & CLK_SET_RATE_PARENT)) {
@@ -1641,25 +1823,58 @@ static void clk_change_rate(struct clk_core *core)
	clk_pm_runtime_put(core);
}

static unsigned long clk_core_req_round_rate_nolock(struct clk_core *core,
						     unsigned long req_rate)
{
	int ret, cnt;
	struct clk_rate_request req;

	lockdep_assert_held(&prepare_lock);

	if (!core)
		return 0;

	/* simulate what the rate would be if it could be freely set */
	cnt = clk_core_rate_nuke_protect(core);
	if (cnt < 0)
		return cnt;

	clk_core_get_boundaries(core, &req.min_rate, &req.max_rate);
	req.rate = req_rate;

	ret = clk_core_round_rate_nolock(core, &req);

	/* restore the protection */
	clk_core_rate_restore_protect(core, cnt);

	return ret ? 0 : req.rate;
}

static int clk_core_set_rate_nolock(struct clk_core *core,
				    unsigned long req_rate)
{
	struct clk_core *top, *fail_clk;
	unsigned long rate = req_rate;
	unsigned long rate;
	int ret = 0;

	if (!core)
		return 0;

	rate = clk_core_req_round_rate_nolock(core, req_rate);

	/* bail early if nothing to do */
	if (rate == clk_core_get_rate_nolock(core))
		return 0;

	/* fail on a direct rate set of a protected provider */
	if (clk_core_rate_is_protected(core))
		return -EBUSY;

	if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count)
		return -EBUSY;

	/* calculate new rates and get the topmost changed clock */
	top = clk_calc_new_rates(core, rate);
	top = clk_calc_new_rates(core, req_rate);
	if (!top)
		return -EINVAL;

@@ -1718,14 +1933,67 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
	/* prevent racing with updates to the clock topology */
	clk_prepare_lock();

	if (clk->exclusive_count)
		clk_core_rate_unprotect(clk->core);

	ret = clk_core_set_rate_nolock(clk->core, rate);

	if (clk->exclusive_count)
		clk_core_rate_protect(clk->core);

	clk_prepare_unlock();

	return ret;
}
EXPORT_SYMBOL_GPL(clk_set_rate);

/**
 * clk_set_rate_exclusive - specify a new rate get exclusive control
 * @clk: the clk whose rate is being changed
 * @rate: the new rate for clk
 *
 * This is a combination of clk_set_rate() and clk_rate_exclusive_get()
 * within a critical section
 *
 * This can be used initially to ensure that at least 1 consumer is
 * statisfied when several consumers are competing for exclusivity over the
 * same clock provider.
 *
 * The exclusivity is not applied if setting the rate failed.
 *
 * Calls to clk_rate_exclusive_get() should be balanced with calls to
 * clk_rate_exclusive_put().
 *
 * Returns 0 on success, -EERROR otherwise.
 */
int clk_set_rate_exclusive(struct clk *clk, unsigned long rate)
{
	int ret;

	if (!clk)
		return 0;

	/* prevent racing with updates to the clock topology */
	clk_prepare_lock();

	/*
	 * The temporary protection removal is not here, on purpose
	 * This function is meant to be used instead of clk_rate_protect,
	 * so before the consumer code path protect the clock provider
	 */

	ret = clk_core_set_rate_nolock(clk->core, rate);
	if (!ret) {
		clk_core_rate_protect(clk->core);
		clk->exclusive_count++;
	}

	clk_prepare_unlock();

	return ret;
}
EXPORT_SYMBOL_GPL(clk_set_rate_exclusive);

/**
 * clk_set_rate_range - set a rate range for a clock source
 * @clk: clock source
@@ -1737,6 +2005,7 @@ EXPORT_SYMBOL_GPL(clk_set_rate);
int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)
{
	int ret = 0;
	unsigned long old_min, old_max, rate;

	if (!clk)
		return 0;
@@ -1750,11 +2019,45 @@ int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)

	clk_prepare_lock();

	if (min != clk->min_rate || max != clk->max_rate) {
	if (clk->exclusive_count)
		clk_core_rate_unprotect(clk->core);

	/* Save the current values in case we need to rollback the change */
	old_min = clk->min_rate;
	old_max = clk->max_rate;
	clk->min_rate = min;
	clk->max_rate = max;
		ret = clk_core_set_rate_nolock(clk->core, clk->core->req_rate);

	rate = clk_core_get_rate_nolock(clk->core);
	if (rate < min || rate > max) {
		/*
		 * FIXME:
		 * We are in bit of trouble here, current rate is outside the
		 * the requested range. We are going try to request appropriate
		 * range boundary but there is a catch. It may fail for the
		 * usual reason (clock broken, clock protected, etc) but also
		 * because:
		 * - round_rate() was not favorable and fell on the wrong
		 *   side of the boundary
		 * - the determine_rate() callback does not really check for
		 *   this corner case when determining the rate
		 */

		if (rate < min)
			rate = min;
		else
			rate = max;

		ret = clk_core_set_rate_nolock(clk->core, rate);
		if (ret) {
			/* rollback the changes */
			clk->min_rate = old_min;
			clk->max_rate = old_max;
		}
	}

	if (clk->exclusive_count)
		clk_core_rate_protect(clk->core);

	clk_prepare_unlock();

@@ -1876,32 +2179,31 @@ bool clk_has_parent(struct clk *clk, struct clk *parent)
}
EXPORT_SYMBOL_GPL(clk_has_parent);

static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
static int clk_core_set_parent_nolock(struct clk_core *core,
				      struct clk_core *parent)
{
	int ret = 0;
	int p_index = 0;
	unsigned long p_rate = 0;

	lockdep_assert_held(&prepare_lock);

	if (!core)
		return 0;

	/* prevent racing with updates to the clock topology */
	clk_prepare_lock();

	if (core->parent == parent)
		goto out;
		return 0;

	/* verify ops for for multi-parent clks */
	if ((core->num_parents > 1) && (!core->ops->set_parent)) {
		ret = -ENOSYS;
		goto out;
	}
	if (core->num_parents > 1 && !core->ops->set_parent)
		return -EPERM;

	/* check that we are allowed to re-parent if the clock is in use */
	if ((core->flags & CLK_SET_PARENT_GATE) && core->prepare_count) {
		ret = -EBUSY;
		goto out;
	}
	if ((core->flags & CLK_SET_PARENT_GATE) && core->prepare_count)
		return -EBUSY;

	if (clk_core_rate_is_protected(core))
		return -EBUSY;

	/* try finding the new parent index */
	if (parent) {
@@ -1909,15 +2211,14 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
		if (p_index < 0) {
			pr_debug("%s: clk %s can not be parent of clk %s\n",
					__func__, parent->name, core->name);
			ret = p_index;
			goto out;
			return p_index;
		}
		p_rate = parent->rate;
	}

	ret = clk_pm_runtime_get(core);
	if (ret)
		goto out;
		return ret;

	/* propagate PRE_RATE_CHANGE notifications */
	ret = __clk_speculate_rates(core, p_rate);
@@ -1939,8 +2240,6 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)

runtime_put:
	clk_pm_runtime_put(core);
out:
	clk_prepare_unlock();

	return ret;
}
@@ -1964,13 +2263,50 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
 */
int clk_set_parent(struct clk *clk, struct clk *parent)
{
	int ret;

	if (!clk)
		return 0;

	return clk_core_set_parent(clk->core, parent ? parent->core : NULL);
	clk_prepare_lock();

	if (clk->exclusive_count)
		clk_core_rate_unprotect(clk->core);

	ret = clk_core_set_parent_nolock(clk->core,
					 parent ? parent->core : NULL);

	if (clk->exclusive_count)
		clk_core_rate_protect(clk->core);

	clk_prepare_unlock();

	return ret;
}
EXPORT_SYMBOL_GPL(clk_set_parent);

static int clk_core_set_phase_nolock(struct clk_core *core, int degrees)
{
	int ret = -EINVAL;

	lockdep_assert_held(&prepare_lock);

	if (!core)
		return 0;

	if (clk_core_rate_is_protected(core))
		return -EBUSY;

	trace_clk_set_phase(core, degrees);

	if (core->ops->set_phase)
		ret = core->ops->set_phase(core->hw, degrees);

	trace_clk_set_phase_complete(core, degrees);

	return ret;
}

/**
 * clk_set_phase - adjust the phase shift of a clock signal
 * @clk: clock signal source
@@ -1993,7 +2329,7 @@ EXPORT_SYMBOL_GPL(clk_set_parent);
 */
int clk_set_phase(struct clk *clk, int degrees)
{
	int ret = -EINVAL;
	int ret;

	if (!clk)
		return 0;
@@ -2005,15 +2341,13 @@ int clk_set_phase(struct clk *clk, int degrees)

	clk_prepare_lock();

	trace_clk_set_phase(clk->core, degrees);
	if (clk->exclusive_count)
		clk_core_rate_unprotect(clk->core);

	if (clk->core->ops->set_phase)
		ret = clk->core->ops->set_phase(clk->core->hw, degrees);
	ret = clk_core_set_phase_nolock(clk->core, degrees);

	trace_clk_set_phase_complete(clk->core, degrees);

	if (!ret)
		clk->core->phase = degrees;
	if (clk->exclusive_count)
		clk_core_rate_protect(clk->core);

	clk_prepare_unlock();

@@ -2101,11 +2435,12 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
	if (!c)
		return;

	seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu %-3d\n",
	seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %-3d\n",
		   level * 3 + 1, "",
		   30 - level * 3, c->name,
		   c->enable_count, c->prepare_count, clk_core_get_rate(c),
		   clk_core_get_accuracy(c), clk_core_get_phase(c));
		   c->enable_count, c->prepare_count, c->protect_count,
		   clk_core_get_rate(c), clk_core_get_accuracy(c),
		   clk_core_get_phase(c));
}

static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
@@ -2127,7 +2462,8 @@ static int clk_summary_show(struct seq_file *s, void *data)
	struct clk_core *c;
	struct hlist_head **lists = (struct hlist_head **)s->private;

	seq_puts(s, "   clock                         enable_cnt  prepare_cnt        rate   accuracy   phase\n");
	seq_puts(s, "                                 enable  prepare  protect                               \n");
	seq_puts(s, "   clock                          count    count    count        rate   accuracy   phase\n");
	seq_puts(s, "----------------------------------------------------------------------------------------\n");

	clk_prepare_lock();
@@ -2163,6 +2499,7 @@ static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level)
	seq_printf(s, "\"%s\": { ", c->name);
	seq_printf(s, "\"enable_count\": %d,", c->enable_count);
	seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
	seq_printf(s, "\"protect_count\": %d,", c->protect_count);
	seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c));
	seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c));
	seq_printf(s, "\"phase\": %d", clk_core_get_phase(c));
@@ -2293,6 +2630,11 @@ static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
	if (!d)
		goto err_out;

	d = debugfs_create_u32("clk_protect_count", S_IRUGO, core->dentry,
			(u32 *)&core->protect_count);
	if (!d)
		goto err_out;

	d = debugfs_create_u32("clk_notifier_count", S_IRUGO, core->dentry,
			(u32 *)&core->notifier_count);
	if (!d)
@@ -2683,7 +3025,13 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
		ret = -ENOMEM;
		goto fail_name;
	}

	if (WARN_ON(!hw->init->ops)) {
		ret = -EINVAL;
		goto fail_ops;
	}
	core->ops = hw->init->ops;

	if (dev && pm_runtime_enabled(dev))
		core->dev = dev;
	if (dev && dev->driver)
@@ -2745,6 +3093,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
		kfree_const(core->parent_names[i]);
	kfree(core->parent_names);
fail_parent_names:
fail_ops:
	kfree_const(core->name);
fail_name:
	kfree(core);
@@ -2856,7 +3205,7 @@ void clk_unregister(struct clk *clk)
		/* Reparent all children to the orphan list. */
		hlist_for_each_entry_safe(child, t, &clk->core->children,
					  child_node)
			clk_core_set_parent(child, NULL);
			clk_core_set_parent_nolock(child, NULL);
	}

	hlist_del_init(&clk->core->child_node);
@@ -2864,6 +3213,11 @@ void clk_unregister(struct clk *clk)
	if (clk->core->prepare_count)
		pr_warn("%s: unregistering prepared clock: %s\n",
					__func__, clk->core->name);

	if (clk->core->protect_count)
		pr_warn("%s: unregistering protected clock: %s\n",
					__func__, clk->core->name);

	kref_put(&clk->core->ref, __clk_release);
unlock:
	clk_prepare_unlock();
@@ -3022,6 +3376,18 @@ void __clk_put(struct clk *clk)

	clk_prepare_lock();

	/*
	 * Before calling clk_put, all calls to clk_rate_exclusive_get() from a
	 * given user should be balanced with calls to clk_rate_exclusive_put()
	 * and by that same consumer
	 */
	if (WARN_ON(clk->exclusive_count)) {
		/* We voiced our concern, let's sanitize the situation */
		clk->core->protect_count -= (clk->exclusive_count - 1);
		clk_core_rate_unprotect(clk->core);
		clk->exclusive_count = 0;
	}

	hlist_del(&clk->clks_node);
	if (clk->min_rate > clk->core->req_rate ||
	    clk->max_rate < clk->core->req_rate)
+423 −93

File changed.

Preview size limit exceeded, changes collapsed.

+34 −1
Original line number Diff line number Diff line
@@ -17,6 +17,30 @@
#include <linux/clk-provider.h>
#include "clk-regmap.h"

/* Alpha PLL types */
enum {
	CLK_ALPHA_PLL_TYPE_DEFAULT,
	CLK_ALPHA_PLL_TYPE_HUAYRA,
	CLK_ALPHA_PLL_TYPE_BRAMMO,
	CLK_ALPHA_PLL_TYPE_MAX,
};

enum {
	PLL_OFF_L_VAL,
	PLL_OFF_ALPHA_VAL,
	PLL_OFF_ALPHA_VAL_U,
	PLL_OFF_USER_CTL,
	PLL_OFF_USER_CTL_U,
	PLL_OFF_CONFIG_CTL,
	PLL_OFF_CONFIG_CTL_U,
	PLL_OFF_TEST_CTL,
	PLL_OFF_TEST_CTL_U,
	PLL_OFF_STATUS,
	PLL_OFF_MAX_REGS
};

extern const u8 clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_MAX][PLL_OFF_MAX_REGS];

struct pll_vco {
	unsigned long min_freq;
	unsigned long max_freq;
@@ -27,16 +51,18 @@ struct pll_vco {
 * struct clk_alpha_pll - phase locked loop (PLL)
 * @offset: base address of registers
 * @vco_table: array of VCO settings
 * @regs: alpha pll register map (see @clk_alpha_pll_regs)
 * @clkr: regmap clock handle
 */
struct clk_alpha_pll {
	u32 offset;
	const u8 *regs;

	const struct pll_vco *vco_table;
	size_t num_vco;
#define SUPPORTS_OFFLINE_REQ	BIT(0)
#define SUPPORTS_16BIT_ALPHA	BIT(1)
#define SUPPORTS_FSM_MODE	BIT(2)
#define SUPPORTS_DYNAMIC_UPDATE	BIT(3)
	u8 flags;

	struct clk_regmap clkr;
@@ -45,12 +71,14 @@ struct clk_alpha_pll {
/**
 * struct clk_alpha_pll_postdiv - phase locked loop (PLL) post-divider
 * @offset: base address of registers
 * @regs: alpha pll register map (see @clk_alpha_pll_regs)
 * @width: width of post-divider
 * @clkr: regmap clock handle
 */
struct clk_alpha_pll_postdiv {
	u32 offset;
	u8 width;
	const u8 *regs;

	struct clk_regmap clkr;
};
@@ -58,12 +86,15 @@ struct clk_alpha_pll_postdiv {
struct alpha_pll_config {
	u32 l;
	u32 alpha;
	u32 alpha_hi;
	u32 config_ctl_val;
	u32 config_ctl_hi_val;
	u32 main_output_mask;
	u32 aux_output_mask;
	u32 aux2_output_mask;
	u32 early_output_mask;
	u32 alpha_en_mask;
	u32 alpha_mode_mask;
	u32 pre_div_val;
	u32 pre_div_mask;
	u32 post_div_val;
@@ -75,6 +106,8 @@ struct alpha_pll_config {
extern const struct clk_ops clk_alpha_pll_ops;
extern const struct clk_ops clk_alpha_pll_hwfsm_ops;
extern const struct clk_ops clk_alpha_pll_postdiv_ops;
extern const struct clk_ops clk_alpha_pll_huayra_ops;
extern const struct clk_ops clk_alpha_pll_postdiv_ro_ops;

void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
			     const struct alpha_pll_config *config);
+2 −0
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ static const struct parent_map gcc_xo_gpll0_gpll0_out_main_div2_map[] = {

static struct clk_alpha_pll gpll0_main = {
	.offset = 0x21000,
	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
	.clkr = {
		.enable_reg = 0x0b000,
		.enable_mask = BIT(0),
@@ -82,6 +83,7 @@ static struct clk_fixed_factor gpll0_out_main_div2 = {

static struct clk_alpha_pll_postdiv gpll0 = {
	.offset = 0x21000,
	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
	.clkr.hw.init = &(struct clk_init_data){
		.name = "gpll0",
		.parent_names = (const char *[]){
+4 −0
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ static struct clk_fixed_factor xo = {

static struct clk_alpha_pll gpll0_early = {
	.offset = 0x00000,
	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
	.clkr = {
		.enable_reg = 0x1480,
		.enable_mask = BIT(0),
@@ -88,6 +89,7 @@ static struct clk_alpha_pll gpll0_early = {

static struct clk_alpha_pll_postdiv gpll0 = {
	.offset = 0x00000,
	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
	.clkr.hw.init = &(struct clk_init_data)
	{
		.name = "gpll0",
@@ -99,6 +101,7 @@ static struct clk_alpha_pll_postdiv gpll0 = {

static struct clk_alpha_pll gpll4_early = {
	.offset = 0x1dc0,
	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
	.clkr = {
		.enable_reg = 0x1480,
		.enable_mask = BIT(4),
@@ -114,6 +117,7 @@ static struct clk_alpha_pll gpll4_early = {

static struct clk_alpha_pll_postdiv gpll4 = {
	.offset = 0x1dc0,
	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
	.clkr.hw.init = &(struct clk_init_data)
	{
		.name = "gpll4",
Loading