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.k...@canonical.com> > + * Copyright (C) 2011-2012 Linaro Ltd <mturque...@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.k...@canonical.com> > + * Copyright (C) 2011-2012 Linaro Ltd <mturque...@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 <mturque...@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 _______________________________________________ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev