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
This commit is contained in:
@@ -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,
|
||||
struct clk_rate_request *req)
|
||||
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,12 +2019,46 @@ 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) {
|
||||
clk->min_rate = min;
|
||||
clk->max_rate = max;
|
||||
ret = clk_core_set_rate_nolock(clk->core, clk->core->req_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;
|
||||
|
||||
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();
|
||||
|
||||
return ret;
|
||||
@@ -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 @@ out:
|
||||
*/
|
||||
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 @@ fail_parent_names_copy:
|
||||
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)
|
||||
|
Reference in New Issue
Block a user