return fail_clk;
}
+static int clk_core_set_rate_nolock(struct clk_core *core,
+ unsigned long req_rate);
+
/*
* walk down a subtree and set the new rates notifying the rate
* change on the way
else if (core->parent)
best_parent_rate = core->parent->rate;
+ if (core->flags & CLK_SET_RATE_UNGATE) {
+ unsigned long flags;
+
+ clk_core_prepare(core);
+ flags = clk_enable_lock();
+ clk_core_enable(core);
+ clk_enable_unlock(flags);
+ }
+
if (core->new_parent && core->new_parent != core->parent) {
old_parent = __clk_set_parent_before(core, core->new_parent);
trace_clk_set_parent(core, core->new_parent);
core->rate = clk_recalc(core, best_parent_rate);
+ if (core->flags & CLK_SET_RATE_UNGATE) {
+ unsigned long flags;
+
+ flags = clk_enable_lock();
+ clk_core_disable(core);
+ clk_enable_unlock(flags);
+ clk_core_unprepare(core);
+ }
+
if (core->notifier_count && old_rate != core->rate)
__clk_notify(core, POST_RATE_CHANGE, old_rate, core->rate);
/* handle the new child who might not be in core->children yet */
if (core->new_child)
clk_change_rate(core->new_child);
+
+ /* handle a changed clock that needs to readjust its rate */
+ if (core->flags & CLK_KEEP_REQ_RATE && core->req_rate
+ && core->new_rate != old_rate
+ && core->new_rate != core->req_rate)
+ clk_core_set_rate_nolock(core, core->req_rate);
}
static int clk_core_set_rate_nolock(struct clk_core *core,
return 0;
/* bail early if nothing to do */
- if (rate == clk_core_get_rate_nolock(core))
+ if (rate == clk_core_get_rate_nolock(core)) {
+ core->req_rate = req_rate;
return 0;
+ }
if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count)
return -EBUSY;
return -EBUSY;
}
+ core->req_rate = req_rate;
+
/* change the rates */
clk_change_rate(top);
- core->req_rate = req_rate;
-
return ret;
}
clk_prepare_lock();
if (min != clk->min_rate || max != clk->max_rate) {
+ unsigned long rate = clk->core->req_rate;
+
+ if (!rate)
+ rate = clk->core->rate;
+
clk->min_rate = min;
clk->max_rate = max;
- ret = clk_core_set_rate_nolock(clk->core, clk->core->req_rate);
+ ret = clk_core_set_rate_nolock(clk->core, rate);
}
clk_prepare_unlock();
clk_prepare_lock();
+ /* bail early if nothing to do */
+ if (degrees == clk->core->phase)
+ goto out;
+
trace_clk_set_phase(clk->core, degrees);
if (clk->core->ops->set_phase)
if (!ret)
clk->core->phase = degrees;
+out:
clk_prepare_unlock();
return ret;
rate = core->parent->rate;
else
rate = 0;
- core->rate = core->req_rate = rate;
+ core->rate = rate;
/*
* walk the list of orphan clocks and reparent any that are children of
void __clk_put(struct clk *clk)
{
+ unsigned long rate;
struct module *owner;
if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
clk_prepare_lock();
hlist_del(&clk->clks_node);
- if (clk->min_rate > clk->core->req_rate ||
- clk->max_rate < clk->core->req_rate)
- clk_core_set_rate_nolock(clk->core, clk->core->req_rate);
+
+ rate = clk->core->req_rate;
+ if (!rate)
+ rate = clk->core->rate;
+
+ if (clk->min_rate > rate || clk->max_rate < rate)
+ clk_core_set_rate_nolock(clk->core, rate);
owner = clk->core->owner;
kref_put(&clk->core->ref, __clk_release);