.release = single_release,
};
-/* caller must hold prepare_lock */
static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
{
struct dentry *d;
mutex_unlock(&clk_debug_lock);
}
-struct dentry *clk_debugfs_add_file(struct clk *clk, char *name, umode_t mode,
+struct dentry *clk_debugfs_add_file(struct clk_hw *hw, char *name, umode_t mode,
void *data, const struct file_operations *fops)
{
struct dentry *d = NULL;
- if (clk->dentry)
- d = debugfs_create_file(name, mode, clk->dentry, data, fops);
+ if (hw->clk->dentry)
+ d = debugfs_create_file(name, mode, hw->clk->dentry, data, fops);
return d;
}
return !clk ? 0 : clk->enable_count;
}
-unsigned int __clk_get_prepare_count(struct clk *clk)
-{
- return !clk ? 0 : clk->prepare_count;
-}
-
unsigned long __clk_get_rate(struct clk *clk)
{
unsigned long ret;
}
EXPORT_SYMBOL_GPL(__clk_get_rate);
-unsigned long __clk_get_accuracy(struct clk *clk)
+static unsigned long __clk_get_accuracy(struct clk *clk)
{
if (!clk)
return 0;
*/
long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
- struct clk **best_parent_p)
+ struct clk_hw **best_parent_p)
{
struct clk *clk = hw->clk, *parent, *best_parent = NULL;
int i, num_parents;
out:
if (best_parent)
- *best_parent_p = best_parent;
+ *best_parent_p = best_parent->hw;
*best_parent_rate = best;
return best;
{
unsigned long parent_rate = 0;
struct clk *parent;
+ struct clk_hw *parent_hw;
if (!clk)
return 0;
if (parent)
parent_rate = parent->rate;
- if (clk->ops->determine_rate)
+ if (clk->ops->determine_rate) {
+ parent_hw = parent ? parent->hw : NULL;
return clk->ops->determine_rate(clk->hw, rate, &parent_rate,
- &parent);
- else if (clk->ops->round_rate)
+ &parent_hw);
+ } else if (clk->ops->round_rate)
return clk->ops->round_rate(clk->hw, rate, &parent_rate);
else if (clk->flags & CLK_SET_RATE_PARENT)
return __clk_round_rate(clk->parent, rate);
{
struct clk *top = clk;
struct clk *old_parent, *parent;
+ struct clk_hw *parent_hw;
unsigned long best_parent_rate = 0;
unsigned long new_rate;
int p_index = 0;
/* find the closest rate and parent clk/rate */
if (clk->ops->determine_rate) {
+ parent_hw = parent ? parent->hw : NULL;
new_rate = clk->ops->determine_rate(clk->hw, rate,
&best_parent_rate,
- &parent);
+ &parent_hw);
+ parent = parent_hw ? parent_hw->clk : NULL;
} else if (clk->ops->round_rate) {
new_rate = clk->ops->round_rate(clk->hw, rate,
&best_parent_rate);
}
/* try finding the new parent index */
- if (parent) {
+ if (parent && clk->num_parents > 1) {
p_index = clk_fetch_parent_index(clk, parent);
if (p_index < 0) {
pr_debug("%s: clk %s can not be parent of clk %s\n",
if (clk->num_parents == 1) {
if (IS_ERR_OR_NULL(clk->parent))
- ret = clk->parent = __clk_lookup(clk->parent_names[0]);
+ clk->parent = __clk_lookup(clk->parent_names[0]);
ret = clk->parent;
goto out;
}
__clk_recalc_rates(clk, POST_RATE_CHANGE);
}
+/**
+ * clk_has_parent - check if a clock is a possible parent for another
+ * @clk: clock source
+ * @parent: parent clock source
+ *
+ * This function can be used in drivers that need to check that a clock can be
+ * the parent of another without actually changing the parent.
+ *
+ * Returns true if @parent is a possible parent for @clk, false otherwise.
+ */
+bool clk_has_parent(struct clk *clk, struct clk *parent)
+{
+ unsigned int i;
+
+ /* NULL clocks should be nops, so return success if either is NULL. */
+ if (!clk || !parent)
+ return true;
+
+ /* Optimize for the case where the parent is already the parent. */
+ if (clk->parent == parent)
+ return true;
+
+ for (i = 0; i < clk->num_parents; i++)
+ if (strcmp(clk->parent_names[i], parent->name) == 0)
+ return true;
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(clk_has_parent);
+
/**
* clk_set_parent - switch the parent of a mux clk
* @clk: the mux clk whose input we are switching
else
clk->rate = 0;
- clk_debug_register(clk);
/*
* walk the list of orphan clocks and reparent any that are children of
* this clock
out:
clk_prepare_unlock();
+ if (!ret)
+ clk_debug_register(clk);
+
return ret;
}
void __clk_put(struct clk *clk)
{
+ struct module *owner;
+
if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
return;
clk_prepare_lock();
+ owner = clk->owner;
kref_put(&clk->ref, __clk_release);
clk_prepare_unlock();
- module_put(clk->owner);
+ module_put(owner);
}
/*** clk rate change notifiers ***/