diff --git a/Documentation/clk.txt b/Documentation/clk.txt index 3aeb5c440442..eb20198783cd 100644 --- a/Documentation/clk.txt +++ b/Documentation/clk.txt @@ -77,6 +77,8 @@ the operations defined in clk.h: 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); + unsigned long (*recalc_accuracy)(struct clk_hw *hw, + unsigned long parent_accuracy); void (*init)(struct clk_hw *hw); }; @@ -202,6 +204,8 @@ optional or must be evaluated on a case-by-case basis. .set_parent | | | n | y | n | .get_parent | | | n | y | n | | | | | | | +.recalc_accuracy| | | | | | + | | | | | | .init | | | | | | ----------------------------------------------------------- [1] either one of round_rate or determine_rate is required. diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 83127363ad4c..fbe08f618d59 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -104,10 +104,11 @@ static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level) if (!c) return; - seq_printf(s, "%*s%-*s %-11d %-12d %-10lu", + seq_printf(s, "%*s%-*s %-11d %-12d %-10lu %-11lu", level * 3 + 1, "", 30 - level * 3, c->name, - c->enable_count, c->prepare_count, clk_get_rate(c)); + c->enable_count, c->prepare_count, clk_get_rate(c), + clk_get_accuracy(c)); seq_printf(s, "\n"); } @@ -129,8 +130,8 @@ static int clk_summary_show(struct seq_file *s, void *data) { struct clk *c; - seq_printf(s, " clock enable_cnt prepare_cnt rate\n"); - seq_printf(s, "---------------------------------------------------------------------\n"); + seq_printf(s, " clock enable_cnt prepare_cnt rate accuracy\n"); + seq_printf(s, "---------------------------------------------------------------------------------\n"); clk_prepare_lock(); @@ -167,6 +168,7 @@ static void clk_dump_one(struct seq_file *s, struct clk *c, int level) seq_printf(s, "\"enable_count\": %d,", c->enable_count); seq_printf(s, "\"prepare_count\": %d,", c->prepare_count); seq_printf(s, "\"rate\": %lu", clk_get_rate(c)); + seq_printf(s, "\"accuracy\": %lu", clk_get_accuracy(c)); } static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level) @@ -248,6 +250,11 @@ static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry) if (!d) goto err_out; + d = debugfs_create_u32("clk_accuracy", S_IRUGO, clk->dentry, + (u32 *)&clk->accuracy); + if (!d) + goto err_out; + d = debugfs_create_x32("clk_flags", S_IRUGO, clk->dentry, (u32 *)&clk->flags); if (!d) @@ -603,6 +610,14 @@ out: return ret; } +unsigned long __clk_get_accuracy(struct clk *clk) +{ + if (!clk) + return 0; + + return clk->accuracy; +} + unsigned long __clk_get_flags(struct clk *clk) { return !clk ? 0 : clk->flags; @@ -1016,6 +1031,59 @@ static int __clk_notify(struct clk *clk, unsigned long msg, return ret; } +/** + * __clk_recalc_accuracies + * @clk: first clk in the subtree + * + * Walks the subtree of clks starting with clk and recalculates accuracies as + * it goes. Note that if a clk does not implement the .recalc_accuracy + * callback then it is assumed that the clock will take on the accuracy of it's + * parent. + * + * Caller must hold prepare_lock. + */ +static void __clk_recalc_accuracies(struct clk *clk) +{ + unsigned long parent_accuracy = 0; + struct clk *child; + + if (clk->parent) + parent_accuracy = clk->parent->accuracy; + + if (clk->ops->recalc_accuracy) + clk->accuracy = clk->ops->recalc_accuracy(clk->hw, + parent_accuracy); + else + clk->accuracy = parent_accuracy; + + hlist_for_each_entry(child, &clk->children, child_node) + __clk_recalc_accuracies(child); +} + +/** + * clk_get_accuracy - return the accuracy of clk + * @clk: the clk whose accuracy is being returned + * + * Simply returns the cached accuracy of the clk, unless + * CLK_GET_ACCURACY_NOCACHE flag is set, which means a recalc_rate will be + * issued. + * If clk is NULL then returns 0. + */ +long clk_get_accuracy(struct clk *clk) +{ + unsigned long accuracy; + + clk_prepare_lock(); + if (clk && (clk->flags & CLK_GET_ACCURACY_NOCACHE)) + __clk_recalc_accuracies(clk); + + accuracy = __clk_get_accuracy(clk); + clk_prepare_unlock(); + + return accuracy; +} +EXPORT_SYMBOL_GPL(clk_get_accuracy); + /** * __clk_recalc_rates * @clk: first clk in the subtree @@ -1552,6 +1620,7 @@ void __clk_reparent(struct clk *clk, struct clk *new_parent) { clk_reparent(clk, new_parent); clk_debug_reparent(clk, new_parent); + __clk_recalc_accuracies(clk); __clk_recalc_rates(clk, POST_RATE_CHANGE); } @@ -1622,11 +1691,13 @@ int clk_set_parent(struct clk *clk, struct clk *parent) /* do the re-parent */ ret = __clk_set_parent(clk, parent, p_index); - /* propagate rate recalculation accordingly */ - if (ret) + /* propagate rate an accuracy recalculation accordingly */ + if (ret) { __clk_recalc_rates(clk, ABORT_RATE_CHANGE); - else + } else { __clk_recalc_rates(clk, POST_RATE_CHANGE); + __clk_recalc_accuracies(clk); + } out: clk_prepare_unlock(); @@ -1730,6 +1801,21 @@ int __clk_init(struct device *dev, struct clk *clk) else hlist_add_head(&clk->child_node, &clk_orphan_list); + /* + * Set clk's accuracy. The preferred method is to use + * .recalc_accuracy. For simple clocks and lazy developers the default + * fallback is to use the parent's accuracy. If a clock doesn't have a + * parent (or is orphaned) then accuracy is set to zero (perfect + * clock). + */ + if (clk->ops->recalc_accuracy) + clk->accuracy = clk->ops->recalc_accuracy(clk->hw, + __clk_get_accuracy(clk->parent)); + else if (clk->parent) + clk->accuracy = clk->parent->accuracy; + else + clk->accuracy = 0; + /* * 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 diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index 8138c94409f3..accb517e77e9 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -41,6 +41,7 @@ struct clk { unsigned long flags; unsigned int enable_count; unsigned int prepare_count; + unsigned long accuracy; struct hlist_head children; struct hlist_node child_node; unsigned int notifier_count; diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 7e59253b8603..16d182c28ce6 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -29,6 +29,7 @@ #define CLK_IS_BASIC BIT(5) /* Basic clk, can't do a to_clk_foo() */ #define CLK_GET_RATE_NOCACHE BIT(6) /* do not use the cached clk rate */ #define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */ +#define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */ struct clk_hw; @@ -108,6 +109,13 @@ struct clk_hw; * which is likely helpful for most .set_rate implementation. * Returns 0 on success, -EERROR otherwise. * + * @recalc_accuracy: Recalculate the accuracy of this clock. The clock accuracy + * is expressed in ppb (parts per billion). The parent accuracy is + * an input parameter. + * Returns the calculated accuracy. Optional - if this op is not + * set then clock accuracy will be initialized to parent accuracy + * or 0 (perfect clock) if clock has no parent. + * * 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, @@ -139,6 +147,8 @@ struct clk_ops { u8 (*get_parent)(struct clk_hw *hw); int (*set_rate)(struct clk_hw *hw, unsigned long, unsigned long); + unsigned long (*recalc_accuracy)(struct clk_hw *hw, + unsigned long parent_accuracy); void (*init)(struct clk_hw *hw); }; @@ -433,6 +443,7 @@ struct clk *clk_get_parent_by_index(struct clk *clk, u8 index); unsigned int __clk_get_enable_count(struct clk *clk); unsigned int __clk_get_prepare_count(struct clk *clk); unsigned long __clk_get_rate(struct clk *clk); +unsigned long __clk_get_accuracy(struct clk *clk); unsigned long __clk_get_flags(struct clk *clk); bool __clk_is_prepared(struct clk *clk); bool __clk_is_enabled(struct clk *clk); diff --git a/include/linux/clk.h b/include/linux/clk.h index 9a6d04524b1a..0dd91148165e 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -82,6 +82,23 @@ int clk_notifier_register(struct clk *clk, struct notifier_block *nb); int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb); +/** + * clk_get_accuracy - obtain the clock accuracy in ppb (parts per billion) + * for a clock source. + * @clk: clock source + * + * This gets the clock source accuracy expressed in ppb. + * A perfect clock returns 0. + */ +long clk_get_accuracy(struct clk *clk); + +#else + +static inline long clk_get_accuracy(struct clk *clk) +{ + return -ENOTSUPP; +} + #endif /**