Hi Mike,
On Sat, Mar 03, 2012 at 12:29:00AM -0800, Mike Turquette wrote:
[snip]
+static void __clk_disable(struct clk *clk) +{
- if (!clk)
return;
- if (WARN_ON(clk->enable_count == 0))
return;
- if (--clk->enable_count > 0)
return;
- if (clk->ops->disable)
clk->ops->disable(clk->hw);
- if (clk->parent)
__clk_disable(clk->parent);
if __clk_xxx handle NULL clk, we might not need to check parent here? There're also many places that checks parent below.
+}
+/**
- clk_disable - gate a clock
- @clk: the clk being gated
- clk_disable must not sleep, which differentiates it from clk_unprepare. In
- a simple case, clk_disable can be used instead of clk_unprepare to gate a
- clk if the operation is fast and will never sleep. One example is a
- SoC-internal clk which is controlled via simple register writes. In the
- complex case a clk gate operation may require a fast and a slow part. It is
- this reason that clk_unprepare and clk_disable are not mutually exclusive.
- In fact clk_disable must be called before clk_unprepare.
- */
+void clk_disable(struct clk *clk) +{
- unsigned long flags;
- spin_lock_irqsave(&enable_lock, flags);
- __clk_disable(clk);
- spin_unlock_irqrestore(&enable_lock, flags);
+} +EXPORT_SYMBOL_GPL(clk_disable);
+static int __clk_enable(struct clk *clk) +{
- int ret = 0;
- if (!clk)
return 0;
- if (WARN_ON(clk->prepare_count == 0))
return -ESHUTDOWN;
- if (clk->enable_count == 0) {
if (clk->parent)
ret = __clk_enable(clk->parent);
ditto
if (ret)
return ret;
if (clk->ops->enable) {
ret = clk->ops->enable(clk->hw);
if (ret) {
__clk_disable(clk->parent);
it's good case that don't check parent is NULL.
return ret;
}
}
- }
- clk->enable_count++;
- return 0;
+}
+/**
- clk_enable - ungate a clock
- @clk: the clk being ungated
- clk_enable must not sleep, which differentiates it from clk_prepare. In a
- simple case, clk_enable can be used instead of clk_prepare to ungate a clk
- if the operation will never sleep. One example is a SoC-internal clk which
- is controlled via simple register writes. In the complex case a clk ungate
- operation may require a fast and a slow part. It is this reason that
- clk_enable and clk_prepare are not mutually exclusive. In fact clk_prepare
- must be called before clk_enable. Returns 0 on success, -EERROR
- otherwise.
- */
+int clk_enable(struct clk *clk) +{
- unsigned long flags;
- int ret;
- spin_lock_irqsave(&enable_lock, flags);
- ret = __clk_enable(clk);
- spin_unlock_irqrestore(&enable_lock, flags);
- return ret;
+} +EXPORT_SYMBOL_GPL(clk_enable);
+/**
- clk_get_rate - return the rate of clk
- @clk: the clk whose rate is being returned
- Simply returns the cached rate of the clk. Does not query the hardware. If
- clk is NULL then returns -EINVAL.
- */
+unsigned long clk_get_rate(struct clk *clk) +{
- unsigned long rate;
- mutex_lock(&prepare_lock);
- rate = __clk_get_rate(clk);
- mutex_unlock(&prepare_lock);
- return rate;
+} +EXPORT_SYMBOL_GPL(clk_get_rate);
+/**
- __clk_round_rate - round the given rate for a clk
- @clk: round the rate of this clock
- Caller must hold prepare_lock. Useful for clk_ops such as .set_rate
- */
+unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) +{
- if (!clk && !clk->ops->round_rate)
be || ?
return -EINVAL;
- return clk->ops->round_rate(clk->hw, rate, NULL);
+}
+/**
- clk_round_rate - round the given rate for a clk
- @clk: the clk for which we are rounding a rate
- @rate: the rate which is to be rounded
- Takes in a rate as input and rounds it to a rate that the clk can actually
- use which is then returned. If clk doesn't support round_rate operation
- then the rate passed in is returned.
- */
+long clk_round_rate(struct clk *clk, unsigned long rate) +{
- unsigned long ret = rate;
- mutex_lock(&prepare_lock);
- if (clk && clk->ops->round_rate)
ret = __clk_round_rate(clk, rate);
- mutex_unlock(&prepare_lock);
- return ret;
If clk is NULL, clk_round_rate and __clk_round_rate return different values. Do you mean it?
+} +EXPORT_SYMBOL_GPL(clk_round_rate);
+/**
- __clk_notify - call clk notifier chain
- @clk: struct clk * that is changing rate
- @msg: clk notifier type (see include/linux/clk.h)
- @old_rate: old clk rate
- @new_rate: new clk rate
- Triggers a notifier call chain on the clk rate-change notification
- for 'clk'. Passes a pointer to the struct clk and the previous
- and current rates to the notifier callback. Intended to be called by
- internal clock code only. Returns NOTIFY_DONE from the last driver
- called if all went well, or NOTIFY_STOP or NOTIFY_BAD immediately if
- a driver returns that.
- */
+static int __clk_notify(struct clk *clk, unsigned long msg,
unsigned long old_rate, unsigned long new_rate)
+{
- struct clk_notifier *cn;
- struct clk_notifier_data cnd;
- int ret = NOTIFY_DONE;
- cnd.clk = clk;
- cnd.old_rate = old_rate;
- cnd.new_rate = new_rate;
- list_for_each_entry(cn, &clk_notifier_list, node) {
if (cn->clk == clk) {
ret = srcu_notifier_call_chain(&cn->notifier_head, msg,
&cnd);
break;
}
- }
- return ret;
+}
+/**
- __clk_recalc_rates
- @clk: first clk in the subtree
- @msg: notification type (see include/linux/clk.h)
- Walks the subtree of clks starting with clk and recalculates rates as it
- goes. Note that if a clk does not implement the recalc_rate operation then
- propagation of that subtree stops and all of that clks children will not
- have their rates updated.
- clk_recalc_rates also propagates the POST_RATE_CHANGE notification,
- if necessary.
- Caller must hold prepare_lock.
- */
+static void __clk_recalc_rates(struct clk *clk, unsigned long msg) +{
- unsigned long old_rate;
- unsigned long parent_rate = 0;
- struct hlist_node *tmp;
- struct clk *child;
- old_rate = clk->rate;
- if (clk->parent)
parent_rate = clk->parent->rate;
- if (clk->ops->recalc_rate)
clk->rate = clk->ops->recalc_rate(clk->hw, parent_rate);
- else
clk->rate = parent_rate;
- /*
* ignore NOTIFY_STOP and NOTIFY_BAD return values for POST_RATE_CHANGE
* & ABORT_RATE_CHANGE notifiers
*/
- if (clk->notifier_count && msg)
__clk_notify(clk, msg, old_rate, clk->rate);
- hlist_for_each_entry(child, tmp, &clk->children, child_node)
__clk_recalc_rates(child, msg);
+}
+/**
- __clk_speculate_rates
- @clk: first clk in the subtree
- @parent_rate: the "future" rate of clk's parent
- Walks the subtree of clks starting with clk, speculating rates as it
- goes and firing off PRE_RATE_CHANGE notifications as necessary.
- Unlike clk_recalc_rates, clk_speculate_rates exists only for sending
- pre-rate change notifications and returns early if no clks in the
- subtree have subscribed to the notifications.
- Caller must hold prepare_lock.
- */
+static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate) +{
- struct hlist_node *tmp;
- struct clk *child;
- unsigned long new_rate;
- int ret = NOTIFY_DONE;
- if (!clk->ops->recalc_rate)
goto out;
When recalc_rate is NULL, it's possible for it and its children to have notifier too.
- new_rate = clk->ops->recalc_rate(clk->hw, parent_rate);
- /* abort the rate change if a driver returns NOTIFY_BAD */
- if (clk->notifier_count)
ret = __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, new_rate);
- if (ret == NOTIFY_BAD)
goto out;
- hlist_for_each_entry(child, tmp, &clk->children, child_node) {
ret = __clk_speculate_rates(child, new_rate);
if (ret == NOTIFY_BAD)
break;
- }
Tell the notifier that already receive PRE_RATE_CHANGE abort?
+out:
- return ret;
+}
+/**
- DOC: Using the CLK_SET_RATE_PARENT flag
- __clk_set_rate changes the child's rate before the parent's to more
- easily handle failure conditions.
- This means clk might run out of spec for a short time if its rate is
- increased before the parent's rate is updated.
- To prevent this consider setting the CLK_SET_RATE_GATE flag on any
- clk where you also set the CLK_SET_RATE_PARENT flag
- PRE_RATE_CHANGE notifications are supposed to stack as a rate change
- request propagates up the clk tree. This reflects the different
- rates that a downstream clk might experience if left enabled while
- upstream parents change their rates.
- */
+static struct clk *__clk_set_rate(struct clk *clk, unsigned long rate) +{
- struct clk *fail_clk = NULL;
- int ret = NOTIFY_DONE;
- unsigned long old_rate = clk->rate;
- unsigned long new_rate;
- unsigned long parent_old_rate;
- unsigned long parent_new_rate = 0;
- struct clk *child;
- struct hlist_node *tmp;
- /* bail early if we can't change rate while clk is enabled */
- if ((clk->flags & CLK_SET_RATE_GATE) && clk->enable_count)
return clk;
- /* find the new rate and see if parent rate should change too */
- WARN_ON(!clk->ops->round_rate);
- new_rate = clk->ops->round_rate(clk->hw, rate, &parent_new_rate);
- /* NOTE: pre-rate change notifications will stack */
- if (clk->notifier_count)
ret = __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, new_rate);
if ((clk->flags & CLK_SET_RATE_PARENT) && parent_new_rate) dowstream notify from parent clk?
- if (ret == NOTIFY_BAD)
return clk;
- /* speculate rate changes down the tree */
- hlist_for_each_entry(child, tmp, &clk->children, child_node) {
ret = __clk_speculate_rates(child, new_rate);
if (ret == NOTIFY_BAD)
roll back?
return clk;
- }
- /* change the rate of this clk */
- if (clk->ops->set_rate)
If set_rate is NULL, it can fail at the beginning of this function.
ret = clk->ops->set_rate(clk->hw, new_rate);
- if (ret == NOTIFY_BAD)
you mean to check set_rate fail? Notify ABORT_RATE_CHANGE?
return clk;
- /*
* change the rate of the parent clk if necessary
*
* hitting the nested 'if' path implies we have hit a .set_rate
* failure somewhere upstream while propagating __clk_set_rate
* up the clk tree. roll back the clk rates one by one and
* return the pointer to the clk that failed. clk_set_rate will
* use the pointer to propagate a rate-change abort notifier
* from the "highest" point.
*/
- if ((clk->flags & CLK_SET_RATE_PARENT) && parent_new_rate) {
parent_old_rate = clk->parent->rate;
fail_clk = __clk_set_rate(clk->parent, parent_new_rate);
/* roll back changes if parent rate change failed */
if (fail_clk) {
pr_warn("%s: failed to set parent %s rate to %lu\n",
__func__, fail_clk->name,
parent_new_rate);
/*
* Send PRE_RATE_CHANGE notifiers down the tree
* again, since we're rolling back the rate
* changes due to the abort.
*
* Ignore any NOTIFY_BAD's since this *is* the
* exception handler.
*
* NOTE: pre-rate change notifications will stack
*/
__clk_speculate_rates(clk, clk->parent->rate);
IMHO, driver can not be happy to receive multiple PRE_RATE_CHANGE. Notify ABORT_RATE_CHANGE?
clk->ops->set_rate(clk->hw, old_rate);
}
return fail_clk;
- }
- /*
* set clk's rate & recalculate the rates of clk's children
*
* hitting this path implies we have successfully finished
* propagating recursive calls to __clk_set_rate up the clk tree
* (if necessary) and it is safe to propagate __clk_recalc_rates
* and post-rate change notifiers down the clk tree from this
* point.
*/
- __clk_recalc_rates(clk, POST_RATE_CHANGE);
- return NULL;
+}
+/**
- clk_set_rate - specify a new rate for clk
- @clk: the clk whose rate is being changed
- @rate: the new rate for clk
- In the simplest case clk_set_rate will only change the rate of clk.
- If clk has the CLK_SET_RATE_GATE flag set and it is enabled this call
- will fail; only when the clk is disabled will it be able to change
- its rate.
- Setting the CLK_SET_RATE_PARENT flag allows clk_set_rate to
- recursively propagate up to clk's parent; whether or not this happens
- depends on the outcome of clk's .round_rate implementation. If
- *parent_rate is 0 after calling .round_rate then upstream parent
- propagation is ignored. If *parent_rate comes back with a new rate
- for clk's parent then we propagate up to clk's parent and set it's
- rate. Upward propagation will continue until either a clk does not
- support the CLK_SET_RATE_PARENT flag or .round_rate stops requesting
- changes to clk's parent_rate. If there is a failure during upstream
- propagation then clk_set_rate will unwind and restore each clk's rate
- that had been successfully changed. Afterwards a rate change abort
- notification will be propagated downstream, starting from the clk
- that failed.
- At the end of all of the rate setting, clk_set_rate internally calls
- __clk_recalc_rates and propagates the rate changes downstream,
- starting from the highest clk whose rate was changed. This has the
- added benefit of propagating post-rate change notifiers.
- Note that while post-rate change and rate change abort notifications
- are guaranteed to be sent to a clk only once per call to
- clk_set_rate, pre-change notifications will be sent for every clk
- whose rate is changed. Stacking pre-change notifications is noisy
- for the drivers subscribed to them, but this allows drivers to react
- to intermediate clk rate changes up until the point where the final
- rate is achieved at the end of upstream propagation.
- Returns 0 on success, -EERROR otherwise.
- */
+int clk_set_rate(struct clk *clk, unsigned long rate) +{
- struct clk *fail_clk;
- int ret = 0;
- /* prevent racing with updates to the clock topology */
- mutex_lock(&prepare_lock);
- /* bail early if nothing to do */
- if (rate == clk->rate)
goto out;
- fail_clk = __clk_set_rate(clk, rate);
- if (fail_clk) {
pr_warn("%s: failed to set %s rate\n", __func__,
fail_clk->name);
__clk_recalc_rates(clk, ABORT_RATE_CHANGE);
It might need to begin from parent clk. move it to __clk_set_rate?
ret = -EIO;
- }
+out:
- mutex_unlock(&prepare_lock);
- return ret;
+} +EXPORT_SYMBOL_GPL(clk_set_rate);
+/**
- clk_get_parent - return the parent of a clk
- @clk: the clk whose parent gets returned
- Simply returns clk->parent. Returns NULL if clk is NULL.
- */
+struct clk *clk_get_parent(struct clk *clk) +{
- struct clk *parent;
- mutex_lock(&prepare_lock);
- parent = __clk_get_parent(clk);
- mutex_unlock(&prepare_lock);
- return parent;
+} +EXPORT_SYMBOL_GPL(clk_get_parent);
+/*
- .get_parent is mandatory for clocks with multiple possible parents. It is
- optional for single-parent clocks. Always call .get_parent if it is
- available and WARN if it is missing for multi-parent clocks.
- For single-parent clocks without .get_parent, first check to see if the
- .parents array exists, and if so use it to avoid an expensive tree
- traversal. If .parents does not exist then walk the tree with __clk_lookup.
- */
+static struct clk *__clk_init_parent(struct clk *clk) +{
- struct clk *ret = NULL;
- u8 index;
- /* handle the trivial cases */
- if (!clk->num_parents)
goto out;
- if (clk->num_parents == 1) {
if (IS_ERR_OR_NULL(clk->parent))
ret = clk->parent = __clk_lookup(clk->parent_names[0]);
ret = clk->parent;
goto out;
- }
- if (!clk->ops->get_parent) {
WARN(!clk->ops->get_parent,
"%s: multi-parent clocks must implement .get_parent\n",
__func__);
goto out;
- };
- /*
* Do our best to cache parent clocks in clk->parents. This prevents
* unnecessary and expensive calls to __clk_lookup. We don't set
* clk->parent here; that is done by the calling function
*/
- index = clk->ops->get_parent(clk->hw);
- if (!clk->parents)
clk->parents =
kmalloc((sizeof(struct clk*) * clk->num_parents),
GFP_KERNEL);
- if (!clk->parents)
ret = __clk_lookup(clk->parent_names[index]);
- else if (!clk->parents[index])
ret = clk->parents[index] =
__clk_lookup(clk->parent_names[index]);
- else
ret = clk->parents[index];
+out:
- return ret;
+}
+void __clk_reparent(struct clk *clk, struct clk *new_parent) +{ +#ifdef CONFIG_COMMON_CLK_DEBUG
- struct dentry *d;
- struct dentry *new_parent_d;
+#endif
- if (!clk || !new_parent)
return;
- hlist_del(&clk->child_node);
- if (new_parent)
hlist_add_head(&clk->child_node, &new_parent->children);
- else
hlist_add_head(&clk->child_node, &clk_orphan_list);
+#ifdef CONFIG_COMMON_CLK_DEBUG
- if (!inited)
goto out;
- if (new_parent)
new_parent_d = new_parent->dentry;
- else
new_parent_d = orphandir;
- d = debugfs_rename(clk->dentry->d_parent, clk->dentry,
new_parent_d, clk->name);
- if (d)
clk->dentry = d;
- else
pr_debug("%s: failed to rename debugfs entry for %s\n",
__func__, clk->name);
+out: +#endif
- clk->parent = new_parent;
- __clk_recalc_rates(clk, POST_RATE_CHANGE);
+}
+static int __clk_set_parent(struct clk *clk, struct clk *parent) +{
- struct clk *old_parent;
- unsigned long flags;
- int ret = -EINVAL;
- u8 i;
- old_parent = clk->parent;
- /* find index of new parent clock using cached parent ptrs */
- for (i = 0; i < clk->num_parents; i++)
if (clk->parents[i] == parent)
break;
- /*
* find index of new parent clock using string name comparison
* also try to cache the parent to avoid future calls to __clk_lookup
*/
- if (i == clk->num_parents)
for (i = 0; i < clk->num_parents; i++)
if (!strcmp(clk->parent_names[i], parent->name)) {
clk->parents[i] = __clk_lookup(parent->name);
break;
}
- if (i == clk->num_parents) {
pr_debug("%s: clock %s is not a possible parent of clock %s\n",
__func__, parent->name, clk->name);
goto out;
- }
- /* migrate prepare and enable */
- if (clk->prepare_count)
__clk_prepare(parent);
- /* FIXME replace with clk_is_enabled(clk) someday */
- spin_lock_irqsave(&enable_lock, flags);
- if (clk->enable_count)
__clk_enable(parent);
- spin_unlock_irqrestore(&enable_lock, flags);
- /* change clock input source */
- ret = clk->ops->set_parent(clk->hw, i);
- /* clean up old prepare and enable */
- spin_lock_irqsave(&enable_lock, flags);
- if (clk->enable_count)
__clk_disable(old_parent);
- spin_unlock_irqrestore(&enable_lock, flags);
- if (clk->prepare_count)
__clk_unprepare(old_parent);
+out:
- return ret;
+}
+/**
- clk_set_parent - switch the parent of a mux clk
- @clk: the mux clk whose input we are switching
- @parent: the new input to clk
- Re-parent clk to use parent as it's new input source. If clk has the
- CLK_SET_PARENT_GATE flag set then clk must be gated for this
- operation to succeed. After successfully changing clk's parent
- clk_set_parent will update the clk topology, sysfs topology and
- propagate rate recalculation via __clk_recalc_rates. Returns 0 on
- success, -EERROR otherwise.
- */
+int clk_set_parent(struct clk *clk, struct clk *parent) +{
- int ret = 0;
- if (!clk || !clk->ops)
return -EINVAL;
- if (!clk->ops->set_parent)
return -ENOSYS;
- /* prevent racing with updates to the clock topology */
- mutex_lock(&prepare_lock);
- if (clk->parent == parent)
goto out;
- /* propagate PRE_RATE_CHANGE notifications */
- if (clk->notifier_count)
ret = __clk_speculate_rates(clk, parent->rate);
- /* abort if a driver objects */
- if (ret == NOTIFY_STOP)
goto out;
- /* only re-parent if the clock is not in use */
- if ((clk->flags & CLK_SET_PARENT_GATE) && clk->prepare_count)
ret = -EBUSY;
- else
ret = __clk_set_parent(clk, parent);
- /* propagate ABORT_RATE_CHANGE if .set_parent failed */
- if (ret) {
__clk_recalc_rates(clk, ABORT_RATE_CHANGE);
goto out;
- }
- /* propagate rate recalculation downstream */
- __clk_reparent(clk, parent);
+out:
- mutex_unlock(&prepare_lock);
- return ret;
+} +EXPORT_SYMBOL_GPL(clk_set_parent);
+/**
- __clk_init - initialize the data structures in a struct clk
- @dev: device initializing this clk, placeholder for now
- @clk: clk being initialized
- Initializes the lists in struct clk, queries the hardware for the
- parent and rate and sets them both.
- Any struct clk passed into __clk_init must have the following members
- populated:
- .name
- .ops
- .hw
- .parent_names
- .num_parents
- .flags
- Essentially, everything that would normally be passed into clk_register is
- assumed to be initialized already in __clk_init. The other members may be
- populated, but are optional.
- __clk_init is only exposed via clk-private.h and is intended for use with
- very large numbers of clocks that need to be statically initialized. It is
- a layering violation to include clk-private.h from any code which implements
- a clock's .ops; as such any statically initialized clock data MUST be in a
- separate C file from the logic that implements it's operations.
- */
+void __clk_init(struct device *dev, struct clk *clk) +{
- int i;
- struct clk *orphan;
- struct hlist_node *tmp;
- if (!clk)
return;
- mutex_lock(&prepare_lock);
- /* check to see if a clock with this name is already registered */
- if (__clk_lookup(clk->name))
goto out;
- /*
* Allocate an array of struct clk *'s to avoid unnecessary string
* look-ups of clk's possible parents. This can fail for clocks passed
* in to clk_init during early boot; thus any access to clk->parents[]
* must always check for a NULL pointer and try to populate it if
* necessary.
*
* If clk->parents is not NULL we skip this entire block. This allows
* for clock drivers to statically initialize clk->parents.
*/
- if (clk->num_parents && !clk->parents) {
clk->parents = kmalloc((sizeof(struct clk*) * clk->num_parents),
GFP_KERNEL);
/*
* __clk_lookup returns NULL for parents that have not been
* clk_init'd; thus any access to clk->parents[] must check
* for a NULL pointer. We can always perform lazy lookups for
* missing parents later on.
*/
if (clk->parents)
for (i = 0; i < clk->num_parents; i++)
clk->parents[i] =
__clk_lookup(clk->parent_names[i]);
- }
- clk->parent = __clk_init_parent(clk);
- /*
* Populate clk->parent if parent has already been __clk_init'd. If
* parent has not yet been __clk_init'd then place clk in the orphan
* list. If clk has set the CLK_IS_ROOT flag then place it in the root
* clk list.
*
* Every time a new clk is clk_init'd then we walk the list of orphan
* clocks and re-parent any that are children of the clock currently
* being clk_init'd.
*/
- if (clk->parent)
hlist_add_head(&clk->child_node,
&clk->parent->children);
- else if (clk->flags & CLK_IS_ROOT)
hlist_add_head(&clk->child_node, &clk_root_list);
- else
hlist_add_head(&clk->child_node, &clk_orphan_list);
- /*
* Set clk's rate. The preferred method is to use .recalc_rate. For
* simple clocks and lazy developers the default fallback is to use the
* parent's rate. If a clock doesn't have a parent (or is orphaned)
* then rate is set to zero.
*/
- if (clk->ops->recalc_rate)
clk->rate = clk->ops->recalc_rate(clk->hw,
__clk_get_rate(clk->parent));
- else if (clk->parent)
clk->rate = clk->parent->rate;
- else
clk->rate = 0;
- /*
* walk the list of orphan clocks and reparent any that are children of
* this clock
*/
- hlist_for_each_entry(orphan, tmp, &clk_orphan_list, child_node)
__clk_reparent(orphan, __clk_init_parent(orphan));
check whether orphan->parent is the value of __clk_init_parent(orphan) before reparent?
- /*
* optional platform-specific magic
*
* The .init callback is not used by any of the basic clock types, but
* exists for weird hardware that must perform initialization magic.
* Please consider other ways of solving initialization problems before
* using this callback, as it's use is discouraged.
*/
- if (clk->ops->init)
clk->ops->init(clk->hw);
- clk_debug_register(clk);
+out:
- mutex_unlock(&prepare_lock);
- return;
+}
+/**
- clk_register - allocate a new clock, register it and return an opaque cookie
- @dev: device that is registering this clock
- @name: clock name
- @ops: operations this clock supports
- @hw: link to hardware-specific clock data
- @parent_names: array of string names for all possible parents
- @num_parents: number of possible parents
- @flags: framework-level hints and quirks
- clk_register is the primary interface for populating the clock tree with new
- clock nodes. It returns a pointer to the newly allocated struct clk which
- cannot be dereferenced by driver code but may be used in conjuction with the
- rest of the clock API.
- */
+struct clk *clk_register(struct device *dev, const char *name,
const struct clk_ops *ops, struct clk_hw *hw,
char **parent_names, u8 num_parents, unsigned long flags)
+{
- struct clk *clk;
- clk = kzalloc(sizeof(*clk), GFP_KERNEL);
- if (!clk)
return NULL;
- clk->name = name;
- clk->ops = ops;
- clk->hw = hw;
- clk->flags = flags;
- clk->parent_names = parent_names;
- clk->num_parents = num_parents;
- hw->clk = clk;
- __clk_init(dev, clk);
- return clk;
+} +EXPORT_SYMBOL_GPL(clk_register);
+/*** clk rate change notifiers ***/
+/**
- clk_notifier_register - add a clk rate change notifier
- @clk: struct clk * to watch
- @nb: struct notifier_block * with callback info
- Request notification when clk's rate changes. This uses an SRCU
- notifier because we want it to block and notifier unregistrations are
- uncommon. The callbacks associated with the notifier must not
- re-enter into the clk framework by calling any top-level clk APIs;
- this will cause a nested prepare_lock mutex.
- Pre-change notifier callbacks will be passed the current, pre-change
- rate of the clk via struct clk_notifier_data.old_rate. The new,
- post-change rate of the clk is passed via struct
- clk_notifier.new_rate.
clk_notifier_data ?
- Post-change notifiers will pass the now-current, post-change rate of
- the clk in both struct clk_notifier_data.old_rate and struct
- clk_notifier_data.new_rate.
- Abort-change notifiers are effectively the opposite of pre-change
- notifiers: the original pre-change clk rate is passed in via struct
- clk_notifier_data.new_rate and the failed post-change rate is passed
- in via struct clk_notifier_data.old_rate.
- clk_notifier_register() must be called from non-atomic context.
- Returns -EINVAL if called with null arguments, -ENOMEM upon
- allocation failure; otherwise, passes along the return value of
- srcu_notifier_chain_register().
- */
+int clk_notifier_register(struct clk *clk, struct notifier_block *nb) +{
- struct clk_notifier *cn;
- int ret = -ENOMEM;
- if (!clk || !nb)
return -EINVAL;
- mutex_lock(&prepare_lock);
- /* search the list of notifiers for this clk */
- list_for_each_entry(cn, &clk_notifier_list, node)
if (cn->clk == clk)
break;
- /* if clk wasn't in the notifier list, allocate new clk_notifier */
- if (cn->clk != clk) {
cn = kzalloc(sizeof(struct clk_notifier), GFP_KERNEL);
if (!cn)
goto out;
cn->clk = clk;
srcu_init_notifier_head(&cn->notifier_head);
list_add(&cn->node, &clk_notifier_list);
- }
why not embedd notifier_head to struct clk?
- ret = srcu_notifier_chain_register(&cn->notifier_head, nb);
- clk->notifier_count++;
+out:
- mutex_unlock(&prepare_lock);
- return ret;
+} +EXPORT_SYMBOL_GPL(clk_notifier_register);
+/**
- clk_notifier_unregister - remove a clk rate change notifier
- @clk: struct clk *
- @nb: struct notifier_block * with callback info
- Request no further notification for changes to 'clk' and frees memory
- allocated in clk_notifier_register.
- Returns -EINVAL if called with null arguments; otherwise, passes
- along the return value of srcu_notifier_chain_unregister().
- */
+int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb) +{
- struct clk_notifier *cn = NULL;
- int ret = -EINVAL;
- if (!clk || !nb)
return -EINVAL;
- mutex_lock(&prepare_lock);
- list_for_each_entry(cn, &clk_notifier_list, node)
if (cn->clk == clk)
break;
- if (cn->clk == clk) {
ret = srcu_notifier_chain_unregister(&cn->notifier_head, nb);
clk->notifier_count--;
/* XXX the notifier code should handle this better */
if (!cn->notifier_head.head) {
srcu_cleanup_notifier_head(&cn->notifier_head);
kfree(cn);
}
- } else {
ret = -ENOENT;
- }
- mutex_unlock(&prepare_lock);
- return ret;
+} +EXPORT_SYMBOL_GPL(clk_notifier_unregister); diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h new file mode 100644 index 0000000..33bf6a7 --- /dev/null +++ b/include/linux/clk-private.h @@ -0,0 +1,68 @@ +/*
- linux/include/linux/clk-private.h
- Copyright (c) 2010-2011 Jeremy Kerr jeremy.kerr@canonical.com
- Copyright (C) 2011-2012 Linaro Ltd mturquette@linaro.org
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation.
- */
+#ifndef __LINUX_CLK_PRIVATE_H +#define __LINUX_CLK_PRIVATE_H
+#include <linux/clk-provider.h> +#include <linux/list.h>
+/*
- WARNING: Do not include clk-private.h from any file that implements struct
- clk_ops. Doing so is a layering violation!
- This header exists only to allow for statically initialized clock data. Any
- static clock data must be defined in a separate file from the logic that
- implements the clock operations for that same data.
- */
+#ifdef CONFIG_COMMON_CLK
+struct clk {
- const char *name;
- const struct clk_ops *ops;
- struct clk_hw *hw;
- struct clk *parent;
- char **parent_names;
- struct clk **parents;
- u8 num_parents;
- unsigned long rate;
- unsigned long flags;
- unsigned int enable_count;
- unsigned int prepare_count;
- struct hlist_head children;
- struct hlist_node child_node;
- unsigned int notifier_count;
+#ifdef CONFIG_COMMON_CLK_DEBUG
- struct dentry *dentry;
+#endif +};
+/**
- __clk_init - initialize the data structures in a struct clk
- @dev: device initializing this clk, placeholder for now
- @clk: clk being initialized
- Initializes the lists in struct clk, queries the hardware for the
- parent and rate and sets them both.
Add: clocks that call __clk_init don't need to call clk_register.
- Any struct clk passed into __clk_init must have the following members
- populated:
- .name
- .ops
- .hw
- .parent_names
- .num_parents
- .flags
- */
+void __clk_init(struct device *dev, struct clk *clk);
+#endif /* CONFIG_COMMON_CLK */ +#endif /* CLK_PRIVATE_H */ diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h new file mode 100644 index 0000000..c9ed582 --- /dev/null +++ b/include/linux/clk-provider.h @@ -0,0 +1,169 @@ +/*
- linux/include/linux/clk-provider.h
- Copyright (c) 2010-2011 Jeremy Kerr jeremy.kerr@canonical.com
- Copyright (C) 2011-2012 Linaro Ltd mturquette@linaro.org
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation.
- */
+#ifndef __LINUX_CLK_PROVIDER_H +#define __LINUX_CLK_PROVIDER_H
+#include <linux/clk.h>
+#ifdef CONFIG_COMMON_CLK
+/**
- struct clk_hw - handle for traversing from a struct clk to its corresponding
- hardware-specific structure. struct clk_hw should be declared within struct
- clk_foo and then referenced by the struct clk instance that uses struct
- clk_foo's clk_ops
- clk: pointer to the struct clk instance that points back to this struct
- clk_hw instance
- */
+struct clk_hw {
- struct clk *clk;
+};
+/*
- flags used across common struct clk. these flags should only affect the
- top-level framework. custom flags for dealing with hardware specifics
- belong in struct clk_foo
- */
+#define CLK_SET_RATE_GATE BIT(0) /* must be gated across rate change */ +#define CLK_SET_PARENT_GATE BIT(1) /* must be gated across re-parent */ +#define CLK_SET_RATE_PARENT BIT(2) /* propagate rate change up one level */ +#define CLK_IGNORE_UNUSED BIT(3) /* do not gate even if unused */
I can not find anywhere check it.
+#define CLK_IS_ROOT BIT(4) /* root clk, has no parent */
+/**
- struct clk_ops - Callback operations for hardware clocks; these are to
- be provided by the clock implementation, and will be called by drivers
- through the clk_* api.
- @prepare: Prepare the clock for enabling. This must not return until
the clock is fully prepared, and it's safe to call clk_enable.
This callback is intended to allow clock implementations to
do any initialisation that may sleep. Called with
prepare_lock held.
- @unprepare: Release the clock from its prepared state. This will typically
undo any work done in the @prepare callback. Called with
prepare_lock held.
- @enable: Enable the clock atomically. This must not return until the
clock is generating a valid clock signal, usable by consumer
devices. Called with enable_lock held. This function must not
sleep.
- @disable: Disable the clock atomically. Called with enable_lock held.
This function must not sleep.
- @recalc_rate Recalculate the rate of this clock, by quering hardware. The
parent rate is an input parameter. It is up to the caller to
insure that the prepare_mutex is held across this call.
Returns the calculated rate. Optional, but recommended - if
this op is not set then clock rate will be initialized to 0.
- @round_rate: Given a target rate as input, returns the closest rate actually
supported by the clock.
- @get_parent: Queries the hardware to determine the parent of a clock. The
return value is a u8 which specifies the index corresponding to
the parent clock. This index can be applied to either the
.parent_names or .parents arrays. In short, this function
translates the parent value read from hardware into an array
index. Currently only called when the clock is initialized by
__clk_init. This callback is mandatory for clocks with
multiple parents. It is optional (and unnecessary) for clocks
with 0 or 1 parents.
- @set_parent: Change the input source of this clock; for clocks with multiple
possible parents specify a new parent by passing in the index
as a u8 corresponding to the parent in either the .parent_names
or .parents arrays. This function in affect translates an
array index into the value programmed into the hardware.
Returns 0 on success, -EERROR otherwise.
- @set_rate: Change the rate of this clock. If this callback returns
CLK_SET_RATE_PARENT, the rate change will be propagated to the
parent clock (which may propagate again if the parent clock
also sets this flag). The requested rate of the parent is
passed back from the callback in the second 'unsigned long *'
argument. Note that it is up to the hardware clock's set_rate
implementation to insure that clocks do not run out of spec
when propgating the call to set_rate up to the parent. One way
to do this is to gate the clock (via clk_disable and/or
clk_unprepare) before calling clk_set_rate, then ungating it
afterward. If your clock also has the CLK_GATE_SET_RATE flag
set then this will insure safety. Returns 0 on success,
-EERROR otherwise.
- The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
- implementations to split any work between atomic (enable) and sleepable
- (prepare) contexts. If enabling a clock requires code that might sleep,
- this must be done in clk_prepare. Clock enable code that will never be
- called in a sleepable context may be implement in clk_enable.
- Typically, drivers will call clk_prepare when a clock may be needed later
- (eg. when a device is opened), and clk_enable when the clock is actually
- required (eg. from an interrupt). Note that clk_prepare MUST have been
- called before clk_enable.
- */
+struct clk_ops {
- int (*prepare)(struct clk_hw *hw);
- void (*unprepare)(struct clk_hw *hw);
- int (*enable)(struct clk_hw *hw);
- void (*disable)(struct clk_hw *hw);
- unsigned long (*recalc_rate)(struct clk_hw *hw,
unsigned long parent_rate);
- long (*round_rate)(struct clk_hw *hw, unsigned long,
unsigned long *);
- int (*set_parent)(struct clk_hw *hw, u8 index);
- u8 (*get_parent)(struct clk_hw *hw);
- int (*set_rate)(struct clk_hw *hw, unsigned long);
- void (*init)(struct clk_hw *hw);
+};
+/**
- clk_register - allocate a new clock, register it and return an opaque cookie
- @dev: device that is registering this clock
- @name: clock name
- @ops: operations this clock supports
- @hw: link to hardware-specific clock data
- @parent_names: array of string names for all possible parents
- @num_parents: number of possible parents
- @flags: framework-level hints and quirks
- clk_register is the primary interface for populating the clock tree with new
- clock nodes. It returns a pointer to the newly allocated struct clk which
- cannot be dereferenced by driver code but may be used in conjuction with the
- rest of the clock API.
- */
+struct clk *clk_register(struct device *dev, const char *name,
const struct clk_ops *ops, struct clk_hw *hw,
char **parent_names, u8 num_parents, unsigned long flags);
+/* helper functions */ +const char *__clk_get_name(struct clk *clk); +struct clk_hw *__clk_get_hw(struct clk *clk); +u8 __clk_get_num_parents(struct clk *clk); +struct clk *__clk_get_parent(struct clk *clk); +unsigned long __clk_get_rate(struct clk *clk); +unsigned long __clk_get_flags(struct clk *clk); +struct clk *__clk_lookup(const char *name);
+/*
- FIXME clock api without lock protection
- */
+int __clk_prepare(struct clk *clk); +void __clk_unprepare(struct clk *clk); +void __clk_reparent(struct clk *clk, struct clk *new_parent);
It only notify POST_RATE_CHANGE without PRE_RATE_CHANGE. Mabe we need to move PRE_RATE_CHANGE to __clk_reparent too?
+unsigned long __clk_round_rate(struct clk *clk, unsigned long rate);
why're there no enable/disable functions?
+#endif /* CONFIG_COMMON_CLK */ +#endif /* CLK_PROVIDER_H */ diff --git a/include/linux/clk.h b/include/linux/clk.h index b9d46fa..b025272 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -3,6 +3,7 @@
- Copyright (C) 2004 ARM Limited.
- Written by Deep Blue Solutions Limited.
- Copyright (C) 2011-2012 Linaro Ltd mturquette@linaro.org
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
@@ -12,18 +13,75 @@ #define __LINUX_CLK_H #include <linux/kernel.h> +#include <linux/notifier.h> struct device; -/*
- The base API.
+struct clk;
+#ifdef CONFIG_COMMON_CLK
+/**
- DOC: clk notifier callback types
- PRE_RATE_CHANGE - called immediately before the clk rate is changed,
to indicate that the rate change will proceed. Drivers must
immediately terminate any operations that will be affected by the
rate change. Callbacks may either return NOTIFY_DONE or
NOTIFY_STOP.
- ABORT_RATE_CHANGE: called if the rate change failed for some reason
after PRE_RATE_CHANGE. In this case, all registered notifiers on
the clk will be called with ABORT_RATE_CHANGE. Callbacks must
always return NOTIFY_DONE.
- POST_RATE_CHANGE - called after the clk rate change has successfully
completed. Callbacks must always return NOTIFY_DONE.
*/
+#define PRE_RATE_CHANGE BIT(0) +#define POST_RATE_CHANGE BIT(1) +#define ABORT_RATE_CHANGE BIT(2) +/**
- struct clk_notifier - associate a clk with a notifier
- @clk: struct clk * to associate the notifier with
- @notifier_head: a blocking_notifier_head for this clk
- @node: linked list pointers
- A list of struct clk_notifier is maintained by the notifier code.
- An entry is created whenever code registers the first notifier on a
- particular @clk. Future notifiers on that @clk are added to the
- @notifier_head.
- */
+struct clk_notifier {
- struct clk *clk;
- struct srcu_notifier_head notifier_head;
- struct list_head node;
+}; -/*
- struct clk - an machine class defined object / cookie.
+/**
- struct clk_notifier_data - rate data to pass to the notifier callback
- @clk: struct clk * being changed
- @old_rate: previous rate of this clk
- @new_rate: new rate of this clk
- For a pre-notifier, old_rate is the clk's rate before this rate
- change, and new_rate is what the rate will be in the future. For a
- post-notifier, old_rate and new_rate are both set to the clk's
*/
- current rate (this was done to optimize the implementation).
-struct clk; +struct clk_notifier_data {
- struct clk *clk;
- unsigned long old_rate;
- unsigned long new_rate;
+};
+int clk_notifier_register(struct clk *clk, struct notifier_block *nb);
+int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);
+#endif /* !CONFIG_COMMON_CLK */ /**
- clk_get - lookup and obtain a reference to a clock producer.
Thanks Richard