* [PATCH v4 0/2] clk: add clk accuracy support
@ 2013-12-21 9:34 Boris BREZILLON
[not found] ` <1387618488-3075-1-git-send-email-b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ@public.gmane.org>
0 siblings, 1 reply; 4+ messages in thread
From: Boris BREZILLON @ 2013-12-21 9:34 UTC (permalink / raw)
To: Rob Landley, Rob Herring, Pawel Moll, Mark Rutland,
Stephen Warren, Ian Campbell, Mike Turquette, Russell King,
Nicolas Ferre, Uwe Kleine-König
Cc: Boris BREZILLON, linux-doc, linux-kernel, devicetree,
linux-arm-kernel
Hello,
This patch series adds support for clock accuracy retrieval in the common clk
framework.
Best Regards,
Boris
Changes since v3:
- do not export __clk_get_accuracy symbol
Changes since v2:
- fix __clk_recalc_accuracies function comment
- modify __clk_get_accuracy to return the current clock accuracy even when the
clock is orphan
- only recalculate clock accuracy when reparent succeed
Changes since v1:
- remove HAVE_CLK_GET_ACCURACY option and enable clk accuracy support only
when using the CCF
- export __clk_get_accuracy (might be used by clk-providers)
- fix documentation (s/recalc_rate/recalc_accuracy/)
- move fixed_accuracy field addition (struct clk_fixed_rate) from the 1st
patch to the 2nd patch of this series
Boris BREZILLON (2):
clk: add clk accuracy retrieval support
clk: add accuracy support for fixed clock
Documentation/clk.txt | 4 +
.../devicetree/bindings/clock/fixed-clock.txt | 3 +
drivers/clk/clk-fixed-rate.c | 43 +++++++--
drivers/clk/clk.c | 102 ++++++++++++++++++--
include/linux/clk-private.h | 1 +
include/linux/clk-provider.h | 15 +++
include/linux/clk.h | 17 ++++
7 files changed, 172 insertions(+), 13 deletions(-)
--
1.7.9.5
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v4 1/2] clk: add clk accuracy retrieval support
[not found] ` <1387618488-3075-1-git-send-email-b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ@public.gmane.org>
@ 2013-12-21 9:34 ` Boris BREZILLON
[not found] ` <20131223075159.22761.63922@quantum>
2013-12-21 9:34 ` [PATCH v4 2/2] clk: add accuracy support for fixed clock Boris BREZILLON
1 sibling, 1 reply; 4+ messages in thread
From: Boris BREZILLON @ 2013-12-21 9:34 UTC (permalink / raw)
To: Rob Landley, Rob Herring, Pawel Moll, Mark Rutland,
Stephen Warren, Ian Campbell, Mike Turquette, Russell King,
Nicolas Ferre, Uwe Kleine-König
Cc: Boris BREZILLON, linux-doc-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
The clock accuracy is expressed in ppb (parts per billion) and represents
the possible clock drift.
Say you have a clock (e.g. an oscillator) which provides a fixed clock of
20MHz with an accuracy of +- 20Hz. This accuracy expressed in ppb is
20Hz/20MHz = 1000 ppb (or 1 ppm).
Clock users may need the clock accuracy information in order to choose
the best clock (the one with the best accuracy) across several available
clocks.
This patch adds clk accuracy retrieval support for common clk framework by
means of a new function called clk_get_accuracy.
This function returns the given clock accuracy expressed in ppb.
In order to get the clock accuracy, this implementation adds one callback
called recalc_accuracy to the clk_ops structure.
This callback is given the parent clock accuracy (if the clock is not a
root clock) and should recalculate the given clock accuracy.
This callback is optional and may be implemented if the clock is not
a perfect clock (accuracy != 0 ppb).
Signed-off-by: Boris BREZILLON <b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ@public.gmane.org>
---
Documentation/clk.txt | 4 ++
drivers/clk/clk.c | 102 +++++++++++++++++++++++++++++++++++++++---
include/linux/clk-private.h | 1 +
include/linux/clk-provider.h | 11 +++++
include/linux/clk.h | 17 +++++++
5 files changed, 128 insertions(+), 7 deletions(-)
diff --git a/Documentation/clk.txt b/Documentation/clk.txt
index 3aeb5c4..eb20198 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 2cf2ea6..6aa5886 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)
@@ -602,6 +609,16 @@ out:
return ret;
}
+unsigned long __clk_get_accuracy(struct clk *clk)
+{
+ unsigned long ret;
+
+ if (!clk)
+ return 0;
+
+ return clk->accuracy;
+}
+
unsigned long __clk_get_flags(struct clk *clk)
{
return !clk ? 0 : clk->flags;
@@ -1016,6 +1033,59 @@ static int __clk_notify(struct clk *clk, unsigned long msg,
}
/**
+ * __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
* @msg: notification type (see include/linux/clk.h)
@@ -1551,6 +1621,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);
}
@@ -1621,11 +1692,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 +1803,21 @@ int __clk_init(struct device *dev, struct clk *clk)
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
* parent's rate. If a clock doesn't have a parent (or is orphaned)
diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h
index 8138c94..accb517 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 7e59253..16d182c 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 9a6d045..0dd9114 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
/**
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v4 2/2] clk: add accuracy support for fixed clock
[not found] ` <1387618488-3075-1-git-send-email-b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ@public.gmane.org>
2013-12-21 9:34 ` [PATCH v4 1/2] clk: add clk accuracy retrieval support Boris BREZILLON
@ 2013-12-21 9:34 ` Boris BREZILLON
1 sibling, 0 replies; 4+ messages in thread
From: Boris BREZILLON @ 2013-12-21 9:34 UTC (permalink / raw)
To: Rob Landley, Rob Herring, Pawel Moll, Mark Rutland,
Stephen Warren, Ian Campbell, Mike Turquette, Russell King,
Nicolas Ferre, Uwe Kleine-König
Cc: Boris BREZILLON, linux-doc-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
This patch adds support for accuracy retrieval on fixed clocks.
It also adds a new dt property called 'clock-accuracy' to define the clock
accuracy.
This can be usefull for oscillator (RC, crystal, ...) definitions which are
always given an accuracy characteristic.
Signed-off-by: Boris BREZILLON <b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ@public.gmane.org>
---
.../devicetree/bindings/clock/fixed-clock.txt | 3 ++
drivers/clk/clk-fixed-rate.c | 43 +++++++++++++++++---
include/linux/clk-provider.h | 4 ++
3 files changed, 44 insertions(+), 6 deletions(-)
diff --git a/Documentation/devicetree/bindings/clock/fixed-clock.txt b/Documentation/devicetree/bindings/clock/fixed-clock.txt
index 0b1fe78..48ea0ad 100644
--- a/Documentation/devicetree/bindings/clock/fixed-clock.txt
+++ b/Documentation/devicetree/bindings/clock/fixed-clock.txt
@@ -10,6 +10,8 @@ Required properties:
- clock-frequency : frequency of clock in Hz. Should be a single cell.
Optional properties:
+- clock-accuracy : accuracy of clock in ppb (parts per billion).
+ Should be a single cell.
- gpios : From common gpio binding; gpio connection to clock enable pin.
- clock-output-names : From common clock binding.
@@ -18,4 +20,5 @@ Example:
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <1000000000>;
+ clock-accuracy = <100>;
};
diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c
index 1ed591a..0fc56ab 100644
--- a/drivers/clk/clk-fixed-rate.c
+++ b/drivers/clk/clk-fixed-rate.c
@@ -34,22 +34,31 @@ static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw,
return to_clk_fixed_rate(hw)->fixed_rate;
}
+static unsigned long clk_fixed_rate_recalc_accuracy(struct clk_hw *hw,
+ unsigned long parent_accuracy)
+{
+ return to_clk_fixed_rate(hw)->fixed_accuracy;
+}
+
const struct clk_ops clk_fixed_rate_ops = {
.recalc_rate = clk_fixed_rate_recalc_rate,
+ .recalc_accuracy = clk_fixed_rate_recalc_accuracy,
};
EXPORT_SYMBOL_GPL(clk_fixed_rate_ops);
/**
- * clk_register_fixed_rate - register fixed-rate clock with the clock framework
+ * clk_register_fixed_rate_with_accuracy - register fixed-rate clock with the
+ * clock framework
* @dev: device that is registering this clock
* @name: name of this clock
* @parent_name: name of clock's parent
* @flags: framework-specific flags
* @fixed_rate: non-adjustable clock rate
+ * @fixed_accuracy: non-adjustable clock rate
*/
-struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
- const char *parent_name, unsigned long flags,
- unsigned long fixed_rate)
+struct clk *clk_register_fixed_rate_with_accuracy(struct device *dev,
+ const char *name, const char *parent_name, unsigned long flags,
+ unsigned long fixed_rate, unsigned long fixed_accuracy)
{
struct clk_fixed_rate *fixed;
struct clk *clk;
@@ -70,16 +79,33 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
/* struct clk_fixed_rate assignments */
fixed->fixed_rate = fixed_rate;
+ fixed->fixed_accuracy = fixed_accuracy;
fixed->hw.init = &init;
/* register the clock */
clk = clk_register(dev, &fixed->hw);
-
if (IS_ERR(clk))
kfree(fixed);
return clk;
}
+EXPORT_SYMBOL_GPL(clk_register_fixed_rate_with_accuracy);
+
+/**
+ * clk_register_fixed_rate - register fixed-rate clock with the clock framework
+ * @dev: device that is registering this clock
+ * @name: name of this clock
+ * @parent_name: name of clock's parent
+ * @flags: framework-specific flags
+ * @fixed_rate: non-adjustable clock rate
+ */
+struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ unsigned long fixed_rate)
+{
+ return clk_register_fixed_rate_with_accuracy(dev, name, parent_name,
+ flags, fixed_rate, 0);
+}
EXPORT_SYMBOL_GPL(clk_register_fixed_rate);
#ifdef CONFIG_OF
@@ -91,13 +117,18 @@ void of_fixed_clk_setup(struct device_node *node)
struct clk *clk;
const char *clk_name = node->name;
u32 rate;
+ u32 accuracy = 0;
if (of_property_read_u32(node, "clock-frequency", &rate))
return;
+ of_property_read_u32(node, "clock-accuracy", &accuracy);
+
of_property_read_string(node, "clock-output-names", &clk_name);
- clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, rate);
+ clk = clk_register_fixed_rate_with_accuracy(NULL, clk_name, NULL,
+ CLK_IS_ROOT, rate,
+ accuracy);
if (!IS_ERR(clk))
of_clk_add_provider(node, of_clk_src_simple_get, clk);
}
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 16d182c..5429f5d 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -204,6 +204,7 @@ struct clk_hw {
struct clk_fixed_rate {
struct clk_hw hw;
unsigned long fixed_rate;
+ unsigned long fixed_accuracy;
u8 flags;
};
@@ -211,6 +212,9 @@ extern const struct clk_ops clk_fixed_rate_ops;
struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
unsigned long fixed_rate);
+struct clk *clk_register_fixed_rate_with_accuracy(struct device *dev,
+ const char *name, const char *parent_name, unsigned long flags,
+ unsigned long fixed_rate, unsigned long fixed_accuracy);
void of_fixed_clk_setup(struct device_node *np);
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v4 1/2] clk: add clk accuracy retrieval support
[not found] ` <20131223075159.22761.63922@quantum>
@ 2013-12-23 8:02 ` boris brezillon
0 siblings, 0 replies; 4+ messages in thread
From: boris brezillon @ 2013-12-23 8:02 UTC (permalink / raw)
To: Mike Turquette, Rob Landley, Rob Herring, Pawel Moll,
Mark Rutland, Stephen Warren, Ian Campbell, Russell King,
Nicolas Ferre, Uwe Kleine-König
Cc: linux-doc-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Le 23/12/2013 08:51, Mike Turquette a écrit :
> Quoting Boris BREZILLON (2013-12-21 01:34:47)
>> The clock accuracy is expressed in ppb (parts per billion) and represents
>> the possible clock drift.
>> Say you have a clock (e.g. an oscillator) which provides a fixed clock of
>> 20MHz with an accuracy of +- 20Hz. This accuracy expressed in ppb is
>> 20Hz/20MHz = 1000 ppb (or 1 ppm).
>>
>> Clock users may need the clock accuracy information in order to choose
>> the best clock (the one with the best accuracy) across several available
>> clocks.
>>
>> This patch adds clk accuracy retrieval support for common clk framework by
>> means of a new function called clk_get_accuracy.
>> This function returns the given clock accuracy expressed in ppb.
>>
>> In order to get the clock accuracy, this implementation adds one callback
>> called recalc_accuracy to the clk_ops structure.
>> This callback is given the parent clock accuracy (if the clock is not a
>> root clock) and should recalculate the given clock accuracy.
>>
>> This callback is optional and may be implemented if the clock is not
>> a perfect clock (accuracy != 0 ppb).
>>
>> Signed-off-by: Boris BREZILLON <b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ@public.gmane.org>
> There was an unused 'unsigned long ret' in __clk_get_accuracy which I
> removed.
Indeed. Thanks!
> Updated patch as applied to clk-next is below:
>
> Regards,
> Mike
>
>
>
> From 5279fc402ae59361a224d641d5823b21b4206232 Mon Sep 17 00:00:00 2001
> From: Boris BREZILLON <b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ@public.gmane.org>
> Date: Sat, 21 Dec 2013 10:34:47 +0100
> Subject: [PATCH] clk: add clk accuracy retrieval support
>
> The clock accuracy is expressed in ppb (parts per billion) and represents
> the possible clock drift.
> Say you have a clock (e.g. an oscillator) which provides a fixed clock of
> 20MHz with an accuracy of +- 20Hz. This accuracy expressed in ppb is
> 20Hz/20MHz = 1000 ppb (or 1 ppm).
>
> Clock users may need the clock accuracy information in order to choose
> the best clock (the one with the best accuracy) across several available
> clocks.
>
> This patch adds clk accuracy retrieval support for common clk framework by
> means of a new function called clk_get_accuracy.
> This function returns the given clock accuracy expressed in ppb.
>
> In order to get the clock accuracy, this implementation adds one callback
> called recalc_accuracy to the clk_ops structure.
> This callback is given the parent clock accuracy (if the clock is not a
> root clock) and should recalculate the given clock accuracy.
>
> This callback is optional and may be implemented if the clock is not
> a perfect clock (accuracy != 0 ppb).
>
> Signed-off-by: Boris BREZILLON <b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Mike Turquette <mturquette-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
> Documentation/clk.txt | 4 ++
> drivers/clk/clk.c | 100 ++++++++++++++++++++++++++++++++++++++++---
> include/linux/clk-private.h | 1 +
> include/linux/clk-provider.h | 11 +++++
> include/linux/clk.h | 17 ++++++++
> 5 files changed, 126 insertions(+), 7 deletions(-)
>
> diff --git a/Documentation/clk.txt b/Documentation/clk.txt
> index 3aeb5c4..eb20198 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 8312736..fbe08f6 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;
> @@ -1017,6 +1032,59 @@ static int __clk_notify(struct clk *clk, unsigned long msg,
> }
>
> /**
> + * __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
> * @msg: notification type (see include/linux/clk.h)
> @@ -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();
> @@ -1731,6 +1802,21 @@ int __clk_init(struct device *dev, struct clk *clk)
> 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
> * parent's rate. If a clock doesn't have a parent (or is orphaned)
> diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h
> index 8138c94..accb517 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 7e59253..16d182c 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 9a6d045..0dd9114 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
>
> /**
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2013-12-23 8:02 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-12-21 9:34 [PATCH v4 0/2] clk: add clk accuracy support Boris BREZILLON
[not found] ` <1387618488-3075-1-git-send-email-b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ@public.gmane.org>
2013-12-21 9:34 ` [PATCH v4 1/2] clk: add clk accuracy retrieval support Boris BREZILLON
[not found] ` <20131223075159.22761.63922@quantum>
2013-12-23 8:02 ` boris brezillon
2013-12-21 9:34 ` [PATCH v4 2/2] clk: add accuracy support for fixed clock Boris BREZILLON
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).