Commit 1c8e6004 authored by Tomeu Vizoso's avatar Tomeu Vizoso Committed by Michael Turquette

clk: Add rate constraints to clocks

Adds a way for clock consumers to set maximum and minimum rates. This
can be used for thermal drivers to set minimum rates, or by misc.
drivers to set maximum rates to assure a minimum performance level.

Changes the signature of the determine_rate callback by adding the
parameters min_rate and max_rate.
Signed-off-by: default avatarTomeu Vizoso <tomeu.vizoso@collabora.com>
Signed-off-by: default avatarStephen Boyd <sboyd@codeaurora.org>
[sboyd@codeaurora.org: set req_rate in __clk_init]
Signed-off-by: default avatarMichael Turquette <mturquette@linaro.org>
[mturquette@linaro.org: min/max rate for sun6i_ahb1_clk_determine_rate
                        migrated clk-private.h changes to clk.c]
parent b09d6d99
...@@ -73,6 +73,8 @@ the operations defined in clk.h: ...@@ -73,6 +73,8 @@ the operations defined in clk.h:
unsigned long *parent_rate); unsigned long *parent_rate);
long (*determine_rate)(struct clk_hw *hw, long (*determine_rate)(struct clk_hw *hw,
unsigned long rate, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk); struct clk_hw **best_parent_clk);
int (*set_parent)(struct clk_hw *hw, u8 index); int (*set_parent)(struct clk_hw *hw, u8 index);
......
...@@ -473,6 +473,8 @@ void omap3_noncore_dpll_disable(struct clk_hw *hw) ...@@ -473,6 +473,8 @@ void omap3_noncore_dpll_disable(struct clk_hw *hw)
* in failure. * in failure.
*/ */
long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, unsigned long rate, long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk) struct clk_hw **best_parent_clk)
{ {
......
...@@ -222,6 +222,8 @@ long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, ...@@ -222,6 +222,8 @@ long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
* in failure. * in failure.
*/ */
long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long rate, long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk) struct clk_hw **best_parent_clk)
{ {
......
...@@ -373,6 +373,8 @@ static long alchemy_calc_div(unsigned long rate, unsigned long prate, ...@@ -373,6 +373,8 @@ static long alchemy_calc_div(unsigned long rate, unsigned long prate,
} }
static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate, static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk, struct clk_hw **best_parent_clk,
int scale, int maxdiv) int scale, int maxdiv)
...@@ -546,6 +548,8 @@ static unsigned long alchemy_clk_fgv1_recalc(struct clk_hw *hw, ...@@ -546,6 +548,8 @@ static unsigned long alchemy_clk_fgv1_recalc(struct clk_hw *hw,
} }
static long alchemy_clk_fgv1_detr(struct clk_hw *hw, unsigned long rate, static long alchemy_clk_fgv1_detr(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk) struct clk_hw **best_parent_clk)
{ {
...@@ -678,6 +682,8 @@ static unsigned long alchemy_clk_fgv2_recalc(struct clk_hw *hw, ...@@ -678,6 +682,8 @@ static unsigned long alchemy_clk_fgv2_recalc(struct clk_hw *hw,
} }
static long alchemy_clk_fgv2_detr(struct clk_hw *hw, unsigned long rate, static long alchemy_clk_fgv2_detr(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk) struct clk_hw **best_parent_clk)
{ {
...@@ -897,6 +903,8 @@ static int alchemy_clk_csrc_setr(struct clk_hw *hw, unsigned long rate, ...@@ -897,6 +903,8 @@ static int alchemy_clk_csrc_setr(struct clk_hw *hw, unsigned long rate,
} }
static long alchemy_clk_csrc_detr(struct clk_hw *hw, unsigned long rate, static long alchemy_clk_csrc_detr(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk) struct clk_hw **best_parent_clk)
{ {
......
...@@ -56,6 +56,8 @@ static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw, ...@@ -56,6 +56,8 @@ static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
static long clk_programmable_determine_rate(struct clk_hw *hw, static long clk_programmable_determine_rate(struct clk_hw *hw,
unsigned long rate, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_hw) struct clk_hw **best_parent_hw)
{ {
......
...@@ -1032,6 +1032,8 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -1032,6 +1032,8 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate,
} }
static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, struct clk_hw **best_parent) unsigned long *best_parent_rate, struct clk_hw **best_parent)
{ {
struct kona_clk *bcm_clk = to_kona_clk(hw); struct kona_clk *bcm_clk = to_kona_clk(hw);
......
...@@ -56,6 +56,8 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw, ...@@ -56,6 +56,8 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw,
} }
static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_p) struct clk_hw **best_parent_p)
{ {
...@@ -73,7 +75,9 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, ...@@ -73,7 +75,9 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
if (rate_hw && rate_ops && rate_ops->determine_rate) { if (rate_hw && rate_ops && rate_ops->determine_rate) {
rate_hw->clk = hw->clk; rate_hw->clk = hw->clk;
return rate_ops->determine_rate(rate_hw, rate, best_parent_rate, return rate_ops->determine_rate(rate_hw, rate, min_rate,
max_rate,
best_parent_rate,
best_parent_p); best_parent_p);
} else if (rate_hw && rate_ops && rate_ops->round_rate && } else if (rate_hw && rate_ops && rate_ops->round_rate &&
mux_hw && mux_ops && mux_ops->set_parent) { mux_hw && mux_ops && mux_ops->set_parent) {
...@@ -117,7 +121,8 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, ...@@ -117,7 +121,8 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
return best_rate; return best_rate;
} else if (mux_hw && mux_ops && mux_ops->determine_rate) { } else if (mux_hw && mux_ops && mux_ops->determine_rate) {
mux_hw->clk = hw->clk; mux_hw->clk = hw->clk;
return mux_ops->determine_rate(mux_hw, rate, best_parent_rate, return mux_ops->determine_rate(mux_hw, rate, min_rate,
max_rate, best_parent_rate,
best_parent_p); best_parent_p);
} else { } else {
pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n"); pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n");
......
...@@ -42,8 +42,6 @@ static unsigned long clk_core_get_rate(struct clk_core *clk); ...@@ -42,8 +42,6 @@ static unsigned long clk_core_get_rate(struct clk_core *clk);
static int clk_core_get_phase(struct clk_core *clk); static int clk_core_get_phase(struct clk_core *clk);
static bool clk_core_is_prepared(struct clk_core *clk); static bool clk_core_is_prepared(struct clk_core *clk);
static bool clk_core_is_enabled(struct clk_core *clk); static bool clk_core_is_enabled(struct clk_core *clk);
static unsigned long clk_core_round_rate_nolock(struct clk_core *clk,
unsigned long rate);
static struct clk_core *clk_core_lookup(const char *name); static struct clk_core *clk_core_lookup(const char *name);
/*** private data structures ***/ /*** private data structures ***/
...@@ -59,6 +57,7 @@ struct clk_core { ...@@ -59,6 +57,7 @@ struct clk_core {
u8 num_parents; u8 num_parents;
u8 new_parent_index; u8 new_parent_index;
unsigned long rate; unsigned long rate;
unsigned long req_rate;
unsigned long new_rate; unsigned long new_rate;
struct clk_core *new_parent; struct clk_core *new_parent;
struct clk_core *new_child; struct clk_core *new_child;
...@@ -70,6 +69,7 @@ struct clk_core { ...@@ -70,6 +69,7 @@ struct clk_core {
struct hlist_head children; struct hlist_head children;
struct hlist_node child_node; struct hlist_node child_node;
struct hlist_node debug_node; struct hlist_node debug_node;
struct hlist_head clks;
unsigned int notifier_count; unsigned int notifier_count;
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
struct dentry *dentry; struct dentry *dentry;
...@@ -81,6 +81,9 @@ struct clk { ...@@ -81,6 +81,9 @@ struct clk {
struct clk_core *core; struct clk_core *core;
const char *dev_id; const char *dev_id;
const char *con_id; const char *con_id;
unsigned long min_rate;
unsigned long max_rate;
struct hlist_node child_node;
}; };
/*** locking ***/ /*** locking ***/
...@@ -783,6 +786,8 @@ static bool mux_is_better_rate(unsigned long rate, unsigned long now, ...@@ -783,6 +786,8 @@ static bool mux_is_better_rate(unsigned long rate, unsigned long now,
static long static long
clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate, clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_p, struct clk_hw **best_parent_p,
unsigned long flags) unsigned long flags)
...@@ -795,7 +800,8 @@ clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate, ...@@ -795,7 +800,8 @@ clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate,
if (core->flags & CLK_SET_RATE_NO_REPARENT) { if (core->flags & CLK_SET_RATE_NO_REPARENT) {
parent = core->parent; parent = core->parent;
if (core->flags & CLK_SET_RATE_PARENT) if (core->flags & CLK_SET_RATE_PARENT)
best = clk_core_round_rate_nolock(parent, rate); best = __clk_determine_rate(parent->hw, rate,
min_rate, max_rate);
else if (parent) else if (parent)
best = clk_core_get_rate_nolock(parent); best = clk_core_get_rate_nolock(parent);
else else
...@@ -810,7 +816,9 @@ clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate, ...@@ -810,7 +816,9 @@ clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate,
if (!parent) if (!parent)
continue; continue;
if (core->flags & CLK_SET_RATE_PARENT) if (core->flags & CLK_SET_RATE_PARENT)
parent_rate = clk_core_round_rate_nolock(parent, rate); parent_rate = __clk_determine_rate(parent->hw, rate,
min_rate,
max_rate);
else else
parent_rate = clk_core_get_rate_nolock(parent); parent_rate = clk_core_get_rate_nolock(parent);
if (mux_is_better_rate(rate, parent_rate, best, flags)) { if (mux_is_better_rate(rate, parent_rate, best, flags)) {
...@@ -834,25 +842,47 @@ struct clk *__clk_lookup(const char *name) ...@@ -834,25 +842,47 @@ struct clk *__clk_lookup(const char *name)
return !core ? NULL : core->hw->clk; return !core ? NULL : core->hw->clk;
} }
static void clk_core_get_boundaries(struct clk_core *clk,
unsigned long *min_rate,
unsigned long *max_rate)
{
struct clk *clk_user;
*min_rate = 0;
*max_rate = ULONG_MAX;
hlist_for_each_entry(clk_user, &clk->clks, child_node)
*min_rate = max(*min_rate, clk_user->min_rate);
hlist_for_each_entry(clk_user, &clk->clks, child_node)
*max_rate = min(*max_rate, clk_user->max_rate);
}
/* /*
* Helper for finding best parent to provide a given frequency. This can be used * Helper for finding best parent to provide a given frequency. This can be used
* directly as a determine_rate callback (e.g. for a mux), or from a more * directly as a determine_rate callback (e.g. for a mux), or from a more
* complex clock that may combine a mux with other operations. * complex clock that may combine a mux with other operations.
*/ */
long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_p) struct clk_hw **best_parent_p)
{ {
return clk_mux_determine_rate_flags(hw, rate, best_parent_rate, return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate,
best_parent_rate,
best_parent_p, 0); best_parent_p, 0);
} }
EXPORT_SYMBOL_GPL(__clk_mux_determine_rate); EXPORT_SYMBOL_GPL(__clk_mux_determine_rate);
long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate, long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_p) struct clk_hw **best_parent_p)
{ {
return clk_mux_determine_rate_flags(hw, rate, best_parent_rate, return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate,
best_parent_rate,
best_parent_p, best_parent_p,
CLK_MUX_ROUND_CLOSEST); CLK_MUX_ROUND_CLOSEST);
} }
...@@ -1068,7 +1098,9 @@ int clk_enable(struct clk *clk) ...@@ -1068,7 +1098,9 @@ int clk_enable(struct clk *clk)
EXPORT_SYMBOL_GPL(clk_enable); EXPORT_SYMBOL_GPL(clk_enable);
static unsigned long clk_core_round_rate_nolock(struct clk_core *clk, static unsigned long clk_core_round_rate_nolock(struct clk_core *clk,
unsigned long rate) unsigned long rate,
unsigned long min_rate,
unsigned long max_rate)
{ {
unsigned long parent_rate = 0; unsigned long parent_rate = 0;
struct clk_core *parent; struct clk_core *parent;
...@@ -1083,16 +1115,40 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *clk, ...@@ -1083,16 +1115,40 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *clk,
if (clk->ops->determine_rate) { if (clk->ops->determine_rate) {
parent_hw = parent ? parent->hw : NULL; parent_hw = parent ? parent->hw : NULL;
return clk->ops->determine_rate(clk->hw, rate, &parent_rate, return clk->ops->determine_rate(clk->hw, rate,
&parent_hw); min_rate, max_rate,
&parent_rate, &parent_hw);
} else if (clk->ops->round_rate) } else if (clk->ops->round_rate)
return clk->ops->round_rate(clk->hw, rate, &parent_rate); return clk->ops->round_rate(clk->hw, rate, &parent_rate);
else if (clk->flags & CLK_SET_RATE_PARENT) else if (clk->flags & CLK_SET_RATE_PARENT)
return clk_core_round_rate_nolock(clk->parent, rate); return clk_core_round_rate_nolock(clk->parent, rate, min_rate,
max_rate);
else else
return clk->rate; return clk->rate;
} }
/**
* __clk_determine_rate - get the closest rate actually supported by a clock
* @hw: determine the rate of this clock
* @rate: target rate
* @min_rate: returned rate must be greater than this rate
* @max_rate: returned rate must be less than this rate
*
* Caller must hold prepare_lock. Useful for clk_ops such as .set_rate and
* .determine_rate.
*/
unsigned long __clk_determine_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long min_rate,
unsigned long max_rate)
{
if (!hw)
return 0;
return clk_core_round_rate_nolock(hw->core, rate, min_rate, max_rate);
}
EXPORT_SYMBOL_GPL(__clk_determine_rate);
/** /**
* __clk_round_rate - round the given rate for a clk * __clk_round_rate - round the given rate for a clk
* @clk: round the rate of this clock * @clk: round the rate of this clock
...@@ -1102,10 +1158,15 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *clk, ...@@ -1102,10 +1158,15 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *clk,
*/ */
unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
{ {
unsigned long min_rate;
unsigned long max_rate;
if (!clk) if (!clk)
return 0; return 0;
return clk_core_round_rate_nolock(clk->core, rate); clk_core_get_boundaries(clk->core, &min_rate, &max_rate);
return clk_core_round_rate_nolock(clk->core, rate, min_rate, max_rate);
} }
EXPORT_SYMBOL_GPL(__clk_round_rate); EXPORT_SYMBOL_GPL(__clk_round_rate);
...@@ -1126,7 +1187,7 @@ long clk_round_rate(struct clk *clk, unsigned long rate) ...@@ -1126,7 +1187,7 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
return 0; return 0;
clk_prepare_lock(); clk_prepare_lock();
ret = clk_core_round_rate_nolock(clk->core, rate); ret = __clk_round_rate(clk, rate);
clk_prepare_unlock(); clk_prepare_unlock();
return ret; return ret;
...@@ -1517,6 +1578,8 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *clk, ...@@ -1517,6 +1578,8 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *clk,
struct clk_hw *parent_hw; struct clk_hw *parent_hw;
unsigned long best_parent_rate = 0; unsigned long best_parent_rate = 0;
unsigned long new_rate; unsigned long new_rate;
unsigned long min_rate;
unsigned long max_rate;
int p_index = 0; int p_index = 0;
/* sanity */ /* sanity */
...@@ -1528,16 +1591,22 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *clk, ...@@ -1528,16 +1591,22 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *clk,
if (parent) if (parent)
best_parent_rate = parent->rate; best_parent_rate = parent->rate;
clk_core_get_boundaries(clk, &min_rate, &max_rate);
/* find the closest rate and parent clk/rate */ /* find the closest rate and parent clk/rate */
if (clk->ops->determine_rate) { if (clk->ops->determine_rate) {
parent_hw = parent ? parent->hw : NULL; parent_hw = parent ? parent->hw : NULL;
new_rate = clk->ops->determine_rate(clk->hw, rate, new_rate = clk->ops->determine_rate(clk->hw, rate,
min_rate,
max_rate,
&best_parent_rate, &best_parent_rate,
&parent_hw); &parent_hw);
parent = parent_hw ? parent_hw->core : NULL; parent = parent_hw ? parent_hw->core : NULL;
} else if (clk->ops->round_rate) { } else if (clk->ops->round_rate) {
new_rate = clk->ops->round_rate(clk->hw, rate, new_rate = clk->ops->round_rate(clk->hw, rate,
&best_parent_rate); &best_parent_rate);
if (new_rate < min_rate || new_rate > max_rate)
return NULL;
} else if (!parent || !(clk->flags & CLK_SET_RATE_PARENT)) { } else if (!parent || !(clk->flags & CLK_SET_RATE_PARENT)) {
/* pass-through clock without adjustable parent */ /* pass-through clock without adjustable parent */
clk->new_rate = clk->rate; clk->new_rate = clk->rate;
...@@ -1675,6 +1744,45 @@ static void clk_change_rate(struct clk_core *clk) ...@@ -1675,6 +1744,45 @@ static void clk_change_rate(struct clk_core *clk)
clk_change_rate(clk->new_child); clk_change_rate(clk->new_child);
} }
static int clk_core_set_rate_nolock(struct clk_core *clk,
unsigned long req_rate)
{
struct clk_core *top, *fail_clk;
unsigned long rate = req_rate;
int ret = 0;
if (!clk)
return 0;
/* bail early if nothing to do */
if (rate == clk_core_get_rate_nolock(clk))
return 0;
if ((clk->flags & CLK_SET_RATE_GATE) && clk->prepare_count)
return -EBUSY;
/* calculate new rates and get the topmost changed clock */
top = clk_calc_new_rates(clk, rate);
if (!top)
return -EINVAL;
/* notify that we are about to change rates */
fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
if (fail_clk) {
pr_debug("%s: failed to set %s rate\n", __func__,
fail_clk->name);
clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
return -EBUSY;
}
/* change the rates */
clk_change_rate(top);
clk->req_rate = req_rate;
return ret;
}
/** /**
* clk_set_rate - specify a new rate for clk * clk_set_rate - specify a new rate for clk
* @clk: the clk whose rate is being changed * @clk: the clk whose rate is being changed
...@@ -1698,8 +1806,7 @@ static void clk_change_rate(struct clk_core *clk) ...@@ -1698,8 +1806,7 @@ static void clk_change_rate(struct clk_core *clk)
*/ */
int clk_set_rate(struct clk *clk, unsigned long rate) int clk_set_rate(struct clk *clk, unsigned long rate)
{ {
struct clk_core *top, *fail_clk; int ret;
int ret = 0;
if (!clk) if (!clk)
return 0; return 0;
...@@ -1707,42 +1814,81 @@ int clk_set_rate(struct clk *clk, unsigned long rate) ...@@ -1707,42 +1814,81 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
/* prevent racing with updates to the clock topology */ /* prevent racing with updates to the clock topology */
clk_prepare_lock(); clk_prepare_lock();
/* bail early if nothing to do */ ret = clk_core_set_rate_nolock(clk->core, rate);
if (rate == clk_get_rate(clk))
goto out;
if ((clk->core->flags & CLK_SET_RATE_GATE) && clk_prepare_unlock();
clk->core->prepare_count) {
ret = -EBUSY;
goto out;
}
/* calculate new rates and get the topmost changed clock */ return ret;
top = clk_calc_new_rates(clk->core, rate); }
if (!top) { EXPORT_SYMBOL_GPL(clk_set_rate);
ret = -EINVAL;
goto out;
}
/* notify that we are about to change rates */ /**
fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE); * clk_set_rate_range - set a rate range for a clock source
if (fail_clk) { * @clk: clock source
pr_debug("%s: failed to set %s rate\n", __func__, * @min: desired minimum clock rate in Hz, inclusive
fail_clk->name); * @max: desired maximum clock rate in Hz, inclusive
clk_propagate_rate_change(top, ABORT_RATE_CHANGE); *
ret = -EBUSY; * Returns success (0) or negative errno.
goto out; */
int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)
{
int ret = 0;
if (!clk)
return 0;
if (min > max) {
pr_err("%s: clk %s dev %s con %s: invalid range [%lu, %lu]\n",
__func__, clk->core->name, clk->dev_id, clk->con_id,
min, max);
return -EINVAL;
} }
/* change the rates */ clk_prepare_lock();
clk_change_rate(top);
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);
}
out:
clk_prepare_unlock(); clk_prepare_unlock();
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(clk_set_rate); EXPORT_SYMBOL_GPL(clk_set_rate_range);
/**
* clk_set_min_rate - set a minimum clock rate for a clock source
* @clk: clock source
* @rate: desired minimum clock rate in Hz, inclusive
*
* Returns success (0) or negative errno.
*/
int clk_set_min_rate(struct clk *clk, unsigned long rate)
{
if (!clk)
return 0;
return clk_set_rate_range(clk, rate, clk->max_rate);
}
EXPORT_SYMBOL_GPL(clk_set_min_rate);
/**
* clk_set_max_rate - set a maximum clock rate for a clock source
* @clk: clock source
* @rate: desired maximum clock rate in Hz, inclusive
*
* Returns success (0) or negative errno.
*/
int clk_set_max_rate(struct clk *clk, unsigned long rate)
{
if (!clk)
return 0;
return clk_set_rate_range(clk, clk->min_rate, rate);
}
EXPORT_SYMBOL_GPL(clk_set_max_rate);
/** /**
* clk_get_parent - return the parent of a clk * clk_get_parent - return the parent of a clk
...@@ -2038,6 +2184,7 @@ static int __clk_init(struct device *dev, struct clk *clk_user) ...@@ -2038,6 +2184,7 @@ static int __clk_init(struct device *dev, struct clk *clk_user)
struct clk_core *orphan; struct clk_core *orphan;
struct hlist_node *tmp2; struct hlist_node *tmp2;
struct clk_core *clk; struct clk_core *clk;
unsigned long rate;
if (!clk_user) if (!clk_user)
return -EINVAL; return -EINVAL;
...@@ -2162,12 +2309,13 @@ static int __clk_init(struct device *dev, struct clk *clk_user) ...@@ -2162,12 +2309,13 @@ static int __clk_init(struct device *dev, struct clk *clk_user)
* then rate is set to zero. * then rate is set to zero.
*/ */
if (clk->ops->recalc_rate) if (clk->ops->recalc_rate)
clk->rate = clk->ops->recalc_rate(clk->hw, rate = clk->ops->recalc_rate(clk->hw,
clk_core_get_rate_nolock(clk->parent)); clk_core_get_rate_nolock(clk->parent));
else if (clk->parent) else if (clk->parent)
clk->rate = clk->parent->rate; rate = clk->parent->rate;
else else
clk->rate = 0; rate = 0;
clk->rate = clk->req_rate = rate;
/* /*
* walk the list of orphan clocks and reparent any that are children of * walk the list of orphan clocks and reparent any that are children of
...@@ -2225,10 +2373,24 @@ struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id, ...@@ -2225,10 +2373,24 @@ struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
clk->core = hw->core; clk->core = hw->core;
clk->dev_id = dev_id; clk->dev_id = dev_id;
clk->con_id = con_id; clk->con_id = con_id;
clk->max_rate = ULONG_MAX;
clk_prepare_lock();
hlist_add_head(&clk->child_node, &hw->core->clks);
clk_prepare_unlock();
return clk; return clk;
} }
static void __clk_free_clk(struct clk *clk)
{
clk_prepare_lock();
hlist_del(&clk->child_node);
clk_prepare_unlock();
kfree(clk);
}
/** /**
* clk_register - allocate a new clock, register it and return an opaque cookie * clk_register - allocate a new clock, register it and return an opaque cookie
* @dev: device that is registering this clock * @dev: device that is registering this clock
...@@ -2288,6 +2450,8 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) ...@@ -2288,6 +2450,8 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
} }
} }
INIT_HLIST_HEAD(&clk->clks);
hw->clk = __clk_create_clk(hw, NULL, NULL); hw->clk = __clk_create_clk(hw, NULL, NULL);
if (IS_ERR(hw->clk)) { if (IS_ERR(hw->clk)) {
pr_err("%s: could not allocate per-user clk\n", __func__); pr_err("%s: could not allocate per-user clk\n", __func__);
...@@ -2299,8 +2463,9 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) ...@@ -2299,8 +2463,9 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
if (!ret) if (!ret)
return hw->clk; return hw->clk;
kfree(hw->clk); __clk_free_clk(hw->clk);
hw->clk = NULL; hw->clk = NULL;
fail_parent_names_copy: fail_parent_names_copy:
while (--i >= 0) while (--i >= 0)
kfree(clk->parent_names[i]); kfree(clk->parent_names[i]);
...@@ -2489,25 +2654,24 @@ int __clk_get(struct clk *clk) ...@@ -2489,25 +2654,24 @@ int __clk_get(struct clk *clk)
return 1; return 1;
} }
static void clk_core_put(struct clk_core *core) void __clk_put(struct clk *clk)
{ {
struct module *owner; struct module *owner;
owner = core->owner; if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
return;
clk_prepare_lock(); clk_prepare_lock();
kref_put(&core->ref, __clk_release);
hlist_del(&clk->child_node);
clk_core_set_rate_nolock(clk->core, clk->core->req_rate);
owner = clk->core->owner;
kref_put(&clk->core->ref, __clk_release);
clk_prepare_unlock(); clk_prepare_unlock();
module_put(owner); module_put(owner);
}
void __clk_put(struct clk *clk)
{
if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
return;
clk_core_put(clk->core);
kfree(clk); kfree(clk);
} }
......
...@@ -295,6 +295,8 @@ static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw, ...@@ -295,6 +295,8 @@ static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw,
} }
static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate, static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_p) struct clk_hw **best_parent_p)
{ {
......
...@@ -202,6 +202,8 @@ static int _set_rate(struct mmp_clk_mix *mix, u32 mux_val, u32 div_val, ...@@ -202,6 +202,8 @@ static int _set_rate(struct mmp_clk_mix *mix, u32 mux_val, u32 div_val,
} }
static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk) struct clk_hw **best_parent_clk)
{ {
......
...@@ -141,6 +141,7 @@ struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate) ...@@ -141,6 +141,7 @@ struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate)
static long static long
clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate, clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p) unsigned long *p_rate, struct clk_hw **p)
{ {
struct clk_pll *pll = to_clk_pll(hw); struct clk_pll *pll = to_clk_pll(hw);
......
...@@ -368,6 +368,7 @@ clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) ...@@ -368,6 +368,7 @@ clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
static long _freq_tbl_determine_rate(struct clk_hw *hw, static long _freq_tbl_determine_rate(struct clk_hw *hw,
const struct freq_tbl *f, unsigned long rate, const struct freq_tbl *f, unsigned long rate,
unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p_hw) unsigned long *p_rate, struct clk_hw **p_hw)
{ {
unsigned long clk_flags; unsigned long clk_flags;
...@@ -397,22 +398,27 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw, ...@@ -397,22 +398,27 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
} }
static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p) unsigned long *p_rate, struct clk_hw **p)
{ {
struct clk_rcg *rcg = to_clk_rcg(hw); struct clk_rcg *rcg = to_clk_rcg(hw);
return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p); return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate,
max_rate, p_rate, p);
} }
static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p) unsigned long *p_rate, struct clk_hw **p)
{ {
struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p); return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate,
max_rate, p_rate, p);
} }
static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate, static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p_hw) unsigned long *p_rate, struct clk_hw **p_hw)
{ {
struct clk_rcg *rcg = to_clk_rcg(hw); struct clk_rcg *rcg = to_clk_rcg(hw);
......
...@@ -208,6 +208,7 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw, ...@@ -208,6 +208,7 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
} }
static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate, static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p) unsigned long *p_rate, struct clk_hw **p)
{ {
struct clk_rcg2 *rcg = to_clk_rcg2(hw); struct clk_rcg2 *rcg = to_clk_rcg2(hw);
...@@ -361,6 +362,8 @@ static int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw, ...@@ -361,6 +362,8 @@ static int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw,
} }
static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p) unsigned long *p_rate, struct clk_hw **p)
{ {
struct clk_rcg2 *rcg = to_clk_rcg2(hw); struct clk_rcg2 *rcg = to_clk_rcg2(hw);
...@@ -412,6 +415,7 @@ const struct clk_ops clk_edp_pixel_ops = { ...@@ -412,6 +415,7 @@ const struct clk_ops clk_edp_pixel_ops = {
EXPORT_SYMBOL_GPL(clk_edp_pixel_ops); EXPORT_SYMBOL_GPL(clk_edp_pixel_ops);
static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate, static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p_hw) unsigned long *p_rate, struct clk_hw **p_hw)
{ {
struct clk_rcg2 *rcg = to_clk_rcg2(hw); struct clk_rcg2 *rcg = to_clk_rcg2(hw);
...@@ -476,6 +480,8 @@ static const struct frac_entry frac_table_pixel[] = { ...@@ -476,6 +480,8 @@ static const struct frac_entry frac_table_pixel[] = {
}; };
static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p) unsigned long *p_rate, struct clk_hw **p)
{ {
struct clk_rcg2 *rcg = to_clk_rcg2(hw); struct clk_rcg2 *rcg = to_clk_rcg2(hw);
......
...@@ -80,6 +80,8 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -80,6 +80,8 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate,
} }
static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate, static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_p) struct clk_hw **best_parent_p)
{ {
......
...@@ -45,6 +45,8 @@ static unsigned long ar100_recalc_rate(struct clk_hw *hw, ...@@ -45,6 +45,8 @@ static unsigned long ar100_recalc_rate(struct clk_hw *hw,
} }
static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate, static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk) struct clk_hw **best_parent_clk)
{ {
......
...@@ -119,6 +119,8 @@ static long sun6i_ahb1_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp, ...@@ -119,6 +119,8 @@ static long sun6i_ahb1_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp,
} }
static long sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, unsigned long rate, static long sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk) struct clk_hw **best_parent_clk)
{ {
......
...@@ -175,9 +175,12 @@ struct clk_ops { ...@@ -175,9 +175,12 @@ struct clk_ops {
unsigned long parent_rate); unsigned long parent_rate);
long (*round_rate)(struct clk_hw *hw, unsigned long rate, long (*round_rate)(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate); unsigned long *parent_rate);
long (*determine_rate)(struct clk_hw *hw, unsigned long rate, long (*determine_rate)(struct clk_hw *hw,
unsigned long *best_parent_rate, unsigned long rate,
struct clk_hw **best_parent_hw); unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_hw);
int (*set_parent)(struct clk_hw *hw, u8 index); int (*set_parent)(struct clk_hw *hw, u8 index);
u8 (*get_parent)(struct clk_hw *hw); u8 (*get_parent)(struct clk_hw *hw);
int (*set_rate)(struct clk_hw *hw, unsigned long rate, int (*set_rate)(struct clk_hw *hw, unsigned long rate,
...@@ -573,9 +576,17 @@ bool __clk_is_prepared(struct clk *clk); ...@@ -573,9 +576,17 @@ bool __clk_is_prepared(struct clk *clk);
bool __clk_is_enabled(struct clk *clk); bool __clk_is_enabled(struct clk *clk);
struct clk *__clk_lookup(const char *name); struct clk *__clk_lookup(const char *name);
long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_p); struct clk_hw **best_parent_p);
unsigned long __clk_determine_rate(struct clk_hw *core,
unsigned long rate,
unsigned long min_rate,
unsigned long max_rate);
long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate, long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_p); struct clk_hw **best_parent_p);
......
...@@ -313,6 +313,34 @@ int clk_set_rate(struct clk *clk, unsigned long rate); ...@@ -313,6 +313,34 @@ int clk_set_rate(struct clk *clk, unsigned long rate);
*/ */
bool clk_has_parent(struct clk *clk, struct clk *parent); bool clk_has_parent(struct clk *clk, struct clk *parent);
/**
* clk_set_rate_range - set a rate range for a clock source
* @clk: clock source
* @min: desired minimum clock rate in Hz, inclusive
* @max: desired maximum clock rate in Hz, inclusive
*
* Returns success (0) or negative errno.
*/
int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max);
/**
* clk_set_min_rate - set a minimum clock rate for a clock source
* @clk: clock source
* @rate: desired minimum clock rate in Hz, inclusive
*
* Returns success (0) or negative errno.
*/
int clk_set_min_rate(struct clk *clk, unsigned long rate);
/**
* clk_set_max_rate - set a maximum clock rate for a clock source
* @clk: clock source
* @rate: desired maximum clock rate in Hz, inclusive
*
* Returns success (0) or negative errno.
*/
int clk_set_max_rate(struct clk *clk, unsigned long rate);
/** /**
* clk_set_parent - set the parent clock source for this clock * clk_set_parent - set the parent clock source for this clock
* @clk: clock source * @clk: clock source
......
...@@ -271,6 +271,8 @@ int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw, ...@@ -271,6 +271,8 @@ int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw,
u8 index); u8 index);
long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, long omap3_noncore_dpll_determine_rate(struct clk_hw *hw,
unsigned long rate, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk); struct clk_hw **best_parent_clk);
unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
...@@ -280,6 +282,8 @@ long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, ...@@ -280,6 +282,8 @@ long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
unsigned long *parent_rate); unsigned long *parent_rate);
long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw,
unsigned long rate, unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk); struct clk_hw **best_parent_clk);
u8 omap2_init_dpll_parent(struct clk_hw *hw); u8 omap2_init_dpll_parent(struct clk_hw *hw);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment