The common clock framework defines a common struct clk as well as an implementation of the clk api that unifies clock operations on various platforms and devices.
The net result is consolidation of many different struct clk definitions and platform-specific clock framework implementations.
Thanks to Sascha Hauer and Andrew Lunn for their great review and feedback on the previous v5 series.
Major changes since v5: * removed redundant HAVE_CLK_PREPARE in Kconfig * new CONFIG_COMMON_CLK_DISABLE_UNUSED feature * results in a new clk_op callback, .is_enabled * standardized the hw-specific locking in the basic clock types * export the individual ops for each basic clock type * improve registration for single-parent basic clocks (thanks Sascha) * fixed bugs in gate clock's static initializers (thanks Andrew) * overall improvements to Documentation/clk.txt * rebased onto Linus' v3.3-rc6 tag
Major changes since v4: * rolled in TGLX's comments on overall design. We now have, * proper handling of root clocks and orphan clocks * multi-parent clocks are handled in the core * struct clk is shielded from struct clk_foo and vice versa * this is a return to the previous struct clk_hw design * split basic clock types out into separate files * split headers up by purpose * clk.h remains the driver-level interface * declarations for rate change notifiers are the only additions * clk-provider.h is primary header for implementing clock operations * clk-private.h allows for static initialization of clock data * validation and bug fixes * rebased onto Linus' v3.3-rc5 tag
Patches can be pulled from: git://git.linaro.org/people/mturquette/linux.git v3.3-rc6-clkv6
v5 can be found at, http://article.gmane.org/gmane.linux.kernel/1261472
v4 can be found at, http://article.gmane.org/gmane.linux.linaro.devel/8896/
v3 can be found at, http://article.gmane.org/gmane.linux.kernel/1218622
Mike Turquette (3): Documentation: common clk API clk: introduce the common clock framework clk: basic clock hardware types
Documentation/clk.txt | 233 +++++++ drivers/clk/Kconfig | 39 ++ drivers/clk/Makefile | 2 + drivers/clk/clk-divider.c | 204 ++++++ drivers/clk/clk-fixed-rate.c | 82 +++ drivers/clk/clk-gate.c | 157 +++++ drivers/clk/clk-mux.c | 123 ++++ drivers/clk/clk.c | 1424 ++++++++++++++++++++++++++++++++++++++++++ include/linux/clk-private.h | 192 ++++++ include/linux/clk-provider.h | 298 +++++++++ include/linux/clk.h | 68 ++- 11 files changed, 2817 insertions(+), 5 deletions(-) create mode 100644 Documentation/clk.txt create mode 100644 drivers/clk/clk-divider.c create mode 100644 drivers/clk/clk-fixed-rate.c create mode 100644 drivers/clk/clk-gate.c create mode 100644 drivers/clk/clk-mux.c create mode 100644 drivers/clk/clk.c create mode 100644 include/linux/clk-private.h create mode 100644 include/linux/clk-provider.h
Provide documentation for the common clk structures and APIs. This code can be found in drivers/clk/ and include/linux/clk*.h.
Signed-off-by: Mike Turquette mturquette@linaro.org Signed-off-by: Mike Turquette mturquette@ti.com Cc: Russell King linux@arm.linux.org.uk Cc: Jeremy Kerr jeremy.kerr@canonical.com Cc: Thomas Gleixner tglx@linutronix.de Cc: Arnd Bergman arnd.bergmann@linaro.org Cc: Paul Walmsley paul@pwsan.com Cc: Shawn Guo shawn.guo@freescale.com Cc: Sascha Hauer s.hauer@pengutronix.de Cc: Richard Zhao richard.zhao@linaro.org Cc: Saravana Kannan skannan@codeaurora.org Cc: Magnus Damm magnus.damm@gmail.com Cc: Rob Herring rob.herring@calxeda.com Cc: Mark Brown broonie@opensource.wolfsonmicro.com Cc: Linus Walleij linus.walleij@stericsson.com Cc: Stephen Boyd sboyd@codeaurora.org Cc: Amit Kucheria amit.kucheria@linaro.org Cc: Deepak Saxena dsaxena@linaro.org Cc: Grant Likely grant.likely@secretlab.ca Cc: Andrew Lunn andrew@lunn.ch --- Changes since v5: * __clk_init must be called for statically initialized clocks * added "clk_ops matrix" to better clarify which ops are mandatory
Documentation/clk.txt | 233 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 233 insertions(+), 0 deletions(-) create mode 100644 Documentation/clk.txt
diff --git a/Documentation/clk.txt b/Documentation/clk.txt new file mode 100644 index 0000000..1943fae --- /dev/null +++ b/Documentation/clk.txt @@ -0,0 +1,233 @@ + The Common Clk Framework + Mike Turquette mturquette@ti.com + +This document endeavours to explain the common clk framework details, +and how to port a platform over to this framework. It is not yet a +detailed explanation of the clock api in include/linux/clk.h, but +perhaps someday it will include that information. + + Part 1 - introduction and interface split + +The common clk framework is an interface to control the clock nodes +available on various devices today. This may come in the form of clock +gating, rate adjustment, muxing or other operations. This framework is +enabled with the CONFIG_COMMON_CLK option. + +The interface itself is divided into two halves, each shielded from the +details of its counterpart. First is the common definition of struct +clk which unifies the framework-level accounting and infrastructure that +has traditionally been duplicated across a variety of platforms. Second +is a common implementation of the clk.h api, defined in +drivers/clk/clk.c. Finally there is struct clk_ops, whose operations +are invoked by the clk api implementation. + +The second half of the interface is comprised of the hardware-specific +callbacks registered with struct clk_ops and the corresponding +hardware-specific structures needed to model a particular clock. For +the remainder of this document any reference to a callback in struct +clk_ops, such as .enable or .set_rate, implies the hardware-specific +implementation of that code. Likewise, references to struct clk_foo +serve as a convenient shorthand for the implementation of the +hardware-specific bits for the hypothetical "foo" hardware. + +Tying the two halves of this interface together is struct clk_hw, which +is defined in struct clk_foo and pointed to within struct clk. This +allows easy for navigation between the two discrete halves of the common +clock interface. + + Part 2 - common data structures and api + +Below is the common struct clk definition from +include/linux/clk-private.h, modified for brevity: + + struct clk { + const char *name; + const struct clk_ops *ops; + struct clk_hw *hw; + char **parent_names; + struct clk **parents; + struct clk *parent; + struct hlist_head children; + struct hlist_node child_node; + ... + }; + +The members above make up the core of the clk tree topology. The clk +api itself defines several driver-facing functions which operate on +struct clk. That api is documented in include/linux/clk.h. + +Platforms and devices utilizing the common struct clk use the struct +clk_ops pointer in struct clk to perform the hardware-specific parts of +the operations defined in clk.h: + + 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); + int (*is_enabled)(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); + }; + + Part 3 - hardware clk implementations + +The strength of the common struct clk comes from its .ops and .hw pointers +which abstract the details of struct clk from the hardware-specific bits, and +vice versa. To illustrate consider the simple gateable clk implementation in +drivers/clk/clk-gate.c: + +struct clk_gate { + struct clk_hw hw; + void __iomem *reg; + u8 bit_idx; + ... +}; + +struct clk_gate contains struct clk_hw hw as well as hardware-specific +knowledge about which register and bit controls this clk's gating. +Nothing about clock topology or accounting, such as enable_count or +notifier_count, is needed here. That is all handled by the common +framework code and struct clk. + +Let's walk through enabling this clk from driver code: + + struct clk *clk; + clk = clk_get(NULL, "my_gateable_clk"); + + clk_prepare(clk); + clk_enable(clk); + +The call graph for clk_enable is very simple: + +clk_enable(clk); + clk->ops->enable(clk->hw); + [resolves to...] + clk_gate_enable(hw); + [resolves struct clk gate with to_clk_gate(hw)] + clk_gate_set_bit(gate); + +And the definition of clk_gate_set_bit: + +static void clk_gate_set_bit(struct clk_gate *gate) +{ + u32 reg; + + reg = __raw_readl(gate->reg); + reg |= BIT(gate->bit_idx); + writel(reg, gate->reg); +} + +Note that to_clk_gate is defined as: + +#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, clk) + +This pattern of abstraction is used for every clock hardware +representation. + + Part 4 - supporting your own clk hardware + +When implementing support for a new type of clock it only necessary to +include the following header: + +#include <linux/clk-provider.h> + +include/linux/clk.h is included within that header and clk-private.h +must never be included from the code which implements the operations for +a clock. More on that below in Part 5. + +To construct a clk hardware structure for your platform you must define +the following: + +struct clk_foo { + struct clk_hw hw; + ... hardware specific data goes here ... +}; + +To take advantage of your data you'll need to support valid operations +for your clk: + +struct clk_ops clk_foo_ops { + .enable = &clk_foo_enable; + .disable = &clk_foo_disable; +}; + +Implement the above functions using container_of: + +#define to_clk_foo(_hw) container_of(_hw, struct clk_foo, hw) + +int clk_foo_enable(struct clk_hw *hw) +{ + struct clk_foo *foo; + + foo = to_clk_foo(hw); + + ... perform magic on foo ... + + return 0; +}; + +Below is a matrix detailing which clk_ops are mandatory based upon the +hardware capbilities of that clock. A cell marked as "y" means +mandatory, a cell marked as "n" implies that either including that +callback is invalid or otherwise uneccesary. Empty cells are either +optional or must be evaluated on a case-by-case basis. + + clock hardware characteristics + ----------------------------------------------------------- + | gate | change rate | single parent | multiplexer | root | + |------|-------------|---------------|-------------|------| +.prepare | | | | | | +.unprepare | | | | | | + | | | | | | +.enable | y | | | | | +.disable | y | | | | | +.is_enabled | y | | | | | + | | | | | | +.recalc_rate | | y | | | | +.round_rate | | y | | | | +.set_rate | | y | | | | + | | | | | | +.set_parent | | | n | y | n | +.get_parent | | | n | y | n | + | | | | | | +.init | | | | | | + ----------------------------------------------------------- + +Finally, register your clock at run-time with a hardware-specific +registration function. This function simply populates struct clk_foo's +data and then passes the common struct clk parameters to the framework +with a call to: + +clk_register(...) + +See the basic clock types in drivers/clk/clk-*.c for examples. + + Part 5 - static initialization of clock data + +For platforms with many clocks (often numbering into the hundreds) it +may be desirable to statically initialize some clock data. This +presents a problem since the definition of struct clk should be hidden +from everyone except for the clock core in drivers/clk/clk.c. + +To get around this problem struct clk's definition is exposed in +include/linux/clk-private.h along with some macros for more easily +initializing instances of the basic clock types. These clocks must +still be initialized with the common clock framework via a call to +__clk_init. + +clk-private.h must NEVER be included by code which implements struct +clk_ops callbacks, nor must it be included by any logic which pokes +around inside of struct clk at run-time. To do so is a layering +violation. + +To better enforce this policy, always follow this simple rule: any +statically initialized clock data MUST be defined in a separate file +from the logic that implements its ops. Basically separate the logic +from the data and all is well.
On Fri, Mar 09, 2012 at 11:54:22PM -0800, Mike Turquette wrote:
Provide documentation for the common clk structures and APIs. This code can be found in drivers/clk/ and include/linux/clk*.h.
Hi Mike
Please feel free to add:
Reviewed-by: Andrew Lunn andrew@lunn.ch
Andrew
The common clock framework defines a common struct clk useful across most platforms as well as an implementation of the clk api that drivers can use safely for managing clocks.
The net result is consolidation of many different struct clk definitions and platform-specific clock framework implementations.
This patch introduces the common struct clk, struct clk_ops and an implementation of the well-known clock api in include/clk/clk.h. Platforms may define their own hardware-specific clock structure and their own clock operation callbacks, so long as it wraps an instance of struct clk_hw.
See Documentation/clk.txt for more details.
This patch is based on the work of Jeremy Kerr, which in turn was based on the work of Ben Herrenschmidt.
Signed-off-by: Mike Turquette mturquette@linaro.org Signed-off-by: Mike Turquette mturquette@ti.com Cc: Russell King linux@arm.linux.org.uk Cc: Jeremy Kerr jeremy.kerr@canonical.com Cc: Thomas Gleixner tglx@linutronix.de Cc: Arnd Bergman arnd.bergmann@linaro.org Cc: Paul Walmsley paul@pwsan.com Cc: Shawn Guo shawn.guo@freescale.com Cc: Sascha Hauer s.hauer@pengutronix.de Cc: Richard Zhao richard.zhao@linaro.org Cc: Saravana Kannan skannan@codeaurora.org Cc: Magnus Damm magnus.damm@gmail.com Cc: Rob Herring rob.herring@calxeda.com Cc: Mark Brown broonie@opensource.wolfsonmicro.com Cc: Linus Walleij linus.walleij@stericsson.com Cc: Stephen Boyd sboyd@codeaurora.org Cc: Amit Kucheria amit.kucheria@linaro.org Cc: Deepak Saxena dsaxena@linaro.org Cc: Grant Likely grant.likely@secretlab.ca Cc: Andrew Lunn andrew@lunn.ch --- Changes since v5: * new CONFIG_COMMON_CLK_DISABLE_UNUSED feature * results in a new clk_op callback, .is_enabled * new helpers * __clk_get_prepare_count * __clk_get_enable_count * __clk_is_enabled * fix bug in __clk_get_rate for orphan clocks
drivers/clk/Kconfig | 39 ++ drivers/clk/Makefile | 1 + drivers/clk/clk.c | 1424 ++++++++++++++++++++++++++++++++++++++++++ include/linux/clk-private.h | 68 ++ include/linux/clk-provider.h | 171 +++++ include/linux/clk.h | 68 ++- 6 files changed, 1766 insertions(+), 5 deletions(-) create mode 100644 drivers/clk/clk.c create mode 100644 include/linux/clk-private.h create mode 100644 include/linux/clk-provider.h
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 9b3cd08..31ceb27 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -8,3 +8,42 @@ config HAVE_CLK_PREPARE
config HAVE_MACH_CLKDEV bool + +menuconfig COMMON_CLK + bool "Common Clock Framework" + select HAVE_CLK_PREPARE + ---help--- + The common clock framework is a single definition of struct + clk, useful across many platforms, as well as an + implementation of the clock API in include/linux/clk.h. + Architectures utilizing the common struct clk should select + this automatically, but it may be necessary to manually select + this option for loadable modules requiring the common clock + framework. + + If in doubt, say "N". + +if COMMON_CLK + +config COMMON_CLK_DISABLE_UNUSED + bool "Disabled unused clocks at boot" + depends on COMMON_CLK + ---help--- + Traverses the entire clock tree and disables any clocks that are + enabled in hardware but have not been enabled by any device drivers. + This saves power and keeps the software model of the clock in line + with reality. + + If in doubt, say "N". + +config COMMON_CLK_DEBUG + bool "DebugFS representation of clock tree" + depends on COMMON_CLK + ---help--- + Creates a directory hierchy in debugfs for visualizing the clk + tree structure. Each directory contains read-only members + that export information specific to that clk node: clk_rate, + clk_flags, clk_prepare_count, clk_enable_count & + clk_notifier_count. + +endif diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 07613fa..ff362c4 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -1,2 +1,3 @@
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o +obj-$(CONFIG_COMMON_CLK) += clk.o diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c new file mode 100644 index 0000000..c7c3bc5 --- /dev/null +++ b/drivers/clk/clk.c @@ -0,0 +1,1424 @@ +/* + * Copyright (C) 2010-2011 Canonical Ltd 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. + * + * Standard functionality for the common clock API. See Documentation/clk.txt + */ + +#include <linux/clk-private.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/spinlock.h> +#include <linux/err.h> +#include <linux/list.h> +#include <linux/slab.h> + +static DEFINE_SPINLOCK(enable_lock); +static DEFINE_MUTEX(prepare_lock); + +static HLIST_HEAD(clk_root_list); +static HLIST_HEAD(clk_orphan_list); +static LIST_HEAD(clk_notifier_list); + +/*** debugfs support ***/ + +#ifdef CONFIG_COMMON_CLK_DEBUG +#include <linux/debugfs.h> + +static struct dentry *rootdir; +static struct dentry *orphandir; +static int inited = 0; + +/* caller must hold prepare_lock */ +static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry) +{ + struct dentry *d; + int ret = -ENOMEM; + + if (!clk || !pdentry) { + ret = -EINVAL; + goto out; + } + + d = debugfs_create_dir(clk->name, pdentry); + if (!d) + goto out; + + clk->dentry = d; + + d = debugfs_create_u32("clk_rate", S_IRUGO, clk->dentry, + (u32 *)&clk->rate); + if (!d) + goto err_out; + + d = debugfs_create_x32("clk_flags", S_IRUGO, clk->dentry, + (u32 *)&clk->flags); + if (!d) + goto err_out; + + d = debugfs_create_u32("clk_prepare_count", S_IRUGO, clk->dentry, + (u32 *)&clk->prepare_count); + if (!d) + goto err_out; + + d = debugfs_create_u32("clk_enable_count", S_IRUGO, clk->dentry, + (u32 *)&clk->enable_count); + if (!d) + goto err_out; + + d = debugfs_create_u32("clk_notifier_count", S_IRUGO, clk->dentry, + (u32 *)&clk->notifier_count); + if (!d) + goto err_out; + + ret = 0; + goto out; + +err_out: + debugfs_remove(clk->dentry); +out: + return ret; +} + +/* caller must hold prepare_lock */ +static int clk_debug_create_subtree(struct clk *clk, struct dentry *pdentry) +{ + struct clk *child; + struct hlist_node *tmp; + int ret = -EINVAL;; + + if (!clk || !pdentry) + goto out; + + ret = clk_debug_create_one(clk, pdentry); + + if (ret) + goto out; + + hlist_for_each_entry(child, tmp, &clk->children, child_node) + clk_debug_create_subtree(child, clk->dentry); + + ret = 0; +out: + return ret; +} + +/** + * clk_debug_register - add a clk node to the debugfs clk tree + * @clk: the clk being added to the debugfs clk tree + * + * Dynamically adds a clk to the debugfs clk tree if debugfs has been + * initialized. Otherwise it bails out early since the debugfs clk tree + * will be created lazily by clk_debug_init as part of a late_initcall. + * + * Caller must hold prepare_lock. Only clk_init calls this function (so + * far) so this is taken care. + */ +static int clk_debug_register(struct clk *clk) +{ + struct clk *parent; + struct dentry *pdentry; + int ret = 0; + + if (!inited) + goto out; + + parent = clk->parent; + + /* + * Check to see if a clk is a root clk. Also check that it is + * safe to add this clk to debugfs + */ + if (!parent) + if (clk->flags & CLK_IS_ROOT) + pdentry = rootdir; + else + pdentry = orphandir; + else + if (parent->dentry) + pdentry = parent->dentry; + else + goto out; + + ret = clk_debug_create_subtree(clk, pdentry); + +out: + return ret; +} + +/** + * clk_debug_init - lazily create the debugfs clk tree visualization + * + * clks are often initialized very early during boot before memory can + * be dynamically allocated and well before debugfs is setup. + * clk_debug_init walks the clk tree hierarchy while holding + * prepare_lock and creates the topology as part of a late_initcall, + * thus insuring that clks initialized very early will still be + * represented in the debugfs clk tree. This function should only be + * called once at boot-time, and all other clks added dynamically will + * be done so with clk_debug_register. + */ +static int __init clk_debug_init(void) +{ + struct clk *clk; + struct hlist_node *tmp; + + rootdir = debugfs_create_dir("clk", NULL); + + if (!rootdir) + return -ENOMEM; + + orphandir = debugfs_create_dir("orphans", rootdir); + + if (!orphandir) + return -ENOMEM; + + mutex_lock(&prepare_lock); + + hlist_for_each_entry(clk, tmp, &clk_root_list, child_node) + clk_debug_create_subtree(clk, rootdir); + + hlist_for_each_entry(clk, tmp, &clk_orphan_list, child_node) + clk_debug_create_subtree(clk, orphandir); + + inited = 1; + + mutex_unlock(&prepare_lock); + + return 0; +} +late_initcall(clk_debug_init); +#else +static inline int clk_debug_register(struct clk *clk) { return 0; } +#endif /* CONFIG_COMMON_CLK_DEBUG */ + +#ifdef CONFIG_COMMON_CLK_DISABLE_UNUSED +/* caller must hold prepare_lock */ +static void clk_disable_unused_subtree(struct clk *clk) +{ + struct clk *child; + struct hlist_node *tmp; + unsigned long flags; + + if (!clk) + goto out; + + hlist_for_each_entry(child, tmp, &clk->children, child_node) + clk_disable_unused_subtree(child); + + spin_lock_irqsave(&enable_lock, flags); + + if (clk->enable_count) + goto unlock_out; + + if (clk->flags & CLK_IGNORE_UNUSED) + goto unlock_out; + + if (__clk_is_enabled(clk) && clk->ops->disable) + clk->ops->disable(clk->hw); + +unlock_out: + spin_unlock_irqrestore(&enable_lock, flags); + +out: + return; +} + +static int clk_disable_unused(void) +{ + struct clk *clk; + struct hlist_node *tmp; + + mutex_lock(&prepare_lock); + + hlist_for_each_entry(clk, tmp, &clk_root_list, child_node) + clk_disable_unused_subtree(clk); + + hlist_for_each_entry(clk, tmp, &clk_orphan_list, child_node) + clk_disable_unused_subtree(clk); + + mutex_unlock(&prepare_lock); + + return 0; +} +late_initcall(clk_disable_unused); +#else +static inline int clk_disable_unused(struct clk *clk) { return 0; } +#endif /* CONFIG_COMMON_CLK_DISABLE_UNUSED */ + +/*** helper functions ***/ + +inline const char *__clk_get_name(struct clk *clk) +{ + return !clk ? NULL : clk->name; +} + +inline struct clk_hw *__clk_get_hw(struct clk *clk) +{ + return !clk ? NULL : clk->hw; +} + +inline u8 __clk_get_num_parents(struct clk *clk) +{ + return !clk ? -EINVAL : clk->num_parents; +} + +inline struct clk *__clk_get_parent(struct clk *clk) +{ + return !clk ? NULL : clk->parent; +} + +inline unsigned long __clk_get_enable_count(struct clk *clk) +{ + return !clk ? -EINVAL : clk->enable_count; +} + +inline unsigned long __clk_get_prepare_count(struct clk *clk) +{ + return !clk ? -EINVAL : clk->prepare_count; +} + +unsigned long __clk_get_rate(struct clk *clk) +{ + unsigned long ret; + + if (!clk) { + ret = -EINVAL; + goto out; + } + + ret = clk->rate; + + if (clk->flags & CLK_IS_ROOT) + goto out; + + if (!clk->parent) + ret = -ENODEV; + +out: + return ret; +} + +inline unsigned long __clk_get_flags(struct clk *clk) +{ + return !clk ? -EINVAL : clk->flags; +} + +int __clk_is_enabled(struct clk *clk) +{ + int ret; + + if (!clk) + return -EINVAL; + + /* + * .is_enabled is only mandatory for clocks that gate + * fall back to software usage counter if .is_enabled is missing + */ + if (!clk->ops->is_enabled) { + ret = clk->enable_count ? 1 : 0; + goto out; + } + + ret = clk->ops->is_enabled(clk->hw); +out: + return ret; +} + +static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk) +{ + struct clk *child; + struct clk *ret; + struct hlist_node *tmp; + + if (!strcmp(clk->name, name)) + return clk; + + hlist_for_each_entry(child, tmp, &clk->children, child_node) { + ret = __clk_lookup_subtree(name, child); + if (ret) + return ret; + } + + return NULL; +} + +struct clk *__clk_lookup(const char *name) +{ + struct clk *root_clk; + struct clk *ret; + struct hlist_node *tmp; + + /* search the 'proper' clk tree first */ + hlist_for_each_entry(root_clk, tmp, &clk_root_list, child_node) { + ret = __clk_lookup_subtree(name, root_clk); + if (ret) + return ret; + } + + /* if not found, then search the orphan tree */ + hlist_for_each_entry(root_clk, tmp, &clk_orphan_list, child_node) { + ret = __clk_lookup_subtree(name, root_clk); + if (ret) + return ret; + } + + return NULL; +} + +/*** clk api ***/ + +void __clk_unprepare(struct clk *clk) +{ + if (!clk) + return; + + if (WARN_ON(clk->prepare_count == 0)) + return; + + if (--clk->prepare_count > 0) + return; + + WARN_ON(clk->enable_count > 0); + + if (clk->ops->unprepare) + clk->ops->unprepare(clk->hw); + + __clk_unprepare(clk->parent); +} + +/** + * clk_unprepare - undo preparation of a clock source + * @clk: the clk being unprepare + * + * clk_unprepare may sleep, which differentiates it from clk_disable. In a + * simple case, clk_unprepare can be used instead of clk_disable to gate a clk + * if the operation may sleep. One example is a clk which is accessed over + * I2c. 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_unprepare(struct clk *clk) +{ + mutex_lock(&prepare_lock); + __clk_unprepare(clk); + mutex_unlock(&prepare_lock); +} +EXPORT_SYMBOL_GPL(clk_unprepare); + +int __clk_prepare(struct clk *clk) +{ + int ret = 0; + + if (!clk) + return 0; + + if (clk->prepare_count == 0) { + ret = __clk_prepare(clk->parent); + if (ret) + return ret; + + if (clk->ops->prepare) { + ret = clk->ops->prepare(clk->hw); + if (ret) { + __clk_unprepare(clk->parent); + return ret; + } + } + } + + clk->prepare_count++; + + return 0; +} + +/** + * clk_prepare - prepare a clock source + * @clk: the clk being prepared + * + * clk_prepare may sleep, which differentiates it from clk_enable. In a simple + * case, clk_prepare can be used instead of clk_enable to ungate a clk if the + * operation may sleep. One example is a clk which is accessed over I2c. In + * the complex case a clk ungate operation may require a fast and a slow part. + * It is this reason that clk_prepare and clk_enable are not mutually + * exclusive. In fact clk_prepare must be called before clk_enable. + * Returns 0 on success, -EERROR otherwise. + */ +int clk_prepare(struct clk *clk) +{ + int ret; + + mutex_lock(&prepare_lock); + ret = __clk_prepare(clk); + mutex_unlock(&prepare_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(clk_prepare); + +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); +} + +/** + * 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); + + if (ret) + return ret; + + if (clk->ops->enable) { + ret = clk->ops->enable(clk->hw); + if (ret) { + __clk_disable(clk->parent); + 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) + 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; +} +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; + + 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; + } + +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 (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) + return clk; + } + + /* change the rate of this clk */ + if (clk->ops->set_rate) + ret = clk->ops->set_rate(clk->hw, new_rate); + + if (ret == NOTIFY_BAD) + 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); + + 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); + 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)); + + /* + * 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. + * + * 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); + } + + 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. + * + * 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..09dea1f --- /dev/null +++ b/include/linux/clk-provider.h @@ -0,0 +1,171 @@ +/* + * 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 */ +#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); + int (*is_enabled)(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); +int __clk_is_enabled(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); +unsigned long __clk_round_rate(struct clk *clk, unsigned long rate); + +#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.
On Fri, 9 Mar 2012, Mike Turquette wrote:
+inline unsigned long __clk_get_enable_count(struct clk *clk) +{
- return !clk ? -EINVAL : clk->enable_count;
Returning negative error codes in a function with a return value unsigned long is a bit strange at least. Shouldn't that be long ?
+#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.
Now the question is whether you should provide a data structure which is explicitely used for static initialization and instead of having struct clk static you register the static initializer structure, which would be initdata. I don't think that anything needs clocks before the memory allocators are up and running. The clocks which are necessary to get that far have to be enabled in the boot loader anyway.
The static initialization question should not hold off this set from being merged, though settling it before growing users would be nice.
Otherwise this is a very well done infrastructure implementation! Thanks a lot Mike!
Reviewed-by: Thomas Gleixner tglx@linutronix.de
On Fri, Mar 09, 2012 at 11:54:23PM -0800, Mike Turquette wrote:
The common clock framework defines a common struct clk useful across most platforms as well as an implementation of the clk api that drivers can use safely for managing clocks.
Hi Mike
Please feel free to add:
Tested-by: Andrew Lunn andrew@lunn.ch
Andrew
Looks like you didn't take my comments for v5. http://www.spinics.net/lists/arm-kernel/msg162903.html
Regards Richard
On Sat, Mar 10, 2012 at 11:52 PM, Richard Zhao richard.zhao@linaro.org wrote:
Looks like you didn't take my comments for v5. http://www.spinics.net/lists/arm-kernel/msg162903.html
Sorry Richard, that one slipped through the cracks. I'll publish a new version tomorrow with some of those fixes. Some of the others (such as multiple pre-rate change notifiers) I won't take in, but we can discuss more.
Regards, Mike
Regards Richard
Hi Mike,
I was about to give my tested-by when I decided to test the set_rate function. Unfortunately this is broken for several reasons. I'll try to come up with a fixup series later the day.
On Fri, Mar 09, 2012 at 11:54:23PM -0800, Mike Turquette wrote:
+/**
- 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);
You don't need a WARN_ON when you derefence clk->ops->round_rate anyway. Also, even when the current clock does not have a set_rate function it can still change its rate when the CLK_SET_RATE_PARENT is set.
- /* NOTE: pre-rate change notifications will stack */
- if (clk->notifier_count)
ret = __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, new_rate);
- 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)
return clk;
- }
- /* change the rate of this clk */
- if (clk->ops->set_rate)
ret = clk->ops->set_rate(clk->hw, new_rate);
I don't know the reason why you change the child clock before the parent clock, but it cannot work since this clock will change its rate based on the old parent rate and not the new one.
There are more things, as said I'll try to come up with a fixup series.
Sascha
On Sun, Mar 11, 2012 at 4:34 AM, Sascha Hauer s.hauer@pengutronix.de wrote:
Hi Mike,
I was about to give my tested-by when I decided to test the set_rate function. Unfortunately this is broken for several reasons. I'll try to come up with a fixup series later the day.
I haven't tested clk_set_rate since V4, but I also haven't changed the code appreciably. I'll retest on my end also.
On Fri, Mar 09, 2012 at 11:54:23PM -0800, Mike Turquette wrote:
- /* 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);
You don't need a WARN_ON when you derefence clk->ops->round_rate anyway.
Agreed that the WARN_ON should not be there.
The v6 Documentation/clk.txt states that .round_rate is mandatory for clocks that can adjust their rate, but I need to clarify this a bit more. Ideally we want to be able to call clk_set_rate on any clock and get a changed rate (if possible) by either adjusting that clocks rate direction (e.g. a PLL or an adjustable divider) or by propagating __clk_set_rate up the parents (assuming of course that CLK_SET_RATE_PARENT flag is set appropriately).
Also, even when the current clock does not have a set_rate function it can still change its rate when the CLK_SET_RATE_PARENT is set.
Correct. I'll clean this up and make the documentation a bit more verbose on when .set_rate/.round_rate/.recalc_rate are mandatory.
- /* NOTE: pre-rate change notifications will stack */
- if (clk->notifier_count)
- ret = __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, new_rate);
- 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)
- return clk;
- }
- /* change the rate of this clk */
- if (clk->ops->set_rate)
- ret = clk->ops->set_rate(clk->hw, new_rate);
I don't know the reason why you change the child clock before the parent clock, but it cannot work since this clock will change its rate based on the old parent rate and not the new one.
This depends on the .round_rate implementation, which I admit to having lost some sleep over. A clever .round_rate will request the "intermediate" rate for a clock when propagating a request to change the parent rate later on. Take for instance the following:
pll @ 200MHz (locked) | parent @ 100MHz (can divide by 1 or 2; currently divider is 2) | child @ 25MHz (can divide by 2 or 4; currently divider is 4)
If we want child to run at 100MHz then the desirable configuration would be to have parent divide-by-1 and child divide-by-2. When we call,
clk_set_rate(child, 100MHz);
Its .round_rate should return 50MHz, and &parent_new_rate should be 200MHz. So 50MHz is an "intermediate" rate, but it gets us the divider we want. And in fact 50MHz reflects reality because that will be the rate of child until the parent propagation completes and we can adjust parent's dividers. (this is one reason why I prefer for pre-rate change notifiers to stack on top of each other).
So now that &parent_new_rate is > 0, __clk_set_rate will propagate the request up and parent's .round_rate will simply return 200MHz and leave it's own &parent_new_rate at 0. This will change from divide-by-2 to divide-by-1 and from this highest point in the tree we will propagate post-rate change notifiers downstream, as part of the recalc_rate tree walk.
I have tested this with OMAP4's CPUfreq driver and I think, while complicated, it is a sound way to approach the problem. Maybe the API can be cleaned up, if you have any suggestions.
Regards, Mike
There are more things, as said I'll try to come up with a fixup series.
Sascha
-- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
On Sun, Mar 11, 2012 at 02:24:46PM -0700, Turquette, Mike wrote:
On Sun, Mar 11, 2012 at 4:34 AM, Sascha Hauer s.hauer@pengutronix.de wrote:
Hi Mike,
I was about to give my tested-by when I decided to test the set_rate function. Unfortunately this is broken for several reasons. I'll try to come up with a fixup series later the day.
I haven't tested clk_set_rate since V4, but I also haven't changed the code appreciably. I'll retest on my end also.
On Fri, Mar 09, 2012 at 11:54:23PM -0800, Mike Turquette wrote:
- /* 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);
You don't need a WARN_ON when you derefence clk->ops->round_rate anyway.
Agreed that the WARN_ON should not be there.
The v6 Documentation/clk.txt states that .round_rate is mandatory for clocks that can adjust their rate, but I need to clarify this a bit more. Ideally we want to be able to call clk_set_rate on any clock and get a changed rate (if possible) by either adjusting that clocks rate direction (e.g. a PLL or an adjustable divider) or by propagating __clk_set_rate up the parents (assuming of course that CLK_SET_RATE_PARENT flag is set appropriately).
Also, even when the current clock does not have a set_rate function it can still change its rate when the CLK_SET_RATE_PARENT is set.
Correct. I'll clean this up and make the documentation a bit more verbose on when .set_rate/.round_rate/.recalc_rate are mandatory.
- /* NOTE: pre-rate change notifications will stack */
- if (clk->notifier_count)
- ret = __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, new_rate);
- 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)
- return clk;
- }
- /* change the rate of this clk */
- if (clk->ops->set_rate)
- ret = clk->ops->set_rate(clk->hw, new_rate);
I don't know the reason why you change the child clock before the parent clock, but it cannot work since this clock will change its rate based on the old parent rate and not the new one.
This depends on the .round_rate implementation, which I admit to having lost some sleep over. A clever .round_rate will request the "intermediate" rate for a clock when propagating a request to change the parent rate later on. Take for instance the following:
pll @ 200MHz (locked) | parent @ 100MHz (can divide by 1 or 2; currently divider is 2) | child @ 25MHz (can divide by 2 or 4; currently divider is 4)
If we want child to run at 100MHz then the desirable configuration would be to have parent divide-by-1 and child divide-by-2. When we call,
clk_set_rate(child, 100MHz);
Its .round_rate should return 50MHz, and &parent_new_rate should be 200MHz. So 50MHz is an "intermediate" rate, but it gets us the divider we want. And in fact 50MHz reflects reality because that will be the rate of child until the parent propagation completes and we can adjust parent's dividers. (this is one reason why I prefer for pre-rate change notifiers to stack on top of each other).
So now that &parent_new_rate is > 0, __clk_set_rate will propagate the request up and parent's .round_rate will simply return 200MHz and leave it's own &parent_new_rate at 0. This will change from divide-by-2 to divide-by-1 and from this highest point in the tree we will propagate post-rate change notifiers downstream, as part of the recalc_rate tree walk.
I have tested this with OMAP4's CPUfreq driver and I think, while complicated, it is a sound way to approach the problem. Maybe the API can be cleaned up, if you have any suggestions.
I cannot see all implications this way will have. All this rate propagation is more complex than I thought it would be. I tried another approach on the weekend which basically does not try to do all in a single recursion but instead sets the rate in multiple steps:
1) call a function which calculates all new rates of affected clocks in a rate change and safes the value in a clk->new_rate field. This function returns the topmost clock which has to be changed. 2) starting from the topmost clock notify all clients. This walks the whole subtree even if a notfifier refuses the change. If necessary we can walk the whole subtree again to abort the change. 3) actually change rates starting from the topmost clocks and notify all clients on the way. I changed the set_rate callback to void. Instead of failing (what is failing in case of set_rate? The clock will still have some rate) I check for the result with clk_ops->recalc_rate.
In the end what's more important than the implementation details is that it actually works. I created a little test module which sets up two cascaded dividers, tries to change the rate at the output and checks the result. We might want to add something like this (and maybe similar tests for reparenting and other stuff) to the generic clock framework later. It's good to have something generic to test the framework with without depending on some particular SoC.
Sascha
8<----------------------------------------------------
clk: Add clock test module
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- drivers/clk/clk-test.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 169 insertions(+), 0 deletions(-) create mode 100644 drivers/clk/clk-test.c
diff --git a/drivers/clk/clk-test.c b/drivers/clk/clk-test.c new file mode 100644 index 0000000..6f901fd --- /dev/null +++ b/drivers/clk/clk-test.c @@ -0,0 +1,169 @@ +#include <linux/spinlock.h> +#include <linux/clk-provider.h> +#include <linux/clk.h> +#include <linux/module.h> + +/* + * We build a fixed rate source clock with two cascaded 2bit dividers: + * + * f1 -> div1 -> div2 + * + * and try set the rate of div2 from 0Hz to f1 + 1 Hz. + * + * This makes the following resulting dividers possible: + * + * 1, 2, 4, 6, 8, 9, 12, 16 + * + * Sometimes there are different results possible due to integer maths. + * For example if we have an input frequency of 100Hz and request an + * output of 16Hz the best divider values would be 2 and 4 resulting + * in a real frequency of 12.5Hz. We also accept 2 and 3 as result + * because 100 / (3 * 2) = 16.6667 which is too high, but multiplying + * 16 * 3 * 2 results in 96Hz which is lower than 100Hz. + * + */ + +static unsigned long div1_reg, div2_reg; + +static struct clk *f1, *div1, *div2; + +static DEFINE_SPINLOCK(imx_ccm_lock); + +//#define FIXED_RATE 144 +#define FIXED_RATE 100 + +static inline struct clk *register_divider(const char *name, const char *parent, + void __iomem *reg, u8 shift, u8 width) +{ + return clk_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT, + reg, shift, width, 0, &imx_ccm_lock); +} + +static unsigned long divs[] = { + 1, 2, 3, 4, 6, 8, 9, 12, 16, +}; + +static int check_rounded_rate(unsigned long want, unsigned long rounded) +{ + int i, j; + unsigned long best1 = 0, best2 = 0, now; + + if (want > FIXED_RATE) { + best1 = best2 = FIXED_RATE; + goto found2; + } + + for (i = 1; i <= 4; i++) { + for (j = 1; j <= 4; j++) { + now = FIXED_RATE / i / j; + if (now <= want && now > best1) + best1 = now; + } + } + + if (!best1) + best1 = (FIXED_RATE / 4) / 4; + + for (i = 0; i < ARRAY_SIZE(divs); i++) { + if (FIXED_RATE <= want * divs[i]) { + best2 = FIXED_RATE / divs[i]; + goto found2; + } + } + + if (!best2) + best2 = FIXED_RATE / 16; +found2: + if (rounded != best1 && rounded != best2) { + if (best1 == best2) + printk("clk-test: wanted rate %ld, best result would be %ld," + " but we have %ld\n", + want, best1, rounded); + else + printk("clk-test: wanted rate %ld, best result would be %ld or %ld," + " but we have %ld\n", + want, best1, best2, rounded); + return -EINVAL; + } + + return 0; +} + +static int check_real_rate(unsigned long rate) +{ + unsigned long realrate1, realrate2; + + realrate1 = FIXED_RATE / (div1_reg + 1) / (div2_reg + 1); + realrate2 = FIXED_RATE / ((div1_reg + 1) * (div2_reg + 1)); + + if (rate != realrate1 && rate != realrate2) { + if (realrate1 == realrate2) + printk("clk-test: divider returns rate %ld, but instead has %ld\n", + rate, realrate1); + else + printk("clk-test: divider returns rate %ld, but instead has %ld or %ld\n", + rate, realrate1, realrate2); + return -EINVAL; + } + + return 0; +} + +static int set_rate_test(void) +{ + unsigned long i, rate, rounded; + int ret, errors = 0; + + for (i = 0; i < FIXED_RATE + 1; i++) { + rounded = clk_round_rate(div2, i); + ret = check_rounded_rate(i, rounded); + if (ret) + errors++; + ret = clk_set_rate(div2, i); + if (ret) { + printk("%s: setting rate of div2 to %ld failed with %d\n", + __func__, i, ret); + errors++; + } + + rate = clk_get_rate(div2); + + if (rounded != rate) { + printk("clk_test: wanted %ld, core rounded to %ld, have now: %ld\n", + i, rounded, rate); + errors++; + } + + ret = check_real_rate(rate); + if (ret) + errors++; + } + + return errors; +} + +static int clk_test_init(void) +{ + int errors; + + f1 = clk_register_fixed_rate(NULL, "f1", NULL, CLK_IS_ROOT, FIXED_RATE); + div1 = register_divider("div1", "f1", &div1_reg, 0, 2); + div2 = register_divider("div2", "div1", &div2_reg, 0, 2); + + if (!f1 || !div1 || !div2) { + printk("clk-test: failed to register clocks\n"); + return -EINVAL; + } + + errors = set_rate_test(); + + printk("clk-test: finished with %d errors\n", errors); +#if 0 + /* Oh, oh */ + clk_unregister(f1); + clk_unregister(div1); + clk_unregister(div2); +#endif + return -EINVAL; +} +subsys_initcall(clk_test_init);
On Mon, Mar 12, 2012 at 4:51 AM, Sascha Hauer s.hauer@pengutronix.de wrote:
On Sun, Mar 11, 2012 at 02:24:46PM -0700, Turquette, Mike wrote:
On Sun, Mar 11, 2012 at 4:34 AM, Sascha Hauer s.hauer@pengutronix.de wrote:
Hi Mike,
I was about to give my tested-by when I decided to test the set_rate function. Unfortunately this is broken for several reasons. I'll try to come up with a fixup series later the day.
I haven't tested clk_set_rate since V4, but I also haven't changed the code appreciably. I'll retest on my end also.
On Fri, Mar 09, 2012 at 11:54:23PM -0800, Mike Turquette wrote:
- /* 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);
You don't need a WARN_ON when you derefence clk->ops->round_rate anyway.
Agreed that the WARN_ON should not be there.
The v6 Documentation/clk.txt states that .round_rate is mandatory for clocks that can adjust their rate, but I need to clarify this a bit more. Ideally we want to be able to call clk_set_rate on any clock and get a changed rate (if possible) by either adjusting that clocks rate direction (e.g. a PLL or an adjustable divider) or by propagating __clk_set_rate up the parents (assuming of course that CLK_SET_RATE_PARENT flag is set appropriately).
Also, even when the current clock does not have a set_rate function it can still change its rate when the CLK_SET_RATE_PARENT is set.
Correct. I'll clean this up and make the documentation a bit more verbose on when .set_rate/.round_rate/.recalc_rate are mandatory.
- /* NOTE: pre-rate change notifications will stack */
- if (clk->notifier_count)
- ret = __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, new_rate);
- 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)
- return clk;
- }
- /* change the rate of this clk */
- if (clk->ops->set_rate)
- ret = clk->ops->set_rate(clk->hw, new_rate);
I don't know the reason why you change the child clock before the parent clock, but it cannot work since this clock will change its rate based on the old parent rate and not the new one.
This depends on the .round_rate implementation, which I admit to having lost some sleep over. A clever .round_rate will request the "intermediate" rate for a clock when propagating a request to change the parent rate later on. Take for instance the following:
pll @ 200MHz (locked) | parent @ 100MHz (can divide by 1 or 2; currently divider is 2) | child @ 25MHz (can divide by 2 or 4; currently divider is 4)
If we want child to run at 100MHz then the desirable configuration would be to have parent divide-by-1 and child divide-by-2. When we call,
clk_set_rate(child, 100MHz);
Its .round_rate should return 50MHz, and &parent_new_rate should be 200MHz. So 50MHz is an "intermediate" rate, but it gets us the divider we want. And in fact 50MHz reflects reality because that will be the rate of child until the parent propagation completes and we can adjust parent's dividers. (this is one reason why I prefer for pre-rate change notifiers to stack on top of each other).
So now that &parent_new_rate is > 0, __clk_set_rate will propagate the request up and parent's .round_rate will simply return 200MHz and leave it's own &parent_new_rate at 0. This will change from divide-by-2 to divide-by-1 and from this highest point in the tree we will propagate post-rate change notifiers downstream, as part of the recalc_rate tree walk.
I have tested this with OMAP4's CPUfreq driver and I think, while complicated, it is a sound way to approach the problem. Maybe the API can be cleaned up, if you have any suggestions.
I cannot see all implications this way will have. All this rate propagation is more complex than I thought it would be.
Hi Sascha,
Yes it is very complicated. The solution I have now (recursive __clk_set_rate, clever .round_rate which requests parent rate) was not something I arrived at immediately.
I decided to validate the v6 patches more thoroughly today, based on your claim that clk_set_rate is broken and here is what I found:
1) clk_set_rate works. I pulled in the latest OMAP4 CPUfreq code into my common clk branch and it Just Worked. This is a dumb implementation involving no upwards parent propagation, and the clock changing is of type struct clk_hw_omap (relocking a PLL)
2) while I was at it I verified the rate change notifiers + clk_set_parent, which also work (I had not touched these since v4 and wanted to make sure nothing was broken)
Here is where things get interesting. I tried the same parent rate propagation via CPUfreq that I had done previously in the v4 series (http://article.gmane.org/gmane.linux.ports.arm.omap/68225), but this time it didn't work. The difference is that back in v4 all of my clocks in that propagation chain were struct clk_hw_omap, none of them were any of the basic clock types. Now in v6, one of the clocks in the chain is struct clk_divider. I started looking at the divider's .round_rate code and for the case where CLK_PARENT_SET_RATE flag is set the code doesn't make any sense. I spent some time today trying to fix struct clk_divider's .round_rate implementation and came to realize that there might not be a sane default for how such code should work. A sane default for the common divider that works correctly on OMAP may not be what you want on iMX.
To illustrate: if CLK_SET_RATE_PARENT flag is set for my clk_divider I'd really like to divide by 1 and pass the exact same rate that was requested for my clk_divider up to the parent. But the existing divider code tries to find the largest div for clk_divider and request a faster rate from the parent (well, I assume this is what it is supposed to do as the code doesn't quite get this right).
Do you have any ideas on this? Also, can you verify if this is what was failing for you, or maybe provide a log if the bug you mentioned exists elsewhere? An extreme solution to the problem would be for clk_divider to not support the CLK_SET_PARENT flag if we cannot agree on a sane default for this behavior. I like the idea of the divider choosing the smallest div possible and requesting the balance from the parent, but I need feedback from others on that point. For non-rate adjustable clocks (clk_gate in particular) it is very easy to continue supporting this flag as the .round_rate implementation should just be a "pass through" up to the parent. In fact this behavior is what some of my omap clocks are doing and that is why parent propagation for CPUfreq was working for me back in v4.
I tried another approach on the weekend which basically does not try to do all in a single recursion but instead sets the rate in multiple steps:
- call a function which calculates all new rates of affected clocks
in a rate change and safes the value in a clk->new_rate field. This function returns the topmost clock which has to be changed. 2) starting from the topmost clock notify all clients. This walks the whole subtree even if a notfifier refuses the change. If necessary we can walk the whole subtree again to abort the change. 3) actually change rates starting from the topmost clocks and notify all clients on the way. I changed the set_rate callback to void. Instead of failing (what is failing in case of set_rate? The clock will still have some rate) I check for the result with clk_ops->recalc_rate.
I've considered something like this for "clock groups", especially when the set of clocks changing are all on the same device and the permutations are well known ahead of time. Is this working for you now?
In the end what's more important than the implementation details is that it actually works. I created a little test module which sets up two cascaded dividers, tries to change the rate at the output and checks the result. We might want to add something like this (and maybe similar tests for reparenting and other stuff) to the generic clock framework later. It's good to have something generic to test the framework with without depending on some particular SoC.
Agreed about the generic test. I'm not taking it into the current series, but we can grow the test cases and submit them later on.
Thanks, Mike
Sascha
8<----------------------------------------------------
clk: Add clock test module
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de
drivers/clk/clk-test.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 169 insertions(+), 0 deletions(-) create mode 100644 drivers/clk/clk-test.c
diff --git a/drivers/clk/clk-test.c b/drivers/clk/clk-test.c new file mode 100644 index 0000000..6f901fd --- /dev/null +++ b/drivers/clk/clk-test.c @@ -0,0 +1,169 @@ +#include <linux/spinlock.h> +#include <linux/clk-provider.h> +#include <linux/clk.h> +#include <linux/module.h>
+/*
- We build a fixed rate source clock with two cascaded 2bit dividers:
- f1 -> div1 -> div2
- and try set the rate of div2 from 0Hz to f1 + 1 Hz.
- This makes the following resulting dividers possible:
- 1, 2, 4, 6, 8, 9, 12, 16
- Sometimes there are different results possible due to integer maths.
- For example if we have an input frequency of 100Hz and request an
- output of 16Hz the best divider values would be 2 and 4 resulting
- in a real frequency of 12.5Hz. We also accept 2 and 3 as result
- because 100 / (3 * 2) = 16.6667 which is too high, but multiplying
- 16 * 3 * 2 results in 96Hz which is lower than 100Hz.
- */
+static unsigned long div1_reg, div2_reg;
+static struct clk *f1, *div1, *div2;
+static DEFINE_SPINLOCK(imx_ccm_lock);
+//#define FIXED_RATE 144 +#define FIXED_RATE 100
+static inline struct clk *register_divider(const char *name, const char *parent,
- void __iomem *reg, u8 shift, u8 width)
+{
- return clk_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT,
- reg, shift, width, 0, &imx_ccm_lock);
+}
+static unsigned long divs[] = {
- 1, 2, 3, 4, 6, 8, 9, 12, 16,
+};
+static int check_rounded_rate(unsigned long want, unsigned long rounded) +{
- int i, j;
- unsigned long best1 = 0, best2 = 0, now;
- if (want > FIXED_RATE) {
- best1 = best2 = FIXED_RATE;
- goto found2;
- }
- for (i = 1; i <= 4; i++) {
- for (j = 1; j <= 4; j++) {
- now = FIXED_RATE / i / j;
- if (now <= want && now > best1)
- best1 = now;
- }
- }
- if (!best1)
- best1 = (FIXED_RATE / 4) / 4;
- for (i = 0; i < ARRAY_SIZE(divs); i++) {
- if (FIXED_RATE <= want * divs[i]) {
- best2 = FIXED_RATE / divs[i];
- goto found2;
- }
- }
- if (!best2)
- best2 = FIXED_RATE / 16;
+found2:
- if (rounded != best1 && rounded != best2) {
- if (best1 == best2)
- printk("clk-test: wanted rate %ld, best result would be %ld,"
- " but we have %ld\n",
- want, best1, rounded);
- else
- printk("clk-test: wanted rate %ld, best result would be %ld or %ld,"
- " but we have %ld\n",
- want, best1, best2, rounded);
- return -EINVAL;
- }
- return 0;
+}
+static int check_real_rate(unsigned long rate) +{
- unsigned long realrate1, realrate2;
- realrate1 = FIXED_RATE / (div1_reg + 1) / (div2_reg + 1);
- realrate2 = FIXED_RATE / ((div1_reg + 1) * (div2_reg + 1));
- if (rate != realrate1 && rate != realrate2) {
- if (realrate1 == realrate2)
- printk("clk-test: divider returns rate %ld, but instead has %ld\n",
- rate, realrate1);
- else
- printk("clk-test: divider returns rate %ld, but instead has %ld or %ld\n",
- rate, realrate1, realrate2);
- return -EINVAL;
- }
- return 0;
+}
+static int set_rate_test(void) +{
- unsigned long i, rate, rounded;
- int ret, errors = 0;
- for (i = 0; i < FIXED_RATE + 1; i++) {
- rounded = clk_round_rate(div2, i);
- ret = check_rounded_rate(i, rounded);
- if (ret)
- errors++;
- ret = clk_set_rate(div2, i);
- if (ret) {
- printk("%s: setting rate of div2 to %ld failed with %d\n",
- __func__, i, ret);
- errors++;
- }
- rate = clk_get_rate(div2);
- if (rounded != rate) {
- printk("clk_test: wanted %ld, core rounded to %ld, have now: %ld\n",
- i, rounded, rate);
- errors++;
- }
- ret = check_real_rate(rate);
- if (ret)
- errors++;
- }
- return errors;
+}
+static int clk_test_init(void) +{
- int errors;
- f1 = clk_register_fixed_rate(NULL, "f1", NULL, CLK_IS_ROOT, FIXED_RATE);
- div1 = register_divider("div1", "f1", &div1_reg, 0, 2);
- div2 = register_divider("div2", "div1", &div2_reg, 0, 2);
- if (!f1 || !div1 || !div2) {
- printk("clk-test: failed to register clocks\n");
- return -EINVAL;
- }
- errors = set_rate_test();
- printk("clk-test: finished with %d errors\n", errors);
+#if 0
- /* Oh, oh */
- clk_unregister(f1);
- clk_unregister(div1);
- clk_unregister(div2);
+#endif
- return -EINVAL;
+}
+subsys_initcall(clk_test_init);
1.7.9.1
-- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
Hi Mike,
On Mon, Mar 12, 2012 at 08:16:36PM -0700, Turquette, Mike wrote:
On Mon, Mar 12, 2012 at 4:51 AM, Sascha Hauer s.hauer@pengutronix.de wrote:
On Sun, Mar 11, 2012 at 02:24:46PM -0700, Turquette, Mike wrote:
On Sun, Mar 11, 2012 at 4:34 AM, Sascha Hauer s.hauer@pengutronix.de wrote:
Hi Mike,
I was about to give my tested-by when I decided to test the set_rate function. Unfortunately this is broken for several reasons. I'll try to come up with a fixup series later the day.
I haven't tested clk_set_rate since V4, but I also haven't changed the code appreciably. I'll retest on my end also.
On Fri, Mar 09, 2012 at 11:54:23PM -0800, Mike Turquette wrote:
- /* 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);
You don't need a WARN_ON when you derefence clk->ops->round_rate anyway.
Agreed that the WARN_ON should not be there.
The v6 Documentation/clk.txt states that .round_rate is mandatory for clocks that can adjust their rate, but I need to clarify this a bit more. Ideally we want to be able to call clk_set_rate on any clock and get a changed rate (if possible) by either adjusting that clocks rate direction (e.g. a PLL or an adjustable divider) or by propagating __clk_set_rate up the parents (assuming of course that CLK_SET_RATE_PARENT flag is set appropriately).
Also, even when the current clock does not have a set_rate function it can still change its rate when the CLK_SET_RATE_PARENT is set.
Correct. I'll clean this up and make the documentation a bit more verbose on when .set_rate/.round_rate/.recalc_rate are mandatory.
- /* NOTE: pre-rate change notifications will stack */
- if (clk->notifier_count)
- ret = __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, new_rate);
- 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)
- return clk;
- }
- /* change the rate of this clk */
- if (clk->ops->set_rate)
- ret = clk->ops->set_rate(clk->hw, new_rate);
I don't know the reason why you change the child clock before the parent clock, but it cannot work since this clock will change its rate based on the old parent rate and not the new one.
This depends on the .round_rate implementation, which I admit to having lost some sleep over. A clever .round_rate will request the "intermediate" rate for a clock when propagating a request to change the parent rate later on. Take for instance the following:
pll @ 200MHz (locked) | parent @ 100MHz (can divide by 1 or 2; currently divider is 2) | child @ 25MHz (can divide by 2 or 4; currently divider is 4)
If we want child to run at 100MHz then the desirable configuration would be to have parent divide-by-1 and child divide-by-2. When we call,
clk_set_rate(child, 100MHz);
Its .round_rate should return 50MHz, and &parent_new_rate should be 200MHz. So 50MHz is an "intermediate" rate, but it gets us the divider we want. And in fact 50MHz reflects reality because that will be the rate of child until the parent propagation completes and we can adjust parent's dividers. (this is one reason why I prefer for pre-rate change notifiers to stack on top of each other).
So now that &parent_new_rate is > 0, __clk_set_rate will propagate the request up and parent's .round_rate will simply return 200MHz and leave it's own &parent_new_rate at 0. This will change from divide-by-2 to divide-by-1 and from this highest point in the tree we will propagate post-rate change notifiers downstream, as part of the recalc_rate tree walk.
I have tested this with OMAP4's CPUfreq driver and I think, while complicated, it is a sound way to approach the problem. Maybe the API can be cleaned up, if you have any suggestions.
I cannot see all implications this way will have. All this rate propagation is more complex than I thought it would be.
Hi Sascha,
Yes it is very complicated. The solution I have now (recursive __clk_set_rate, clever .round_rate which requests parent rate) was not something I arrived at immediately.
I decided to validate the v6 patches more thoroughly today, based on your claim that clk_set_rate is broken and here is what I found:
- clk_set_rate works. I pulled in the latest OMAP4 CPUfreq code into
my common clk branch and it Just Worked. This is a dumb implementation involving no upwards parent propagation, and the clock changing is of type struct clk_hw_omap (relocking a PLL)
- while I was at it I verified the rate change notifiers +
clk_set_parent, which also work (I had not touched these since v4 and wanted to make sure nothing was broken)
Here is where things get interesting. I tried the same parent rate propagation via CPUfreq that I had done previously in the v4 series (http://article.gmane.org/gmane.linux.ports.arm.omap/68225), but this time it didn't work. The difference is that back in v4 all of my clocks in that propagation chain were struct clk_hw_omap, none of them were any of the basic clock types. Now in v6, one of the clocks in the chain is struct clk_divider. I started looking at the divider's .round_rate code and for the case where CLK_PARENT_SET_RATE flag is set the code doesn't make any sense. I spent some time today trying to fix struct clk_divider's .round_rate implementation and came to realize that there might not be a sane default for how such code should work. A sane default for the common divider that works correctly on OMAP may not be what you want on iMX.
To illustrate: if CLK_SET_RATE_PARENT flag is set for my clk_divider I'd really like to divide by 1 and pass the exact same rate that was requested for my clk_divider up to the parent.
I don't understand this. If you use the CLK_SET_RATE_PARENT to force a divider value to 1 then why do you register a divider at all?
But the existing divider code tries to find the largest div for clk_divider and request a faster rate from the parent (well, I assume this is what it is supposed to do as the code doesn't quite get this right).
That's indeed different assumptions. When I set CLK_SET_RATE_PARENT I want to say to the divider that it is allowed to change the parent rate. So what it does (or should do) is to loop around its divider values and tries to round the parent rate to (rate * div). This way it can find the best divider values for this divider and the parent divider to get the wanted rate. This was done (almost) correctly in the version of the divider I posted to the list, but indeed the current version is broken.
Do you have any ideas on this? Also, can you verify if this is what was failing for you, or maybe provide a log if the bug you mentioned exists elsewhere? An extreme solution to the problem would be for clk_divider to not support the CLK_SET_PARENT flag if we cannot agree on a sane default for this behavior. I like the idea of the divider choosing the smallest div possible and requesting the balance from the parent, but I need feedback from others on that point.
As said, the divider tries to get the *best* value for itself and the parent divider (if exists), not the smallest. I think the current divider implements something between what I thought it should should do and what you thought it should do.
For non-rate adjustable clocks (clk_gate in particular) it is very easy to continue supporting this flag as the .round_rate implementation should just be a "pass through" up to the parent. In fact this behavior is what some of my omap clocks are doing and that is why parent propagation for CPUfreq was working for me back in v4.
I tried another approach on the weekend which basically does not try to do all in a single recursion but instead sets the rate in multiple steps:
- call a function which calculates all new rates of affected clocks
in a rate change and safes the value in a clk->new_rate field. This function returns the topmost clock which has to be changed. 2) starting from the topmost clock notify all clients. This walks the whole subtree even if a notfifier refuses the change. If necessary we can walk the whole subtree again to abort the change. 3) actually change rates starting from the topmost clocks and notify all clients on the way. I changed the set_rate callback to void. Instead of failing (what is failing in case of set_rate? The clock will still have some rate) I check for the result with clk_ops->recalc_rate.
I've considered something like this for "clock groups", especially when the set of clocks changing are all on the same device and the permutations are well known ahead of time. Is this working for you now?
The way described above works for me now, see this branch:
git://git.pengutronix.de/git/imx/linux-2.6.git v3.3-rc6-clkv6-fixup
You may not necessarily like it as it changes quite a lot in the rate changing code.
For the clock groups I plan to drop them at least for i.MX as the concept of clk groups seems somewhat broken. What we are grouping together are really different clocks and the driver should know about it and could even make use of it. We may not want to have more clocks in the driver though and may need something handling this on the bus layer, but that's another topic. The clock framework seems to be the wrong place for it.
In the end what's more important than the implementation details is that it actually works. I created a little test module which sets up two cascaded dividers, tries to change the rate at the output and checks the result. We might want to add something like this (and maybe similar tests for reparenting and other stuff) to the generic clock framework later. It's good to have something generic to test the framework with without depending on some particular SoC.
Agreed about the generic test. I'm not taking it into the current series, but we can grow the test cases and submit them later on.
Have you tried running it? It's not i.MX specific. I attached an updated version of the test. It fails with several NULL pointer exceptions, mostly because it has the CLK_SET_RATE_PARENT flag set for a divider whose parent is a fixed clock. If I don't set this flag no more NULL pointer exceptions occur, but the rate is not correct because the divider has to use DIV_ROUND_UP in its calc_best_div function. Otherwise it always returns a higher frequency if parentrate/rate is not an integer.
Apart from these little details we are discussing about here I really like your patches and can't wait to see them mainline. Thanks for working on this.
Sascha
8<---------------------------------------------------------------
clk: Add clock test module
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- drivers/clk/Makefile | 2 +- drivers/clk/clk-test.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 219 insertions(+), 1 deletions(-) create mode 100644 drivers/clk/clk-test.c
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 1f736bc..ba9a779 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -1,4 +1,4 @@
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \ - clk-mux.o clk-divider.o + clk-mux.o clk-divider.o clk-test.o diff --git a/drivers/clk/clk-test.c b/drivers/clk/clk-test.c new file mode 100644 index 0000000..cdee544 --- /dev/null +++ b/drivers/clk/clk-test.c @@ -0,0 +1,218 @@ +#include <linux/spinlock.h> +#include <linux/clk-provider.h> +#include <linux/clk.h> +#include <linux/module.h> + +/* + * We build a fixed rate source clock with two cascaded 2bit dividers: + * + * f1 -> div1 -> div2 + * + * and try set the rate of div2 from 0Hz to f1 + 1 Hz. + * + * Note that we expect the core to divide the dividers one after + * another: + * + * fout = (f1 / div1) / div + * + * and not like this: + * + * fout = f1 / (div1 * div2) + * This has in some cases different results due to integer maths + */ + +static unsigned long div1_reg, div2_reg; +static int div1_width = 3; +static int div2_width = 3; + +#define MAX_DIV(x) (1 << (x)) + +static struct clk *f1, *div1, *div2; + +static DEFINE_SPINLOCK(clk_test_lock); + +#define FIXED_RATE 1000 + +static int check_rounded_rate_div2(unsigned long want, unsigned long rounded) +{ + int i, j; + unsigned long best = 0, now; + + if (want > FIXED_RATE) { + best = FIXED_RATE; + goto found; + } + + for (i = 1; i <= MAX_DIV(div1_width); i++) { + for (j = 1; j <= MAX_DIV(div2_width); j++) { + now = FIXED_RATE / i / j; + if (now <= want && now > best) + best = now; + } + } + + if (!best) + best = (FIXED_RATE / MAX_DIV(div1_width)) / MAX_DIV(div2_width); +found: + if (rounded != best) { + printk("clk-test: wanted rate %ld, best result would be %ld," + " but we have %ld\n", + want, best, rounded); + return -EINVAL; + } + + return 0; +} + +static int check_real_rate_div2(unsigned long rate) +{ + unsigned long realrate; + + realrate = FIXED_RATE / (div1_reg + 1) / (div2_reg + 1); + + if (rate != realrate) { + printk("clk-test: divider returns rate %ld, but instead has %ld\n", + rate, realrate); + return -EINVAL; + } + + return 0; +} + +static int set_rate_test_div2(void) +{ + unsigned long i, rate, rounded; + int ret, errors = 0; + + for (i = 0; i < FIXED_RATE + 1; i++) { + rounded = clk_round_rate(div2, i); + ret = check_rounded_rate_div2(i, rounded); + if (ret) + errors++; + ret = clk_set_rate(div2, i); + if (ret) { + printk("%s: setting rate of div2 to %ld failed with %d\n", + __func__, i, ret); + errors++; + } + + rate = clk_get_rate(div2); + + if (rounded != rate) { + printk("clk_test: wanted %ld, core rounded to %ld, have now: %ld\n", + i, rounded, rate); + errors++; + } + + ret = check_real_rate_div2(rate); + if (ret) + errors++; + } + + return errors; +} + +static int check_rounded_rate_div1(unsigned long want, unsigned long rounded) +{ + unsigned long best; + int i; + + for (i = 1; i <= MAX_DIV(div1_width); i++) + if (FIXED_RATE / i <= want) { + best = FIXED_RATE / i; + goto found; + } + + best = FIXED_RATE / MAX_DIV(div1_width); +found: + if (rounded != best) { + printk("clk-test: wanted rate %ld, best result would be %ld," + " but we have %ld\n", + want, best, rounded); + return -EINVAL; + } + + return 0; +} + +static int check_real_rate_div1(unsigned long rate) +{ + unsigned long realrate; + + realrate = FIXED_RATE / (div1_reg + 1); + + if (rate != realrate) { + printk("clk-test: divider returns rate %ld, but instead has %ld\n", + rate, realrate); + return -EINVAL; + } + + return 0; +} + +static int set_rate_test_div1(void) +{ + unsigned long i, rate, rounded; + int ret, errors = 0; + + for (i = 0; i < FIXED_RATE + 1; i++) { + rounded = clk_round_rate(div1, i); + ret = check_rounded_rate_div1(i, rounded); + if (ret) + errors++; + ret = clk_set_rate(div1, i); + if (ret) { + printk("%s: setting rate of div2 to %ld failed with %d\n", + __func__, i, ret); + errors++; + } + + rate = clk_get_rate(div1); + + if (rounded != rate) { + printk("clk_test: wanted %ld, core rounded to %ld, have now: %ld\n", + i, rounded, rate); + errors++; + } + + ret = check_real_rate_div1(rate); + if (ret) + errors++; + } + + return errors; +} + +/* The core does not like this flag when the parent is not adjustable */ +#define DIV1_FLAGS CLK_SET_RATE_PARENT + +static int clk_test_init(void) +{ + int errors = 0; + + f1 = clk_register_fixed_rate(NULL, "f1", NULL, CLK_IS_ROOT, FIXED_RATE); + div1 = clk_register_divider(NULL, "div1", "f1", DIV1_FLAGS, + &div1_reg, 0, div1_width, 0, &clk_test_lock); + div2 = clk_register_divider(NULL, "div2", "div1", CLK_SET_RATE_PARENT, + &div2_reg, 0, div2_width, 0, &clk_test_lock); + + if (!f1 || !div1 || !div2) { + printk("clk-test: failed to register clocks\n"); + return -EINVAL; + } + + /* First pass: no cascaded divider, only f1 -> div1 */ + errors = set_rate_test_div1(); + /* Second pass: cascaded divider, f1 -> div1 -> div2 */ + errors += set_rate_test_div2(); + + printk("clk-test: finished with %d errors\n", errors); +#if 0 + /* we should be able to unregister clocks */ + clk_unregister(f1); + clk_unregister(div1); + clk_unregister(div2); +#endif + return -EINVAL; +} +subsys_initcall(clk_test_init);
On Tue, Mar 13, 2012 at 5:05 AM, Sascha Hauer s.hauer@pengutronix.de wrote:
On Mon, Mar 12, 2012 at 08:16:36PM -0700, Turquette, Mike wrote:
On Mon, Mar 12, 2012 at 4:51 AM, Sascha Hauer s.hauer@pengutronix.de wrote:
I tried another approach on the weekend which basically does not try to do all in a single recursion but instead sets the rate in multiple steps:
- call a function which calculates all new rates of affected clocks
in a rate change and safes the value in a clk->new_rate field. This function returns the topmost clock which has to be changed. 2) starting from the topmost clock notify all clients. This walks the whole subtree even if a notfifier refuses the change. If necessary we can walk the whole subtree again to abort the change. 3) actually change rates starting from the topmost clocks and notify all clients on the way. I changed the set_rate callback to void. Instead of failing (what is failing in case of set_rate? The clock will still have some rate) I check for the result with clk_ops->recalc_rate.
The way described above works for me now, see this branch:
git://git.pengutronix.de/git/imx/linux-2.6.git v3.3-rc6-clkv6-fixup
You may not necessarily like it as it changes quite a lot in the rate changing code.
I tried that code and I really like it! It is much more readable and feels less "fragile" than the previous recursive __clk_set_rate. I did quite a bit of testing with this code today. One of the tests looks like this:
pll (adjustable to anything) | clk_divider (5 bits wide) | dummy (no clk_ops)
The new code did a fine job arbitrating rates for the PLL and the intermediate divider even if I put weird constraints on the PLL. For instance if I artificially limited it to a minimum of 600MHz and then ran clk_set_rate(dummy, 300MHz) it would lock at 600MHz and set clk_divider to divide-by-2. Setting to 600MHz or more set the divider back to 1 and relocked the PLL appropriately. Pretty cool.
I also tested the notifiers with this code and they seem to function properly. I'll take this code in for v7. Thanks a lot for this helpful contribution.
I did find that MULT_ROUND_UP caused trouble for my PLL's round_rate implementation. Maybe my PLL code is fragile but a quick fix was to make sure that we send the exact value we want to the round_rate code. I also feel this is more correct. Let me know what you think:
8<---------------------------------------------------------------
commit 189fecedb175d0366759246c4192f45b0bc39a50 Author: Mike Turquette mturquette@linaro.org Date: Wed Mar 14 17:29:51 2012 -0700
clk-divider.c: round the actual rate we care about
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 86ca9cd..06ef4a0 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -47,12 +47,6 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, } EXPORT_SYMBOL_GPL(clk_divider_recalc_rate);
-/* - * The reverse of DIV_ROUND_UP: The maximum number which - * divided by m is r - */ -#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1) - static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate) { @@ -84,9 +78,9 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
for (i = 1; i <= maxdiv; i++) { parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), - MULT_ROUND_UP(rate, i)); + (rate * i)); now = parent_rate / i; - if (now <= rate && now >= best) { + if (now <= rate && now > best) { bestdiv = i; best = now; *best_parent_rate = parent_rate;
On Wed, Mar 14, 2012 at 05:51:48PM -0700, Turquette, Mike wrote:
On Tue, Mar 13, 2012 at 5:05 AM, Sascha Hauer s.hauer@pengutronix.de wrote:
On Mon, Mar 12, 2012 at 08:16:36PM -0700, Turquette, Mike wrote:
On Mon, Mar 12, 2012 at 4:51 AM, Sascha Hauer s.hauer@pengutronix.de wrote:
I tried another approach on the weekend which basically does not try to do all in a single recursion but instead sets the rate in multiple steps:
- call a function which calculates all new rates of affected clocks
in a rate change and safes the value in a clk->new_rate field. This function returns the topmost clock which has to be changed. 2) starting from the topmost clock notify all clients. This walks the whole subtree even if a notfifier refuses the change. If necessary we can walk the whole subtree again to abort the change. 3) actually change rates starting from the topmost clocks and notify all clients on the way. I changed the set_rate callback to void. Instead of failing (what is failing in case of set_rate? The clock will still have some rate) I check for the result with clk_ops->recalc_rate.
The way described above works for me now, see this branch:
git://git.pengutronix.de/git/imx/linux-2.6.git v3.3-rc6-clkv6-fixup
You may not necessarily like it as it changes quite a lot in the rate changing code.
I tried that code and I really like it! It is much more readable and feels less "fragile" than the previous recursive __clk_set_rate. I did quite a bit of testing with this code today. One of the tests looks like this:
pll (adjustable to anything) |
clk_divider (5 bits wide) | dummy (no clk_ops)
The new code did a fine job arbitrating rates for the PLL and the intermediate divider even if I put weird constraints on the PLL. For instance if I artificially limited it to a minimum of 600MHz and then ran clk_set_rate(dummy, 300MHz) it would lock at 600MHz and set clk_divider to divide-by-2. Setting to 600MHz or more set the divider back to 1 and relocked the PLL appropriately. Pretty cool.
I also tested the notifiers with this code and they seem to function properly. I'll take this code in for v7. Thanks a lot for this helpful contribution.
I did find that MULT_ROUND_UP caused trouble for my PLL's round_rate implementation. Maybe my PLL code is fragile but a quick fix was to make sure that we send the exact value we want to the round_rate code. I also feel this is more correct. Let me know what you think:
8<---------------------------------------------------------------
commit 189fecedb175d0366759246c4192f45b0bc39a50 Author: Mike Turquette mturquette@linaro.org Date: Wed Mar 14 17:29:51 2012 -0700
clk-divider.c: round the actual rate we care about
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 86ca9cd..06ef4a0 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -47,12 +47,6 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, } EXPORT_SYMBOL_GPL(clk_divider_recalc_rate);
-/*
- The reverse of DIV_ROUND_UP: The maximum number which
- divided by m is r
- */
-#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate) { @@ -84,9 +78,9 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
for (i = 1; i <= maxdiv; i++) { parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
MULT_ROUND_UP(rate, i));
(rate * i));
I think MULT_ROUND_UP is the right thing to use here (not sure if this is a good name though) Consider we want to have an output rate of 33Hz. Now acceptable input rates for a divider value of 3 would be 99, 100 and 101Hz, so we have to call round_rate for the parent with 101Hz which includes 100 and 99Hz.
If you have problems with your PLL than most likely because it does something different on clk_round_rate than it does in clk_set_rate, for example clk_round_rate(10000) returns 10000, but clk_set_rate then sets the rate 9999 due to some rounding error. Being consistent between round_rate and set_rate is very important for this mechanism to work properly. It did cost me some nerves to get it right for the divider (and even more nerves to figure out why it is correct the way it works)
now = parent_rate / i;
if (now <= rate && now >= best) {
if (now <= rate && now > best) {
This change is an optimization, but should be unrelated to your PLL problem, right?
Sascha
On Thu, Mar 15, 2012 at 2:43 AM, Sascha Hauer s.hauer@pengutronix.de wrote:
On Wed, Mar 14, 2012 at 05:51:48PM -0700, Turquette, Mike wrote:
@@ -84,9 +78,9 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
for (i = 1; i <= maxdiv; i++) { parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
- MULT_ROUND_UP(rate, i));
- (rate * i));
I think MULT_ROUND_UP is the right thing to use here (not sure if this is a good name though) Consider we want to have an output rate of 33Hz. Now acceptable input rates for a divider value of 3 would be 99, 100 and 101Hz, so we have to call round_rate for the parent with 101Hz which includes 100 and 99Hz.
We're back to the point Rob brought up about .round_rate rounding up or down. We really need a least-upper-bounds or greatest-lower-bounds flag, similar to how CPUfreq selects target frequencies today. I'm freezing features for this patchset now, so I'll keep your MULT_ROUND_UP approach and some day I'll fix .round_rate for good.
If you have problems with your PLL than most likely because it does something different on clk_round_rate than it does in clk_set_rate, for example clk_round_rate(10000) returns 10000, but clk_set_rate then sets the rate 9999 due to some rounding error. Being consistent between round_rate and set_rate is very important for this mechanism to work properly. It did cost me some nerves to get it right for the divider (and even more nerves to figure out why it is correct the way it works)
What I'd like to do is request the *exact* frequency I want when passing in a rate to my PLLs .round_rate. Due to the way that my MN dividers are calculated, and due to some jitter avoidance code, it is bad for me to request 600000001 Hz when I really want 600MHz exactly. Anyways I fixed this up on my end enough to work with MULT_ROUND_UP, so that can stay for the immediate future.
now = parent_rate / i;
- if (now <= rate && now >= best) {
- if (now <= rate && now > best) {
This change is an optimization, but should be unrelated to your PLL problem, right?
MULT_ROUND_UP yields multiples of 'rate' plus an incrementing value (m - 1). Without that incrementing value added to the rate passed into __clk_round_rate the for loop above will always max out the divider. To illustrate:
The rate we want is 300MHz. Without MULT_ROUND_UP the for loop will start yielding these combinations:
__clk_round_rate(parent, 300MHz), divide-by-1 __clk_round_rate(parent, 600MHz), divide-by-2 __clk_round_rate(parent, 900MHz), divide-by-3 __clk_round_rate(parent, 1200MHz), divide-by-4 ...etc...
These all yield the desired 300MHz for our divider so it just keeps going until you max out the divider and requests some crazy rate for the parent. On most hardware that I am aware of it is desirable to keep the divider as low as possible so the change to the conditional prevents us from overwriting best every single time while keeping the divider low. So yes, it is an optimization, but it is also quite necessary without MULT_ROUND_UP.
Anyways I've kept MULT_ROUND_UP exactly as-is with the exception that I've added that small optimization to keep dividers low. I hope there are no objections to that.
Regards, Mike
Sascha
-- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
On 03/10/2012 01:54 AM, Mike Turquette wrote:
The common clock framework defines a common struct clk useful across most platforms as well as an implementation of the clk api that drivers can use safely for managing clocks.
The net result is consolidation of many different struct clk definitions and platform-specific clock framework implementations.
This patch introduces the common struct clk, struct clk_ops and an implementation of the well-known clock api in include/clk/clk.h. Platforms may define their own hardware-specific clock structure and their own clock operation callbacks, so long as it wraps an instance of struct clk_hw.
See Documentation/clk.txt for more details.
This patch is based on the work of Jeremy Kerr, which in turn was based on the work of Ben Herrenschmidt.
Signed-off-by: Mike Turquette mturquette@linaro.org Signed-off-by: Mike Turquette mturquette@ti.com Cc: Russell King linux@arm.linux.org.uk Cc: Jeremy Kerr jeremy.kerr@canonical.com Cc: Thomas Gleixner tglx@linutronix.de Cc: Arnd Bergman arnd.bergmann@linaro.org Cc: Paul Walmsley paul@pwsan.com Cc: Shawn Guo shawn.guo@freescale.com Cc: Sascha Hauer s.hauer@pengutronix.de Cc: Richard Zhao richard.zhao@linaro.org Cc: Saravana Kannan skannan@codeaurora.org Cc: Magnus Damm magnus.damm@gmail.com Cc: Rob Herring rob.herring@calxeda.com Cc: Mark Brown broonie@opensource.wolfsonmicro.com Cc: Linus Walleij linus.walleij@stericsson.com Cc: Stephen Boyd sboyd@codeaurora.org Cc: Amit Kucheria amit.kucheria@linaro.org Cc: Deepak Saxena dsaxena@linaro.org Cc: Grant Likely grant.likely@secretlab.ca Cc: Andrew Lunn andrew@lunn.ch
I've gotten this at least booting on highbank with DT clock bindings.
One comment below, but otherwise:
Reviewed-by: Rob Herring rob.herring@calxeda.com
Changes since v5:
- new CONFIG_COMMON_CLK_DISABLE_UNUSED feature
- results in a new clk_op callback, .is_enabled
- new helpers
- __clk_get_prepare_count
- __clk_get_enable_count
- __clk_is_enabled
- fix bug in __clk_get_rate for orphan clocks
drivers/clk/Kconfig | 39 ++ drivers/clk/Makefile | 1 + drivers/clk/clk.c | 1424 ++++++++++++++++++++++++++++++++++++++++++ include/linux/clk-private.h | 68 ++ include/linux/clk-provider.h | 171 +++++ include/linux/clk.h | 68 ++- 6 files changed, 1766 insertions(+), 5 deletions(-) create mode 100644 drivers/clk/clk.c create mode 100644 include/linux/clk-private.h create mode 100644 include/linux/clk-provider.h
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 9b3cd08..31ceb27 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -8,3 +8,42 @@ config HAVE_CLK_PREPARE config HAVE_MACH_CLKDEV bool
+menuconfig COMMON_CLK
- bool "Common Clock Framework"
- select HAVE_CLK_PREPARE
- ---help---
The common clock framework is a single definition of struct
clk, useful across many platforms, as well as an
implementation of the clock API in include/linux/clk.h.
Architectures utilizing the common struct clk should select
this automatically, but it may be necessary to manually select
this option for loadable modules requiring the common clock
framework.
If in doubt, say "N".
+if COMMON_CLK
+config COMMON_CLK_DISABLE_UNUSED
- bool "Disabled unused clocks at boot"
- depends on COMMON_CLK
- ---help---
Traverses the entire clock tree and disables any clocks that are
enabled in hardware but have not been enabled by any device drivers.
This saves power and keeps the software model of the clock in line
with reality.
If in doubt, say "N".
+config COMMON_CLK_DEBUG
- bool "DebugFS representation of clock tree"
- depends on COMMON_CLK
depends on or select DEBUG_FS
- ---help---
Creates a directory hierchy in debugfs for visualizing the clk
tree structure. Each directory contains read-only members
that export information specific to that clk node: clk_rate,
clk_flags, clk_prepare_count, clk_enable_count &
clk_notifier_count.
+endif diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 07613fa..ff362c4 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o +obj-$(CONFIG_COMMON_CLK) += clk.o diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c new file mode 100644 index 0000000..c7c3bc5 --- /dev/null +++ b/drivers/clk/clk.c @@ -0,0 +1,1424 @@ +/*
- Copyright (C) 2010-2011 Canonical Ltd 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.
- Standard functionality for the common clock API. See Documentation/clk.txt
- */
+#include <linux/clk-private.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/spinlock.h> +#include <linux/err.h> +#include <linux/list.h> +#include <linux/slab.h>
+static DEFINE_SPINLOCK(enable_lock); +static DEFINE_MUTEX(prepare_lock);
+static HLIST_HEAD(clk_root_list); +static HLIST_HEAD(clk_orphan_list); +static LIST_HEAD(clk_notifier_list);
+/*** debugfs support ***/
+#ifdef CONFIG_COMMON_CLK_DEBUG +#include <linux/debugfs.h>
+static struct dentry *rootdir; +static struct dentry *orphandir; +static int inited = 0;
+/* caller must hold prepare_lock */ +static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry) +{
- struct dentry *d;
- int ret = -ENOMEM;
- if (!clk || !pdentry) {
ret = -EINVAL;
goto out;
- }
- d = debugfs_create_dir(clk->name, pdentry);
- if (!d)
goto out;
- clk->dentry = d;
- d = debugfs_create_u32("clk_rate", S_IRUGO, clk->dentry,
(u32 *)&clk->rate);
- if (!d)
goto err_out;
- d = debugfs_create_x32("clk_flags", S_IRUGO, clk->dentry,
(u32 *)&clk->flags);
- if (!d)
goto err_out;
- d = debugfs_create_u32("clk_prepare_count", S_IRUGO, clk->dentry,
(u32 *)&clk->prepare_count);
- if (!d)
goto err_out;
- d = debugfs_create_u32("clk_enable_count", S_IRUGO, clk->dentry,
(u32 *)&clk->enable_count);
- if (!d)
goto err_out;
- d = debugfs_create_u32("clk_notifier_count", S_IRUGO, clk->dentry,
(u32 *)&clk->notifier_count);
- if (!d)
goto err_out;
- ret = 0;
- goto out;
+err_out:
- debugfs_remove(clk->dentry);
+out:
- return ret;
+}
+/* caller must hold prepare_lock */ +static int clk_debug_create_subtree(struct clk *clk, struct dentry *pdentry) +{
- struct clk *child;
- struct hlist_node *tmp;
- int ret = -EINVAL;;
- if (!clk || !pdentry)
goto out;
- ret = clk_debug_create_one(clk, pdentry);
- if (ret)
goto out;
- hlist_for_each_entry(child, tmp, &clk->children, child_node)
clk_debug_create_subtree(child, clk->dentry);
- ret = 0;
+out:
- return ret;
+}
+/**
- clk_debug_register - add a clk node to the debugfs clk tree
- @clk: the clk being added to the debugfs clk tree
- Dynamically adds a clk to the debugfs clk tree if debugfs has been
- initialized. Otherwise it bails out early since the debugfs clk tree
- will be created lazily by clk_debug_init as part of a late_initcall.
- Caller must hold prepare_lock. Only clk_init calls this function (so
- far) so this is taken care.
- */
+static int clk_debug_register(struct clk *clk) +{
- struct clk *parent;
- struct dentry *pdentry;
- int ret = 0;
- if (!inited)
goto out;
- parent = clk->parent;
- /*
* Check to see if a clk is a root clk. Also check that it is
* safe to add this clk to debugfs
*/
- if (!parent)
if (clk->flags & CLK_IS_ROOT)
pdentry = rootdir;
else
pdentry = orphandir;
- else
if (parent->dentry)
pdentry = parent->dentry;
else
goto out;
- ret = clk_debug_create_subtree(clk, pdentry);
+out:
- return ret;
+}
+/**
- clk_debug_init - lazily create the debugfs clk tree visualization
- clks are often initialized very early during boot before memory can
- be dynamically allocated and well before debugfs is setup.
- clk_debug_init walks the clk tree hierarchy while holding
- prepare_lock and creates the topology as part of a late_initcall,
- thus insuring that clks initialized very early will still be
- represented in the debugfs clk tree. This function should only be
- called once at boot-time, and all other clks added dynamically will
- be done so with clk_debug_register.
- */
+static int __init clk_debug_init(void) +{
- struct clk *clk;
- struct hlist_node *tmp;
- rootdir = debugfs_create_dir("clk", NULL);
- if (!rootdir)
return -ENOMEM;
- orphandir = debugfs_create_dir("orphans", rootdir);
- if (!orphandir)
return -ENOMEM;
- mutex_lock(&prepare_lock);
- hlist_for_each_entry(clk, tmp, &clk_root_list, child_node)
clk_debug_create_subtree(clk, rootdir);
- hlist_for_each_entry(clk, tmp, &clk_orphan_list, child_node)
clk_debug_create_subtree(clk, orphandir);
- inited = 1;
- mutex_unlock(&prepare_lock);
- return 0;
+} +late_initcall(clk_debug_init); +#else +static inline int clk_debug_register(struct clk *clk) { return 0; } +#endif /* CONFIG_COMMON_CLK_DEBUG */
+#ifdef CONFIG_COMMON_CLK_DISABLE_UNUSED +/* caller must hold prepare_lock */ +static void clk_disable_unused_subtree(struct clk *clk) +{
- struct clk *child;
- struct hlist_node *tmp;
- unsigned long flags;
- if (!clk)
goto out;
- hlist_for_each_entry(child, tmp, &clk->children, child_node)
clk_disable_unused_subtree(child);
- spin_lock_irqsave(&enable_lock, flags);
- if (clk->enable_count)
goto unlock_out;
- if (clk->flags & CLK_IGNORE_UNUSED)
goto unlock_out;
- if (__clk_is_enabled(clk) && clk->ops->disable)
clk->ops->disable(clk->hw);
+unlock_out:
- spin_unlock_irqrestore(&enable_lock, flags);
+out:
- return;
+}
+static int clk_disable_unused(void) +{
- struct clk *clk;
- struct hlist_node *tmp;
- mutex_lock(&prepare_lock);
- hlist_for_each_entry(clk, tmp, &clk_root_list, child_node)
clk_disable_unused_subtree(clk);
- hlist_for_each_entry(clk, tmp, &clk_orphan_list, child_node)
clk_disable_unused_subtree(clk);
- mutex_unlock(&prepare_lock);
- return 0;
+} +late_initcall(clk_disable_unused); +#else +static inline int clk_disable_unused(struct clk *clk) { return 0; } +#endif /* CONFIG_COMMON_CLK_DISABLE_UNUSED */
+/*** helper functions ***/
+inline const char *__clk_get_name(struct clk *clk) +{
- return !clk ? NULL : clk->name;
+}
+inline struct clk_hw *__clk_get_hw(struct clk *clk) +{
- return !clk ? NULL : clk->hw;
+}
+inline u8 __clk_get_num_parents(struct clk *clk) +{
- return !clk ? -EINVAL : clk->num_parents;
+}
+inline struct clk *__clk_get_parent(struct clk *clk) +{
- return !clk ? NULL : clk->parent;
+}
+inline unsigned long __clk_get_enable_count(struct clk *clk) +{
- return !clk ? -EINVAL : clk->enable_count;
+}
+inline unsigned long __clk_get_prepare_count(struct clk *clk) +{
- return !clk ? -EINVAL : clk->prepare_count;
+}
+unsigned long __clk_get_rate(struct clk *clk) +{
- unsigned long ret;
- if (!clk) {
ret = -EINVAL;
goto out;
- }
- ret = clk->rate;
- if (clk->flags & CLK_IS_ROOT)
goto out;
- if (!clk->parent)
ret = -ENODEV;
+out:
- return ret;
+}
+inline unsigned long __clk_get_flags(struct clk *clk) +{
- return !clk ? -EINVAL : clk->flags;
+}
+int __clk_is_enabled(struct clk *clk) +{
- int ret;
- if (!clk)
return -EINVAL;
- /*
* .is_enabled is only mandatory for clocks that gate
* fall back to software usage counter if .is_enabled is missing
*/
- if (!clk->ops->is_enabled) {
ret = clk->enable_count ? 1 : 0;
goto out;
- }
- ret = clk->ops->is_enabled(clk->hw);
+out:
- return ret;
+}
+static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk) +{
- struct clk *child;
- struct clk *ret;
- struct hlist_node *tmp;
- if (!strcmp(clk->name, name))
return clk;
- hlist_for_each_entry(child, tmp, &clk->children, child_node) {
ret = __clk_lookup_subtree(name, child);
if (ret)
return ret;
- }
- return NULL;
+}
+struct clk *__clk_lookup(const char *name) +{
- struct clk *root_clk;
- struct clk *ret;
- struct hlist_node *tmp;
- /* search the 'proper' clk tree first */
- hlist_for_each_entry(root_clk, tmp, &clk_root_list, child_node) {
ret = __clk_lookup_subtree(name, root_clk);
if (ret)
return ret;
- }
- /* if not found, then search the orphan tree */
- hlist_for_each_entry(root_clk, tmp, &clk_orphan_list, child_node) {
ret = __clk_lookup_subtree(name, root_clk);
if (ret)
return ret;
- }
- return NULL;
+}
+/*** clk api ***/
+void __clk_unprepare(struct clk *clk) +{
- if (!clk)
return;
- if (WARN_ON(clk->prepare_count == 0))
return;
- if (--clk->prepare_count > 0)
return;
- WARN_ON(clk->enable_count > 0);
- if (clk->ops->unprepare)
clk->ops->unprepare(clk->hw);
- __clk_unprepare(clk->parent);
+}
+/**
- clk_unprepare - undo preparation of a clock source
- @clk: the clk being unprepare
- clk_unprepare may sleep, which differentiates it from clk_disable. In a
- simple case, clk_unprepare can be used instead of clk_disable to gate a clk
- if the operation may sleep. One example is a clk which is accessed over
- I2c. 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_unprepare(struct clk *clk) +{
- mutex_lock(&prepare_lock);
- __clk_unprepare(clk);
- mutex_unlock(&prepare_lock);
+} +EXPORT_SYMBOL_GPL(clk_unprepare);
+int __clk_prepare(struct clk *clk) +{
- int ret = 0;
- if (!clk)
return 0;
- if (clk->prepare_count == 0) {
ret = __clk_prepare(clk->parent);
if (ret)
return ret;
if (clk->ops->prepare) {
ret = clk->ops->prepare(clk->hw);
if (ret) {
__clk_unprepare(clk->parent);
return ret;
}
}
- }
- clk->prepare_count++;
- return 0;
+}
+/**
- clk_prepare - prepare a clock source
- @clk: the clk being prepared
- clk_prepare may sleep, which differentiates it from clk_enable. In a simple
- case, clk_prepare can be used instead of clk_enable to ungate a clk if the
- operation may sleep. One example is a clk which is accessed over I2c. In
- the complex case a clk ungate operation may require a fast and a slow part.
- It is this reason that clk_prepare and clk_enable are not mutually
- exclusive. In fact clk_prepare must be called before clk_enable.
- Returns 0 on success, -EERROR otherwise.
- */
+int clk_prepare(struct clk *clk) +{
- int ret;
- mutex_lock(&prepare_lock);
- ret = __clk_prepare(clk);
- mutex_unlock(&prepare_lock);
- return ret;
+} +EXPORT_SYMBOL_GPL(clk_prepare);
+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);
+}
+/**
- 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);
if (ret)
return ret;
if (clk->ops->enable) {
ret = clk->ops->enable(clk->hw);
if (ret) {
__clk_disable(clk->parent);
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)
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;
+} +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;
- 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;
- }
+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 (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)
return clk;
- }
- /* change the rate of this clk */
- if (clk->ops->set_rate)
ret = clk->ops->set_rate(clk->hw, new_rate);
- if (ret == NOTIFY_BAD)
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);
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);
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));
- /*
* 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.
- 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);
- }
- 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.
- 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..09dea1f --- /dev/null +++ b/include/linux/clk-provider.h @@ -0,0 +1,171 @@ +/*
- 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 */ +#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);
- int (*is_enabled)(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); +int __clk_is_enabled(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); +unsigned long __clk_round_rate(struct clk *clk, unsigned long rate);
+#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.
Mike,
On 03/10/2012 01:54 AM, Mike Turquette wrote:
The common clock framework defines a common struct clk useful across most platforms as well as an implementation of the clk api that drivers can use safely for managing clocks.
The net result is consolidation of many different struct clk definitions and platform-specific clock framework implementations.
This patch introduces the common struct clk, struct clk_ops and an implementation of the well-known clock api in include/clk/clk.h. Platforms may define their own hardware-specific clock structure and their own clock operation callbacks, so long as it wraps an instance of struct clk_hw.
See Documentation/clk.txt for more details.
This patch is based on the work of Jeremy Kerr, which in turn was based on the work of Ben Herrenschmidt.
Signed-off-by: Mike Turquette mturquette@linaro.org Signed-off-by: Mike Turquette mturquette@ti.com Cc: Russell King linux@arm.linux.org.uk Cc: Jeremy Kerr jeremy.kerr@canonical.com Cc: Thomas Gleixner tglx@linutronix.de Cc: Arnd Bergman arnd.bergmann@linaro.org Cc: Paul Walmsley paul@pwsan.com Cc: Shawn Guo shawn.guo@freescale.com Cc: Sascha Hauer s.hauer@pengutronix.de Cc: Richard Zhao richard.zhao@linaro.org Cc: Saravana Kannan skannan@codeaurora.org Cc: Magnus Damm magnus.damm@gmail.com Cc: Rob Herring rob.herring@calxeda.com Cc: Mark Brown broonie@opensource.wolfsonmicro.com Cc: Linus Walleij linus.walleij@stericsson.com Cc: Stephen Boyd sboyd@codeaurora.org Cc: Amit Kucheria amit.kucheria@linaro.org Cc: Deepak Saxena dsaxena@linaro.org Cc: Grant Likely grant.likely@secretlab.ca Cc: Andrew Lunn andrew@lunn.ch
snip
- /*
* 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)
In __clk_init, this needs to be hlist_for_each_entry_safe as entries can be removed.
Rob
On Tue, Mar 13, 2012 at 2:48 PM, Rob Herring robherring2@gmail.com wrote:
Mike,
On 03/10/2012 01:54 AM, Mike Turquette wrote:
The common clock framework defines a common struct clk useful across most platforms as well as an implementation of the clk api that drivers can use safely for managing clocks.
The net result is consolidation of many different struct clk definitions and platform-specific clock framework implementations.
This patch introduces the common struct clk, struct clk_ops and an implementation of the well-known clock api in include/clk/clk.h. Platforms may define their own hardware-specific clock structure and their own clock operation callbacks, so long as it wraps an instance of struct clk_hw.
See Documentation/clk.txt for more details.
This patch is based on the work of Jeremy Kerr, which in turn was based on the work of Ben Herrenschmidt.
Signed-off-by: Mike Turquette mturquette@linaro.org Signed-off-by: Mike Turquette mturquette@ti.com Cc: Russell King linux@arm.linux.org.uk Cc: Jeremy Kerr jeremy.kerr@canonical.com Cc: Thomas Gleixner tglx@linutronix.de Cc: Arnd Bergman arnd.bergmann@linaro.org Cc: Paul Walmsley paul@pwsan.com Cc: Shawn Guo shawn.guo@freescale.com Cc: Sascha Hauer s.hauer@pengutronix.de Cc: Richard Zhao richard.zhao@linaro.org Cc: Saravana Kannan skannan@codeaurora.org Cc: Magnus Damm magnus.damm@gmail.com Cc: Rob Herring rob.herring@calxeda.com Cc: Mark Brown broonie@opensource.wolfsonmicro.com Cc: Linus Walleij linus.walleij@stericsson.com Cc: Stephen Boyd sboyd@codeaurora.org Cc: Amit Kucheria amit.kucheria@linaro.org Cc: Deepak Saxena dsaxena@linaro.org Cc: Grant Likely grant.likely@secretlab.ca Cc: Andrew Lunn andrew@lunn.ch
snip
- /*
- * 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)
In __clk_init, this needs to be hlist_for_each_entry_safe as entries can be removed.
Thanks for the catch Rob. I'll take this in.
Regards, Mike
Rob
linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Many platforms support simple gateable clocks, fixed-rate clocks, adjustable divider clocks and multi-parent multiplexer clocks.
This patch introduces basic clock types for the above-mentioned hardware which share some common characteristics.
Based on original work by Jeremy Kerr and contribution by Jamie Iles. Dividers and multiplexor clocks originally contributed by Richard Zhao & Sascha Hauer.
Signed-off-by: Mike Turquette mturquette@linaro.org Signed-off-by: Mike Turquette mturquette@ti.com Cc: Russell King linux@arm.linux.org.uk Cc: Jeremy Kerr jeremy.kerr@canonical.com Cc: Thomas Gleixner tglx@linutronix.de Cc: Arnd Bergman arnd.bergmann@linaro.org Cc: Paul Walmsley paul@pwsan.com Cc: Shawn Guo shawn.guo@freescale.com Cc: Sascha Hauer s.hauer@pengutronix.de Cc: Jamie Iles jamie@jamieiles.com Cc: Richard Zhao richard.zhao@linaro.org Cc: Saravana Kannan skannan@codeaurora.org Cc: Magnus Damm magnus.damm@gmail.com Cc: Rob Herring rob.herring@calxeda.com Cc: Mark Brown broonie@opensource.wolfsonmicro.com Cc: Linus Walleij linus.walleij@stericsson.com Cc: Stephen Boyd sboyd@codeaurora.org Cc: Amit Kucheria amit.kucheria@linaro.org Cc: Deepak Saxena dsaxena@linaro.org Cc: Grant Likely grant.likely@secretlab.ca Cc: Andrew Lunn andrew@lunn.ch --- Changes since v5: * standardized the hw-specific locking in the basic clock types * export the individual ops for each basic clock type * improve registration for single-parent basic clocks (thanks Sascha) * fixed bugs in gate clock's static initializers (thanks Andrew)
drivers/clk/Makefile | 3 +- drivers/clk/clk-divider.c | 204 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/clk-fixed-rate.c | 82 +++++++++++++++++ drivers/clk/clk-gate.c | 157 ++++++++++++++++++++++++++++++++ drivers/clk/clk-mux.c | 123 +++++++++++++++++++++++++ include/linux/clk-private.h | 124 +++++++++++++++++++++++++ include/linux/clk-provider.h | 127 ++++++++++++++++++++++++++ 7 files changed, 819 insertions(+), 1 deletions(-) create mode 100644 drivers/clk/clk-divider.c create mode 100644 drivers/clk/clk-fixed-rate.c create mode 100644 drivers/clk/clk-gate.c create mode 100644 drivers/clk/clk-mux.c
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index ff362c4..1f736bc 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -1,3 +1,4 @@
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o -obj-$(CONFIG_COMMON_CLK) += clk.o +obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \ + clk-mux.o clk-divider.o diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c new file mode 100644 index 0000000..c0c4e0b --- /dev/null +++ b/drivers/clk/clk-divider.c @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2011 Sascha Hauer, Pengutronix s.hauer@pengutronix.de + * Copyright (C) 2011 Richard Zhao, Linaro richard.zhao@linaro.org + * Copyright (C) 2011-2012 Mike Turquette, 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. + * + * Adjustable divider clock implementation + */ + +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/string.h> + +/* + * DOC: basic adjustable divider clock that cannot gate + * + * Traits of this clock: + * prepare - clk_prepare only ensures that parents are prepared + * enable - clk_enable only ensures that parents are enabled + * rate - rate is adjustable. clk->rate = parent->rate / divisor + * parent - fixed parent. No clk_set_parent support + */ + +#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) + +static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned int div; + unsigned long flags = 0; + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + + div = readl(divider->reg) >> divider->shift; + div &= (1 << divider->width) - 1; + + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + + if (!(divider->flags & CLK_DIVIDER_ONE_BASED)) + div++; + + return parent_rate / div; +} +EXPORT_SYMBOL_GPL(clk_divider_recalc_rate); + +static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + int i, bestdiv = 0; + unsigned long parent_rate, best = 0, now, maxdiv; + + maxdiv = (1 << divider->width); + + if (divider->flags & CLK_DIVIDER_ONE_BASED) + maxdiv--; + + if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { + parent_rate = __clk_get_rate(__clk_get_parent(hw->clk)); + bestdiv = parent_rate / rate; + bestdiv = bestdiv == 0 ? 1 : bestdiv; + bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; + goto out; + } + + /* + * The maximum divider we can use without overflowing + * unsigned long in rate * i below + */ + maxdiv = min(ULONG_MAX / rate, maxdiv); + + for (i = 1; i <= maxdiv; i++) { + int div; + parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), + rate * i); + div = parent_rate / rate; + div = div > maxdiv ? maxdiv : div; + div = div < 1 ? 1 : div; + now = parent_rate / div; + + if (now <= rate && now >= best) { + bestdiv = div; + best = now; + *best_parent_rate = parent_rate; + } + } + + if (!bestdiv) { + bestdiv = (1 << divider->width); + parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1); + } else { + parent_rate = best * bestdiv; + } + +out: + if (best_parent_rate) + *best_parent_rate = parent_rate; + + return bestdiv; +} + +static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long best_parent_rate; + int div = clk_divider_bestdiv(hw, rate, &best_parent_rate); + if (prate) { + if (best_parent_rate == __clk_get_rate( + __clk_get_parent(hw->clk))) + *prate = 0; + else + *prate = best_parent_rate; + } + + return best_parent_rate / div; +} +EXPORT_SYMBOL_GPL(clk_divider_round_rate); + +static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate) +{ + unsigned long best_parent_rate; + struct clk_divider *divider = to_clk_divider(hw); + unsigned int div; + unsigned long flags = 0; + u32 val; + + div = clk_divider_bestdiv(hw, rate, &best_parent_rate); + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + + if (!(divider->flags & CLK_DIVIDER_ONE_BASED)) + div--; + + val = readl(divider->reg); + val &= ~(((1 << divider->width) - 1) << divider->shift); + val |= div << divider->shift; + writel(val, divider->reg); + + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(clk_divider_set_rate); + +struct clk_ops clk_divider_ops = { + .recalc_rate = clk_divider_recalc_rate, + .round_rate = clk_divider_round_rate, + .set_rate = clk_divider_set_rate, +}; +EXPORT_SYMBOL_GPL(clk_divider_ops); + +struct clk *clk_register_divider(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 shift, u8 width, + u8 clk_divider_flags, spinlock_t *lock) +{ + struct clk_divider *div; + struct clk *clk; + + div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL); + + if (!div) { + pr_err("%s: could not allocate divider clk\n", __func__); + return NULL; + } + + /* struct clk_divider assignments */ + div->reg = reg; + div->shift = shift; + div->width = width; + div->flags = clk_divider_flags; + div->lock = lock; + + if (parent_name) { + div->parent[0] = kstrdup(parent_name, GFP_KERNEL); + if (!div->parent[0]) + goto out; + } + + clk = clk_register(dev, name, + &clk_divider_ops, &div->hw, + div->parent, + (parent_name ? 1 : 0), + flags); + if (clk) + return clk; + +out: + kfree(div->parent[0]); + kfree(div); + + return NULL; +} diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c new file mode 100644 index 0000000..90c79fb --- /dev/null +++ b/drivers/clk/clk-fixed-rate.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2010-2011 Canonical Ltd jeremy.kerr@canonical.com + * Copyright (C) 2011-2012 Mike Turquette, 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. + * + * Fixed rate clock implementation + */ + +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> + +/* + * DOC: basic fixed-rate clock that cannot gate + * + * Traits of this clock: + * prepare - clk_(un)prepare only ensures parents are prepared + * enable - clk_enable only ensures parents are enabled + * rate - rate is always a fixed value. No clk_set_rate support + * parent - fixed parent. No clk_set_parent support + */ + +#define to_clk_fixed_rate(_hw) container_of(_hw, struct clk_fixed_rate, hw) + +static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return to_clk_fixed_rate(hw)->fixed_rate; +} +EXPORT_SYMBOL_GPL(clk_fixed_rate_recalc_rate); + +struct clk_ops clk_fixed_rate_ops = { + .recalc_rate = clk_fixed_rate_recalc_rate, +}; +EXPORT_SYMBOL_GPL(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_fixed_rate *fixed; + char **parent_names = NULL; + u8 len; + + fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL); + + if (!fixed) { + pr_err("%s: could not allocate fixed clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + /* struct clk_fixed_rate assignments */ + fixed->fixed_rate = fixed_rate; + + if (parent_name) { + parent_names = kmalloc(sizeof(char *), GFP_KERNEL); + + if (! parent_names) + goto out; + + len = sizeof(char) * strlen(parent_name); + + parent_names[0] = kmalloc(len, GFP_KERNEL); + + if (!parent_names[0]) + goto out; + + strncpy(parent_names[0], parent_name, len); + } + +out: + return clk_register(dev, name, + &clk_fixed_rate_ops, &fixed->hw, + parent_names, + (parent_name ? 1 : 0), + flags); +} diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c new file mode 100644 index 0000000..5d50efa --- /dev/null +++ b/drivers/clk/clk-gate.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2010-2011 Canonical Ltd jeremy.kerr@canonical.com + * Copyright (C) 2011-2012 Mike Turquette, 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. + * + * Gated clock implementation + */ + +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/string.h> + +/** + * DOC: basic gatable clock which can gate and ungate it's ouput + * + * Traits of this clock: + * prepare - clk_(un)prepare only ensures parent is (un)prepared + * enable - clk_enable and clk_disable are functional & control gating + * rate - inherits rate from parent. No clk_set_rate support + * parent - fixed parent. No clk_set_parent support + */ + +#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) + +static void clk_gate_set_bit(struct clk_gate *gate) +{ + u32 reg; + unsigned long flags = 0; + + if (gate->lock) + spin_lock_irqsave(gate->lock, flags); + + reg = readl(gate->reg); + reg |= BIT(gate->bit_idx); + writel(reg, gate->reg); + + if (gate->lock) + spin_unlock_irqrestore(gate->lock, flags); +} + +static void clk_gate_clear_bit(struct clk_gate *gate) +{ + u32 reg; + unsigned long flags = 0; + + if (gate->lock) + spin_lock_irqsave(gate->lock, flags); + + reg = readl(gate->reg); + reg &= ~BIT(gate->bit_idx); + writel(reg, gate->reg); + + if (gate->lock) + spin_unlock_irqrestore(gate->lock, flags); +} + +static int clk_gate_enable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + + if (gate->flags & CLK_GATE_SET_TO_DISABLE) + clk_gate_clear_bit(gate); + else + clk_gate_set_bit(gate); + + return 0; +} +EXPORT_SYMBOL_GPL(clk_gate_enable); + +static void clk_gate_disable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + + if (gate->flags & CLK_GATE_SET_TO_DISABLE) + clk_gate_set_bit(gate); + else + clk_gate_clear_bit(gate); +} +EXPORT_SYMBOL_GPL(clk_gate_disable); + +static int clk_gate_is_enabled(struct clk_hw *hw) +{ + u32 reg; + unsigned long flags = 0; + struct clk_gate *gate = to_clk_gate(hw); + + if (gate->lock) + spin_lock_irqsave(gate->lock, flags); + + reg = readl(gate->reg); + + if (gate->lock) + spin_unlock_irqrestore(gate->lock, flags); + + /* if a set bit disables this clk, flip it before masking */ + if (gate->flags & CLK_GATE_SET_TO_DISABLE) + reg ^= BIT(gate->bit_idx); + + reg &= BIT(gate->bit_idx); + + return reg ? 1 : 0; +} +EXPORT_SYMBOL_GPL(clk_gate_is_enabled); + +struct clk_ops clk_gate_ops = { + .enable = clk_gate_enable, + .disable = clk_gate_disable, + .is_enabled = clk_gate_is_enabled, +}; +EXPORT_SYMBOL_GPL(clk_gate_ops); + +struct clk *clk_register_gate(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, + u8 clk_gate_flags, spinlock_t *lock) +{ + struct clk_gate *gate; + struct clk *clk; + + gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); + + if (!gate) { + pr_err("%s: could not allocate gated clk\n", __func__); + return NULL; + } + + /* struct clk_gate assignments */ + gate->reg = reg; + gate->bit_idx = bit_idx; + gate->flags = clk_gate_flags; + gate->lock = lock; + + if (parent_name) { + gate->parent[0] = kstrdup(parent_name, GFP_KERNEL); + if (!gate->parent[0]) + goto out; + } + + clk = clk_register(dev, name, + &clk_gate_ops, &gate->hw, + gate->parent, + (parent_name ? 1 : 0), + flags); + if (clk) + return clk; +out: + kfree(gate->parent[0]); + kfree(gate); + + return NULL; +} diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c new file mode 100644 index 0000000..6fc0878 --- /dev/null +++ b/drivers/clk/clk-mux.c @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2011 Sascha Hauer, Pengutronix s.hauer@pengutronix.de + * Copyright (C) 2011 Richard Zhao, Linaro richard.zhao@linaro.org + * Copyright (C) 2011-2012 Mike Turquette, 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. + * + * Simple multiplexer clock implementation + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> + +/* + * DOC: basic adjustable multiplexer clock that cannot gate + * + * Traits of this clock: + * prepare - clk_prepare only ensures that parents are prepared + * enable - clk_enable only ensures that parents are enabled + * rate - rate is only affected by parent switching. No clk_set_rate support + * parent - parent is adjustable through clk_set_parent + */ + +#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw) + +static u8 clk_mux_get_parent(struct clk_hw *hw) +{ + struct clk_mux *mux = to_clk_mux(hw); + u32 val; + unsigned long flags = 0; + + if (mux->lock) + spin_lock_irqsave(mux->lock, flags); + + /* + * FIXME need a mux-specific flag to determine if val is bitwise or numeric + * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1 + * to 0x7 (index starts at one) + * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so + * val = 0x4 really means "bit 2, index starts at bit 0" + */ + val = readl(mux->reg) >> mux->shift; + val &= (1 << mux->width) - 1; + + if (mux->lock) + spin_unlock_irqrestore(mux->lock, flags); + + if (val && (mux->flags & CLK_MUX_INDEX_BIT)) + val = ffs(val) - 1; + + if (val && (mux->flags & CLK_MUX_INDEX_ONE)) + val--; + + if (val >= __clk_get_num_parents(hw->clk)) + return -EINVAL; + + return val; +} +EXPORT_SYMBOL_GPL(clk_mux_get_parent); + +static int clk_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_mux *mux = to_clk_mux(hw); + u32 val; + unsigned long flags = 0; + + if (mux->flags & CLK_MUX_INDEX_BIT) + index = (1 << ffs(index)); + + if (mux->flags & CLK_MUX_INDEX_ONE) + index++; + + if (mux->lock) + spin_lock_irqsave(mux->lock, flags); + + val = readl(mux->reg); + val &= ~(((1 << mux->width) - 1) << mux->shift); + val |= index << mux->shift; + writel(val, mux->reg); + + if (mux->lock) + spin_unlock_irqrestore(mux->lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(clk_mux_set_parent); + +struct clk_ops clk_mux_ops = { + .get_parent = clk_mux_get_parent, + .set_parent = clk_mux_set_parent, +}; +EXPORT_SYMBOL_GPL(clk_mux_ops); + +struct clk *clk_register_mux(struct device *dev, const char *name, + char **parent_names, u8 num_parents, unsigned long flags, + void __iomem *reg, u8 shift, u8 width, + u8 clk_mux_flags, spinlock_t *lock) +{ + struct clk_mux *mux; + + mux = kmalloc(sizeof(struct clk_mux), GFP_KERNEL); + + if (!mux) { + pr_err("%s: could not allocate mux clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + /* struct clk_mux assignments */ + mux->reg = reg; + mux->shift = shift; + mux->width = width; + mux->flags = clk_mux_flags; + mux->lock = lock; + + return clk_register(dev, name, &clk_mux_ops, &mux->hw, + parent_names, num_parents, flags); +} diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index 33bf6a7..9d5c4b1 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -45,6 +45,130 @@ struct clk { #endif };
+/* + * DOC: Basic clock implementations common to many platforms + * + * Each basic clock hardware type is comprised of a structure describing the + * clock hardware, implementations of the relevant callbacks in struct clk_ops, + * unique flags for that hardware type, a registration function and an + * alternative macro for static initialization + */ + +extern struct clk_ops clk_fixed_rate_ops; + +#define DEFINE_CLK_FIXED_RATE(_name, _flags, _rate, \ + _fixed_rate_flags) \ + static struct clk _name; \ + static char *_name##_parent_names[] = {}; \ + static struct clk_fixed_rate _name##_hw = { \ + .hw = { \ + .clk = &_name, \ + }, \ + .fixed_rate = _rate, \ + .flags = _fixed_rate_flags, \ + }; \ + static struct clk _name = { \ + .name = #_name, \ + .ops = &clk_fixed_rate_ops, \ + .hw = &_name##_hw.hw, \ + .parent_names = _name##_parent_names, \ + .num_parents = \ + ARRAY_SIZE(_name##_parent_names), \ + .flags = _flags, \ + }; + +extern struct clk_ops clk_gate_ops; + +#define DEFINE_CLK_GATE(_name, _parent_name, _parent_ptr, \ + _flags, _reg, _bit_idx, \ + _gate_flags, _lock) \ + static struct clk _name; \ + static char *_name##_parent_names[] = { \ + _parent_name, \ + }; \ + static struct clk *_name##_parents[] = { \ + _parent_ptr, \ + }; \ + static struct clk_gate _name##_hw = { \ + .hw = { \ + .clk = &_name, \ + }, \ + .reg = _reg, \ + .bit_idx = _bit_idx, \ + .flags = _gate_flags, \ + .lock = _lock, \ + }; \ + static struct clk _name = { \ + .name = #_name, \ + .ops = &clk_gate_ops, \ + .hw = &_name##_hw.hw, \ + .parent_names = _name##_parent_names, \ + .num_parents = \ + ARRAY_SIZE(_name##_parent_names), \ + .parents = _name##_parents, \ + .flags = _flags, \ + }; + +extern struct clk_ops clk_divider_ops; + +#define DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \ + _flags, _reg, _shift, _width, \ + _divider_flags, _lock) \ + static struct clk _name; \ + static char *_name##_parent_names[] = { \ + _parent_name, \ + }; \ + static struct clk *_name##_parents[] = { \ + _parent_ptr, \ + }; \ + static struct clk_divider _name##_hw = { \ + .hw = { \ + .clk = &_name, \ + }, \ + .reg = _reg, \ + .shift = _shift, \ + .width = _width, \ + .flags = _divider_flags, \ + .lock = _lock, \ + }; \ + static struct clk _name = { \ + .name = #_name, \ + .ops = &clk_divider_ops, \ + .hw = &_name##_hw.hw, \ + .parent_names = _name##_parent_names, \ + .num_parents = \ + ARRAY_SIZE(_name##_parent_names), \ + .parents = _name##_parents, \ + .flags = _flags, \ + }; + +extern struct clk_ops clk_mux_ops; + +#define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags, \ + _reg, _shift, _width, \ + _mux_flags, _lock) \ + static struct clk _name; \ + static struct clk_mux _name##_hw = { \ + .hw = { \ + .clk = &_name, \ + }, \ + .reg = _reg, \ + .shift = _shift, \ + .width = _width, \ + .flags = _mux_flags, \ + .lock = _lock, \ + }; \ + static struct clk _name = { \ + .name = #_name, \ + .ops = &clk_mux_ops, \ + .hw = &_name##_hw.hw, \ + .parent_names = _parent_names, \ + .num_parents = \ + ARRAY_SIZE(_parent_names), \ + .parents = _parents, \ + .flags = _flags, \ + }; + /** * __clk_init - initialize the data structures in a struct clk * @dev: device initializing this clk, placeholder for now diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 09dea1f..853d526 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -129,6 +129,133 @@ struct clk_ops { void (*init)(struct clk_hw *hw); };
+/* + * DOC: Basic clock implementations common to many platforms + * + * Each basic clock hardware type is comprised of a structure describing the + * clock hardware, implementations of the relevant callbacks in struct clk_ops, + * unique flags for that hardware type, a registration function and an + * alternative macro for static initialization + */ + +/** + * struct clk_fixed_rate - fixed-rate clock + * @hw: handle between common and hardware-specific interfaces + * @fixed_rate: constant frequency of clock + */ +struct clk_fixed_rate { + struct clk_hw hw; + unsigned long fixed_rate; + u8 flags; +}; + +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_gate - gating clock + * + * @hw: handle between common and hardware-specific interfaces + * @reg: register controlling gate + * @bit_idx: single bit controlling gate + * @flags: hardware-specific flags + * @lock: register lock + * + * Clock which can gate its output. Implements .enable & .disable + * + * Flags: + * CLK_GATE_SET_DISABLE - by default this clock sets the bit at bit_idx to + * enable the clock. Setting this flag does the opposite: setting the bit + * disable the clock and clearing it enables the clock + */ +struct clk_gate { + struct clk_hw hw; + void __iomem *reg; + u8 bit_idx; + u8 flags; + spinlock_t *lock; + char *parent[1]; +}; + +#define CLK_GATE_SET_TO_DISABLE BIT(0) + +struct clk *clk_register_gate(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, + u8 clk_gate_flags, spinlock_t *lock); + +/** + * struct clk_divider - adjustable divider clock + * + * @hw: handle between common and hardware-specific interfaces + * @reg: register containing the divider + * @shift: shift to the divider bit field + * @width: width of the divider bit field + * @lock: register lock + * + * Clock with an adjustable divider affecting its output frequency. Implements + * .recalc_rate, .set_rate and .round_rate + * + * Flags: + * CLK_DIVIDER_ONE_BASED - by default the divisor is the value read from the + * register plus one. If CLK_DIVIDER_ONE_BASED is set then the divider is + * the raw value read from the register, with the value of zero considered + * invalid + * CLK_DIVIDER_POWER_OF_TWO - clock divisor is 2 raised to the value read from + * the hardware register + */ +struct clk_divider { + struct clk_hw hw; + void __iomem *reg; + u8 shift; + u8 width; + u8 flags; + spinlock_t *lock; + char *parent[1]; +}; + +#define CLK_DIVIDER_ONE_BASED BIT(0) +#define CLK_DIVIDER_POWER_OF_TWO BIT(1) + +struct clk *clk_register_divider(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 shift, u8 width, + u8 clk_divider_flags, spinlock_t *lock); + +/** + * struct clk_mux - multiplexer clock + * + * @hw: handle between common and hardware-specific interfaces + * @reg: register controlling multiplexer + * @shift: shift to multiplexer bit field + * @width: width of mutliplexer bit field + * @num_clks: number of parent clocks + * @lock: register lock + * + * Clock with multiple selectable parents. Implements .get_parent, .set_parent + * and .recalc_rate + * + * Flags: + * CLK_MUX_INDEX_ONE - register index starts at 1, not 0 + * CLK_MUX_INDEX_BITWISE - register index is a single bit (power of two) + */ +struct clk_mux { + struct clk_hw hw; + void __iomem *reg; + u8 shift; + u8 width; + u8 flags; + spinlock_t *lock; +}; + +#define CLK_MUX_INDEX_ONE BIT(0) +#define CLK_MUX_INDEX_BIT BIT(1) + +struct clk *clk_register_mux(struct device *dev, const char *name, + char **parent_names, u8 num_parents, unsigned long flags, + void __iomem *reg, u8 shift, u8 width, + u8 clk_mux_flags, spinlock_t *lock);
/** * clk_register - allocate a new clock, register it and return an opaque cookie
On Fri, Mar 09, 2012 at 11:54:24PM -0800, Mike Turquette wrote:
Many platforms support simple gateable clocks, fixed-rate clocks, adjustable divider clocks and multi-parent multiplexer clocks.
Hi Mike
Please feel free to add:
Reviewed-by: Andrew Lunn andrew@lunn.ch Tested-by: Andrew Lunn andrew@lunn.ch
Andrew
On 03/10/2012 01:54 AM, Mike Turquette wrote:
Many platforms support simple gateable clocks, fixed-rate clocks, adjustable divider clocks and multi-parent multiplexer clocks.
This patch introduces basic clock types for the above-mentioned hardware which share some common characteristics.
Based on original work by Jeremy Kerr and contribution by Jamie Iles. Dividers and multiplexor clocks originally contributed by Richard Zhao & Sascha Hauer.
Signed-off-by: Mike Turquette mturquette@linaro.org Signed-off-by: Mike Turquette mturquette@ti.com Cc: Russell King linux@arm.linux.org.uk Cc: Jeremy Kerr jeremy.kerr@canonical.com Cc: Thomas Gleixner tglx@linutronix.de Cc: Arnd Bergman arnd.bergmann@linaro.org Cc: Paul Walmsley paul@pwsan.com Cc: Shawn Guo shawn.guo@freescale.com Cc: Sascha Hauer s.hauer@pengutronix.de Cc: Jamie Iles jamie@jamieiles.com Cc: Richard Zhao richard.zhao@linaro.org Cc: Saravana Kannan skannan@codeaurora.org Cc: Magnus Damm magnus.damm@gmail.com Cc: Rob Herring rob.herring@calxeda.com Cc: Mark Brown broonie@opensource.wolfsonmicro.com Cc: Linus Walleij linus.walleij@stericsson.com Cc: Stephen Boyd sboyd@codeaurora.org Cc: Amit Kucheria amit.kucheria@linaro.org Cc: Deepak Saxena dsaxena@linaro.org Cc: Grant Likely grant.likely@secretlab.ca Cc: Andrew Lunn andrew@lunn.ch
One issue with spinlocks below, but otherwise:
Reviewed-by: Rob Herring rob.herring@calxeda.com
Changes since v5:
- standardized the hw-specific locking in the basic clock types
- export the individual ops for each basic clock type
- improve registration for single-parent basic clocks (thanks Sascha)
- fixed bugs in gate clock's static initializers (thanks Andrew)
drivers/clk/Makefile | 3 +- drivers/clk/clk-divider.c | 204 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/clk-fixed-rate.c | 82 +++++++++++++++++ drivers/clk/clk-gate.c | 157 ++++++++++++++++++++++++++++++++ drivers/clk/clk-mux.c | 123 +++++++++++++++++++++++++ include/linux/clk-private.h | 124 +++++++++++++++++++++++++ include/linux/clk-provider.h | 127 ++++++++++++++++++++++++++ 7 files changed, 819 insertions(+), 1 deletions(-) create mode 100644 drivers/clk/clk-divider.c create mode 100644 drivers/clk/clk-fixed-rate.c create mode 100644 drivers/clk/clk-gate.c create mode 100644 drivers/clk/clk-mux.c
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index ff362c4..1f736bc 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o -obj-$(CONFIG_COMMON_CLK) += clk.o +obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \
clk-mux.o clk-divider.o
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c new file mode 100644 index 0000000..c0c4e0b --- /dev/null +++ b/drivers/clk/clk-divider.c @@ -0,0 +1,204 @@ +/*
- Copyright (C) 2011 Sascha Hauer, Pengutronix s.hauer@pengutronix.de
- Copyright (C) 2011 Richard Zhao, Linaro richard.zhao@linaro.org
- Copyright (C) 2011-2012 Mike Turquette, 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.
- Adjustable divider clock implementation
- */
+#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/string.h>
+/*
- DOC: basic adjustable divider clock that cannot gate
- Traits of this clock:
- prepare - clk_prepare only ensures that parents are prepared
- enable - clk_enable only ensures that parents are enabled
- rate - rate is adjustable. clk->rate = parent->rate / divisor
- parent - fixed parent. No clk_set_parent support
- */
+#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
+static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
+{
- struct clk_divider *divider = to_clk_divider(hw);
- unsigned int div;
- unsigned long flags = 0;
- if (divider->lock)
spin_lock_irqsave(divider->lock, flags);
- div = readl(divider->reg) >> divider->shift;
- div &= (1 << divider->width) - 1;
- if (divider->lock)
spin_unlock_irqrestore(divider->lock, flags);
What are you locking against? You are only reading the register.
- if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
div++;
- return parent_rate / div;
+} +EXPORT_SYMBOL_GPL(clk_divider_recalc_rate);
+static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate)
+{
- struct clk_divider *divider = to_clk_divider(hw);
- int i, bestdiv = 0;
- unsigned long parent_rate, best = 0, now, maxdiv;
- maxdiv = (1 << divider->width);
- if (divider->flags & CLK_DIVIDER_ONE_BASED)
maxdiv--;
- if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
bestdiv = parent_rate / rate;
bestdiv = bestdiv == 0 ? 1 : bestdiv;
bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
goto out;
- }
- /*
* The maximum divider we can use without overflowing
* unsigned long in rate * i below
*/
- maxdiv = min(ULONG_MAX / rate, maxdiv);
- for (i = 1; i <= maxdiv; i++) {
int div;
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
rate * i);
div = parent_rate / rate;
div = div > maxdiv ? maxdiv : div;
div = div < 1 ? 1 : div;
now = parent_rate / div;
if (now <= rate && now >= best) {
bestdiv = div;
best = now;
*best_parent_rate = parent_rate;
}
- }
- if (!bestdiv) {
bestdiv = (1 << divider->width);
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
- } else {
parent_rate = best * bestdiv;
- }
+out:
- if (best_parent_rate)
*best_parent_rate = parent_rate;
- return bestdiv;
+}
+static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
+{
- unsigned long best_parent_rate;
- int div = clk_divider_bestdiv(hw, rate, &best_parent_rate);
- if (prate) {
if (best_parent_rate == __clk_get_rate(
__clk_get_parent(hw->clk)))
*prate = 0;
else
*prate = best_parent_rate;
- }
- return best_parent_rate / div;
+} +EXPORT_SYMBOL_GPL(clk_divider_round_rate);
+static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate) +{
- unsigned long best_parent_rate;
- struct clk_divider *divider = to_clk_divider(hw);
- unsigned int div;
- unsigned long flags = 0;
- u32 val;
- div = clk_divider_bestdiv(hw, rate, &best_parent_rate);
- if (divider->lock)
spin_lock_irqsave(divider->lock, flags);
- if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
div--;
- val = readl(divider->reg);
- val &= ~(((1 << divider->width) - 1) << divider->shift);
- val |= div << divider->shift;
- writel(val, divider->reg);
- if (divider->lock)
spin_unlock_irqrestore(divider->lock, flags);
- return 0;
+} +EXPORT_SYMBOL_GPL(clk_divider_set_rate);
+struct clk_ops clk_divider_ops = {
- .recalc_rate = clk_divider_recalc_rate,
- .round_rate = clk_divider_round_rate,
- .set_rate = clk_divider_set_rate,
+}; +EXPORT_SYMBOL_GPL(clk_divider_ops);
+struct clk *clk_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, spinlock_t *lock)
+{
- struct clk_divider *div;
- struct clk *clk;
- div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
- if (!div) {
pr_err("%s: could not allocate divider clk\n", __func__);
return NULL;
- }
- /* struct clk_divider assignments */
- div->reg = reg;
- div->shift = shift;
- div->width = width;
- div->flags = clk_divider_flags;
- div->lock = lock;
- if (parent_name) {
div->parent[0] = kstrdup(parent_name, GFP_KERNEL);
if (!div->parent[0])
goto out;
- }
- clk = clk_register(dev, name,
&clk_divider_ops, &div->hw,
div->parent,
(parent_name ? 1 : 0),
flags);
- if (clk)
return clk;
+out:
- kfree(div->parent[0]);
- kfree(div);
- return NULL;
+} diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c new file mode 100644 index 0000000..90c79fb --- /dev/null +++ b/drivers/clk/clk-fixed-rate.c @@ -0,0 +1,82 @@ +/*
- Copyright (C) 2010-2011 Canonical Ltd jeremy.kerr@canonical.com
- Copyright (C) 2011-2012 Mike Turquette, 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.
- Fixed rate clock implementation
- */
+#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h>
+/*
- DOC: basic fixed-rate clock that cannot gate
- Traits of this clock:
- prepare - clk_(un)prepare only ensures parents are prepared
- enable - clk_enable only ensures parents are enabled
- rate - rate is always a fixed value. No clk_set_rate support
- parent - fixed parent. No clk_set_parent support
- */
+#define to_clk_fixed_rate(_hw) container_of(_hw, struct clk_fixed_rate, hw)
+static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
+{
- return to_clk_fixed_rate(hw)->fixed_rate;
+} +EXPORT_SYMBOL_GPL(clk_fixed_rate_recalc_rate);
+struct clk_ops clk_fixed_rate_ops = {
- .recalc_rate = clk_fixed_rate_recalc_rate,
+}; +EXPORT_SYMBOL_GPL(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_fixed_rate *fixed;
- char **parent_names = NULL;
- u8 len;
- fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL);
- if (!fixed) {
pr_err("%s: could not allocate fixed clk\n", __func__);
return ERR_PTR(-ENOMEM);
- }
- /* struct clk_fixed_rate assignments */
- fixed->fixed_rate = fixed_rate;
- if (parent_name) {
parent_names = kmalloc(sizeof(char *), GFP_KERNEL);
if (! parent_names)
goto out;
len = sizeof(char) * strlen(parent_name);
parent_names[0] = kmalloc(len, GFP_KERNEL);
if (!parent_names[0])
goto out;
strncpy(parent_names[0], parent_name, len);
- }
+out:
- return clk_register(dev, name,
&clk_fixed_rate_ops, &fixed->hw,
parent_names,
(parent_name ? 1 : 0),
flags);
+} diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c new file mode 100644 index 0000000..5d50efa --- /dev/null +++ b/drivers/clk/clk-gate.c @@ -0,0 +1,157 @@ +/*
- Copyright (C) 2010-2011 Canonical Ltd jeremy.kerr@canonical.com
- Copyright (C) 2011-2012 Mike Turquette, 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.
- Gated clock implementation
- */
+#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/string.h>
+/**
- DOC: basic gatable clock which can gate and ungate it's ouput
- Traits of this clock:
- prepare - clk_(un)prepare only ensures parent is (un)prepared
- enable - clk_enable and clk_disable are functional & control gating
- rate - inherits rate from parent. No clk_set_rate support
- parent - fixed parent. No clk_set_parent support
- */
+#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
+static void clk_gate_set_bit(struct clk_gate *gate) +{
- u32 reg;
- unsigned long flags = 0;
- if (gate->lock)
spin_lock_irqsave(gate->lock, flags);
- reg = readl(gate->reg);
- reg |= BIT(gate->bit_idx);
- writel(reg, gate->reg);
- if (gate->lock)
spin_unlock_irqrestore(gate->lock, flags);
+}
+static void clk_gate_clear_bit(struct clk_gate *gate) +{
- u32 reg;
- unsigned long flags = 0;
- if (gate->lock)
spin_lock_irqsave(gate->lock, flags);
- reg = readl(gate->reg);
- reg &= ~BIT(gate->bit_idx);
- writel(reg, gate->reg);
- if (gate->lock)
spin_unlock_irqrestore(gate->lock, flags);
+}
+static int clk_gate_enable(struct clk_hw *hw) +{
- struct clk_gate *gate = to_clk_gate(hw);
- if (gate->flags & CLK_GATE_SET_TO_DISABLE)
clk_gate_clear_bit(gate);
- else
clk_gate_set_bit(gate);
- return 0;
+} +EXPORT_SYMBOL_GPL(clk_gate_enable);
+static void clk_gate_disable(struct clk_hw *hw) +{
- struct clk_gate *gate = to_clk_gate(hw);
- if (gate->flags & CLK_GATE_SET_TO_DISABLE)
clk_gate_set_bit(gate);
- else
clk_gate_clear_bit(gate);
+} +EXPORT_SYMBOL_GPL(clk_gate_disable);
+static int clk_gate_is_enabled(struct clk_hw *hw) +{
- u32 reg;
- unsigned long flags = 0;
- struct clk_gate *gate = to_clk_gate(hw);
- if (gate->lock)
spin_lock_irqsave(gate->lock, flags);
- reg = readl(gate->reg);
- if (gate->lock)
spin_unlock_irqrestore(gate->lock, flags);
ditto.
- /* if a set bit disables this clk, flip it before masking */
- if (gate->flags & CLK_GATE_SET_TO_DISABLE)
reg ^= BIT(gate->bit_idx);
- reg &= BIT(gate->bit_idx);
- return reg ? 1 : 0;
+} +EXPORT_SYMBOL_GPL(clk_gate_is_enabled);
+struct clk_ops clk_gate_ops = {
- .enable = clk_gate_enable,
- .disable = clk_gate_disable,
- .is_enabled = clk_gate_is_enabled,
+}; +EXPORT_SYMBOL_GPL(clk_gate_ops);
+struct clk *clk_register_gate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 bit_idx,
u8 clk_gate_flags, spinlock_t *lock)
+{
- struct clk_gate *gate;
- struct clk *clk;
- gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
- if (!gate) {
pr_err("%s: could not allocate gated clk\n", __func__);
return NULL;
- }
- /* struct clk_gate assignments */
- gate->reg = reg;
- gate->bit_idx = bit_idx;
- gate->flags = clk_gate_flags;
- gate->lock = lock;
- if (parent_name) {
gate->parent[0] = kstrdup(parent_name, GFP_KERNEL);
if (!gate->parent[0])
goto out;
- }
- clk = clk_register(dev, name,
&clk_gate_ops, &gate->hw,
gate->parent,
(parent_name ? 1 : 0),
flags);
- if (clk)
return clk;
+out:
- kfree(gate->parent[0]);
- kfree(gate);
- return NULL;
+} diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c new file mode 100644 index 0000000..6fc0878 --- /dev/null +++ b/drivers/clk/clk-mux.c @@ -0,0 +1,123 @@ +/*
- Copyright (C) 2011 Sascha Hauer, Pengutronix s.hauer@pengutronix.de
- Copyright (C) 2011 Richard Zhao, Linaro richard.zhao@linaro.org
- Copyright (C) 2011-2012 Mike Turquette, 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.
- Simple multiplexer clock implementation
- */
+#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h>
+/*
- DOC: basic adjustable multiplexer clock that cannot gate
- Traits of this clock:
- prepare - clk_prepare only ensures that parents are prepared
- enable - clk_enable only ensures that parents are enabled
- rate - rate is only affected by parent switching. No clk_set_rate support
- parent - parent is adjustable through clk_set_parent
- */
+#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw)
+static u8 clk_mux_get_parent(struct clk_hw *hw) +{
- struct clk_mux *mux = to_clk_mux(hw);
- u32 val;
- unsigned long flags = 0;
- if (mux->lock)
spin_lock_irqsave(mux->lock, flags);
- /*
* FIXME need a mux-specific flag to determine if val is bitwise or numeric
* e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1
* to 0x7 (index starts at one)
* OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
* val = 0x4 really means "bit 2, index starts at bit 0"
*/
- val = readl(mux->reg) >> mux->shift;
- val &= (1 << mux->width) - 1;
- if (mux->lock)
spin_unlock_irqrestore(mux->lock, flags);
ditto
- if (val && (mux->flags & CLK_MUX_INDEX_BIT))
val = ffs(val) - 1;
- if (val && (mux->flags & CLK_MUX_INDEX_ONE))
val--;
- if (val >= __clk_get_num_parents(hw->clk))
return -EINVAL;
- return val;
+} +EXPORT_SYMBOL_GPL(clk_mux_get_parent);
+static int clk_mux_set_parent(struct clk_hw *hw, u8 index) +{
- struct clk_mux *mux = to_clk_mux(hw);
- u32 val;
- unsigned long flags = 0;
- if (mux->flags & CLK_MUX_INDEX_BIT)
index = (1 << ffs(index));
- if (mux->flags & CLK_MUX_INDEX_ONE)
index++;
- if (mux->lock)
spin_lock_irqsave(mux->lock, flags);
- val = readl(mux->reg);
- val &= ~(((1 << mux->width) - 1) << mux->shift);
- val |= index << mux->shift;
- writel(val, mux->reg);
- if (mux->lock)
spin_unlock_irqrestore(mux->lock, flags);
- return 0;
+} +EXPORT_SYMBOL_GPL(clk_mux_set_parent);
+struct clk_ops clk_mux_ops = {
- .get_parent = clk_mux_get_parent,
- .set_parent = clk_mux_set_parent,
+}; +EXPORT_SYMBOL_GPL(clk_mux_ops);
+struct clk *clk_register_mux(struct device *dev, const char *name,
char **parent_names, u8 num_parents, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_mux_flags, spinlock_t *lock)
+{
- struct clk_mux *mux;
- mux = kmalloc(sizeof(struct clk_mux), GFP_KERNEL);
- if (!mux) {
pr_err("%s: could not allocate mux clk\n", __func__);
return ERR_PTR(-ENOMEM);
- }
- /* struct clk_mux assignments */
- mux->reg = reg;
- mux->shift = shift;
- mux->width = width;
- mux->flags = clk_mux_flags;
- mux->lock = lock;
- return clk_register(dev, name, &clk_mux_ops, &mux->hw,
parent_names, num_parents, flags);
+} diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index 33bf6a7..9d5c4b1 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -45,6 +45,130 @@ struct clk { #endif }; +/*
- DOC: Basic clock implementations common to many platforms
- Each basic clock hardware type is comprised of a structure describing the
- clock hardware, implementations of the relevant callbacks in struct clk_ops,
- unique flags for that hardware type, a registration function and an
- alternative macro for static initialization
- */
+extern struct clk_ops clk_fixed_rate_ops;
+#define DEFINE_CLK_FIXED_RATE(_name, _flags, _rate, \
_fixed_rate_flags) \
- static struct clk _name; \
- static char *_name##_parent_names[] = {}; \
- static struct clk_fixed_rate _name##_hw = { \
.hw = { \
.clk = &_name, \
}, \
.fixed_rate = _rate, \
.flags = _fixed_rate_flags, \
- }; \
- static struct clk _name = { \
.name = #_name, \
.ops = &clk_fixed_rate_ops, \
.hw = &_name##_hw.hw, \
.parent_names = _name##_parent_names, \
.num_parents = \
ARRAY_SIZE(_name##_parent_names), \
.flags = _flags, \
- };
+extern struct clk_ops clk_gate_ops;
+#define DEFINE_CLK_GATE(_name, _parent_name, _parent_ptr, \
_flags, _reg, _bit_idx, \
_gate_flags, _lock) \
- static struct clk _name; \
- static char *_name##_parent_names[] = { \
_parent_name, \
- }; \
- static struct clk *_name##_parents[] = { \
_parent_ptr, \
- }; \
- static struct clk_gate _name##_hw = { \
.hw = { \
.clk = &_name, \
}, \
.reg = _reg, \
.bit_idx = _bit_idx, \
.flags = _gate_flags, \
.lock = _lock, \
- }; \
- static struct clk _name = { \
.name = #_name, \
.ops = &clk_gate_ops, \
.hw = &_name##_hw.hw, \
.parent_names = _name##_parent_names, \
.num_parents = \
ARRAY_SIZE(_name##_parent_names), \
.parents = _name##_parents, \
.flags = _flags, \
- };
+extern struct clk_ops clk_divider_ops;
+#define DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \
_flags, _reg, _shift, _width, \
_divider_flags, _lock) \
- static struct clk _name; \
- static char *_name##_parent_names[] = { \
_parent_name, \
- }; \
- static struct clk *_name##_parents[] = { \
_parent_ptr, \
- }; \
- static struct clk_divider _name##_hw = { \
.hw = { \
.clk = &_name, \
}, \
.reg = _reg, \
.shift = _shift, \
.width = _width, \
.flags = _divider_flags, \
.lock = _lock, \
- }; \
- static struct clk _name = { \
.name = #_name, \
.ops = &clk_divider_ops, \
.hw = &_name##_hw.hw, \
.parent_names = _name##_parent_names, \
.num_parents = \
ARRAY_SIZE(_name##_parent_names), \
.parents = _name##_parents, \
.flags = _flags, \
- };
+extern struct clk_ops clk_mux_ops;
+#define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags, \
_reg, _shift, _width, \
_mux_flags, _lock) \
- static struct clk _name; \
- static struct clk_mux _name##_hw = { \
.hw = { \
.clk = &_name, \
}, \
.reg = _reg, \
.shift = _shift, \
.width = _width, \
.flags = _mux_flags, \
.lock = _lock, \
- }; \
- static struct clk _name = { \
.name = #_name, \
.ops = &clk_mux_ops, \
.hw = &_name##_hw.hw, \
.parent_names = _parent_names, \
.num_parents = \
ARRAY_SIZE(_parent_names), \
.parents = _parents, \
.flags = _flags, \
- };
/**
- __clk_init - initialize the data structures in a struct clk
- @dev: device initializing this clk, placeholder for now
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 09dea1f..853d526 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -129,6 +129,133 @@ struct clk_ops { void (*init)(struct clk_hw *hw); }; +/*
- DOC: Basic clock implementations common to many platforms
- Each basic clock hardware type is comprised of a structure describing the
- clock hardware, implementations of the relevant callbacks in struct clk_ops,
- unique flags for that hardware type, a registration function and an
- alternative macro for static initialization
- */
+/**
- struct clk_fixed_rate - fixed-rate clock
- @hw: handle between common and hardware-specific interfaces
- @fixed_rate: constant frequency of clock
- */
+struct clk_fixed_rate {
- struct clk_hw hw;
- unsigned long fixed_rate;
- u8 flags;
+};
+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_gate - gating clock
- @hw: handle between common and hardware-specific interfaces
- @reg: register controlling gate
- @bit_idx: single bit controlling gate
- @flags: hardware-specific flags
- @lock: register lock
- Clock which can gate its output. Implements .enable & .disable
- Flags:
- CLK_GATE_SET_DISABLE - by default this clock sets the bit at bit_idx to
- enable the clock. Setting this flag does the opposite: setting the bit
- disable the clock and clearing it enables the clock
- */
+struct clk_gate {
- struct clk_hw hw;
- void __iomem *reg;
- u8 bit_idx;
- u8 flags;
- spinlock_t *lock;
- char *parent[1];
+};
+#define CLK_GATE_SET_TO_DISABLE BIT(0)
+struct clk *clk_register_gate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 bit_idx,
u8 clk_gate_flags, spinlock_t *lock);
+/**
- struct clk_divider - adjustable divider clock
- @hw: handle between common and hardware-specific interfaces
- @reg: register containing the divider
- @shift: shift to the divider bit field
- @width: width of the divider bit field
- @lock: register lock
- Clock with an adjustable divider affecting its output frequency. Implements
- .recalc_rate, .set_rate and .round_rate
- Flags:
- CLK_DIVIDER_ONE_BASED - by default the divisor is the value read from the
- register plus one. If CLK_DIVIDER_ONE_BASED is set then the divider is
- the raw value read from the register, with the value of zero considered
- invalid
- CLK_DIVIDER_POWER_OF_TWO - clock divisor is 2 raised to the value read from
- the hardware register
- */
+struct clk_divider {
- struct clk_hw hw;
- void __iomem *reg;
- u8 shift;
- u8 width;
- u8 flags;
- spinlock_t *lock;
- char *parent[1];
+};
+#define CLK_DIVIDER_ONE_BASED BIT(0) +#define CLK_DIVIDER_POWER_OF_TWO BIT(1)
+struct clk *clk_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, spinlock_t *lock);
+/**
- struct clk_mux - multiplexer clock
- @hw: handle between common and hardware-specific interfaces
- @reg: register controlling multiplexer
- @shift: shift to multiplexer bit field
- @width: width of mutliplexer bit field
- @num_clks: number of parent clocks
- @lock: register lock
- Clock with multiple selectable parents. Implements .get_parent, .set_parent
- and .recalc_rate
- Flags:
- CLK_MUX_INDEX_ONE - register index starts at 1, not 0
- CLK_MUX_INDEX_BITWISE - register index is a single bit (power of two)
- */
+struct clk_mux {
- struct clk_hw hw;
- void __iomem *reg;
- u8 shift;
- u8 width;
- u8 flags;
- spinlock_t *lock;
+};
+#define CLK_MUX_INDEX_ONE BIT(0) +#define CLK_MUX_INDEX_BIT BIT(1)
+struct clk *clk_register_mux(struct device *dev, const char *name,
char **parent_names, u8 num_parents, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_mux_flags, spinlock_t *lock);
/**
- clk_register - allocate a new clock, register it and return an opaque cookie
On Mon, Mar 12, 2012 at 1:18 PM, Rob Herring robherring2@gmail.com wrote:
On 03/10/2012 01:54 AM, Mike Turquette wrote:
Many platforms support simple gateable clocks, fixed-rate clocks, adjustable divider clocks and multi-parent multiplexer clocks.
This patch introduces basic clock types for the above-mentioned hardware which share some common characteristics.
Based on original work by Jeremy Kerr and contribution by Jamie Iles. Dividers and multiplexor clocks originally contributed by Richard Zhao & Sascha Hauer.
Signed-off-by: Mike Turquette mturquette@linaro.org Signed-off-by: Mike Turquette mturquette@ti.com Cc: Russell King linux@arm.linux.org.uk Cc: Jeremy Kerr jeremy.kerr@canonical.com Cc: Thomas Gleixner tglx@linutronix.de Cc: Arnd Bergman arnd.bergmann@linaro.org Cc: Paul Walmsley paul@pwsan.com Cc: Shawn Guo shawn.guo@freescale.com Cc: Sascha Hauer s.hauer@pengutronix.de Cc: Jamie Iles jamie@jamieiles.com Cc: Richard Zhao richard.zhao@linaro.org Cc: Saravana Kannan skannan@codeaurora.org Cc: Magnus Damm magnus.damm@gmail.com Cc: Rob Herring rob.herring@calxeda.com Cc: Mark Brown broonie@opensource.wolfsonmicro.com Cc: Linus Walleij linus.walleij@stericsson.com Cc: Stephen Boyd sboyd@codeaurora.org Cc: Amit Kucheria amit.kucheria@linaro.org Cc: Deepak Saxena dsaxena@linaro.org Cc: Grant Likely grant.likely@secretlab.ca Cc: Andrew Lunn andrew@lunn.ch
One issue with spinlocks below, but otherwise:
Reviewed-by: Rob Herring rob.herring@calxeda.com
Changes since v5: * standardized the hw-specific locking in the basic clock types * export the individual ops for each basic clock type * improve registration for single-parent basic clocks (thanks Sascha) * fixed bugs in gate clock's static initializers (thanks Andrew)
drivers/clk/Makefile | 3 +- drivers/clk/clk-divider.c | 204 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/clk-fixed-rate.c | 82 +++++++++++++++++ drivers/clk/clk-gate.c | 157 ++++++++++++++++++++++++++++++++ drivers/clk/clk-mux.c | 123 +++++++++++++++++++++++++ include/linux/clk-private.h | 124 +++++++++++++++++++++++++ include/linux/clk-provider.h | 127 ++++++++++++++++++++++++++ 7 files changed, 819 insertions(+), 1 deletions(-) create mode 100644 drivers/clk/clk-divider.c create mode 100644 drivers/clk/clk-fixed-rate.c create mode 100644 drivers/clk/clk-gate.c create mode 100644 drivers/clk/clk-mux.c
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index ff362c4..1f736bc 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -1,3 +1,4 @@
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o -obj-$(CONFIG_COMMON_CLK) += clk.o +obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \
- clk-mux.o clk-divider.o
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c new file mode 100644 index 0000000..c0c4e0b --- /dev/null +++ b/drivers/clk/clk-divider.c @@ -0,0 +1,204 @@ +/*
- Copyright (C) 2011 Sascha Hauer, Pengutronix s.hauer@pengutronix.de
- Copyright (C) 2011 Richard Zhao, Linaro richard.zhao@linaro.org
- Copyright (C) 2011-2012 Mike Turquette, 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.
- Adjustable divider clock implementation
- */
+#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/string.h>
+/*
- DOC: basic adjustable divider clock that cannot gate
- Traits of this clock:
- prepare - clk_prepare only ensures that parents are prepared
- enable - clk_enable only ensures that parents are enabled
- rate - rate is adjustable. clk->rate = parent->rate / divisor
- parent - fixed parent. No clk_set_parent support
- */
+#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
+static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
+{
- struct clk_divider *divider = to_clk_divider(hw);
- unsigned int div;
- unsigned long flags = 0;
- if (divider->lock)
- spin_lock_irqsave(divider->lock, flags);
- div = readl(divider->reg) >> divider->shift;
- div &= (1 << divider->width) - 1;
- if (divider->lock)
- spin_unlock_irqrestore(divider->lock, flags);
What are you locking against? You are only reading the register.
Hi Rob,
These register-level locks originally came in from the divider & multiplexer patches from Richard and Sascha and I'm sure they can give you more details than I.
Basically on their platform they have some 32-bits regs that have a lot of overlapping clock functions in them, such as enable/disable and adjusting a divider all in one reg. Those operations are protected by different locks (enable spinlock and prepare mutex, respectively) so some synchronization mechanism is necessary. On OMAP we don't use this since we have a billion registers that typically only map to one clock each. I also wonder if having device type memory for the affected regions makes a this irrelevant on ARM... but that wouldn't matter for non-ARM architectures. Just a thought.
Regards, Mike
- if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
- div++;
- return parent_rate / div;
+} +EXPORT_SYMBOL_GPL(clk_divider_recalc_rate);
+static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
- unsigned long *best_parent_rate)
+{
- struct clk_divider *divider = to_clk_divider(hw);
- int i, bestdiv = 0;
- unsigned long parent_rate, best = 0, now, maxdiv;
- maxdiv = (1 << divider->width);
- if (divider->flags & CLK_DIVIDER_ONE_BASED)
- maxdiv--;
- if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
- parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
- bestdiv = parent_rate / rate;
- bestdiv = bestdiv == 0 ? 1 : bestdiv;
- bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
- goto out;
- }
- /*
- * The maximum divider we can use without overflowing
- * unsigned long in rate * i below
- */
- maxdiv = min(ULONG_MAX / rate, maxdiv);
- for (i = 1; i <= maxdiv; i++) {
- int div;
- parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
- rate * i);
- div = parent_rate / rate;
- div = div > maxdiv ? maxdiv : div;
- div = div < 1 ? 1 : div;
- now = parent_rate / div;
- if (now <= rate && now >= best) {
- bestdiv = div;
- best = now;
- *best_parent_rate = parent_rate;
- }
- }
- if (!bestdiv) {
- bestdiv = (1 << divider->width);
- parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
- } else {
- parent_rate = best * bestdiv;
- }
+out:
- if (best_parent_rate)
- *best_parent_rate = parent_rate;
- return bestdiv;
+}
+static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+{
- unsigned long best_parent_rate;
- int div = clk_divider_bestdiv(hw, rate, &best_parent_rate);
- if (prate) {
- if (best_parent_rate == __clk_get_rate(
- __clk_get_parent(hw->clk)))
- *prate = 0;
- else
- *prate = best_parent_rate;
- }
- return best_parent_rate / div;
+} +EXPORT_SYMBOL_GPL(clk_divider_round_rate);
+static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate) +{
- unsigned long best_parent_rate;
- struct clk_divider *divider = to_clk_divider(hw);
- unsigned int div;
- unsigned long flags = 0;
- u32 val;
- div = clk_divider_bestdiv(hw, rate, &best_parent_rate);
- if (divider->lock)
- spin_lock_irqsave(divider->lock, flags);
- if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
- div--;
- val = readl(divider->reg);
- val &= ~(((1 << divider->width) - 1) << divider->shift);
- val |= div << divider->shift;
- writel(val, divider->reg);
- if (divider->lock)
- spin_unlock_irqrestore(divider->lock, flags);
- return 0;
+} +EXPORT_SYMBOL_GPL(clk_divider_set_rate);
+struct clk_ops clk_divider_ops = {
- .recalc_rate = clk_divider_recalc_rate,
- .round_rate = clk_divider_round_rate,
- .set_rate = clk_divider_set_rate,
+}; +EXPORT_SYMBOL_GPL(clk_divider_ops);
+struct clk *clk_register_divider(struct device *dev, const char *name,
- const char *parent_name, unsigned long flags,
- void __iomem *reg, u8 shift, u8 width,
- u8 clk_divider_flags, spinlock_t *lock)
+{
- struct clk_divider *div;
- struct clk *clk;
- div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
- if (!div) {
- pr_err("%s: could not allocate divider clk\n", __func__);
- return NULL;
- }
- /* struct clk_divider assignments */
- div->reg = reg;
- div->shift = shift;
- div->width = width;
- div->flags = clk_divider_flags;
- div->lock = lock;
- if (parent_name) {
- div->parent[0] = kstrdup(parent_name, GFP_KERNEL);
- if (!div->parent[0])
- goto out;
- }
- clk = clk_register(dev, name,
- &clk_divider_ops, &div->hw,
- div->parent,
- (parent_name ? 1 : 0),
- flags);
- if (clk)
- return clk;
+out:
- kfree(div->parent[0]);
- kfree(div);
- return NULL;
+} diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c new file mode 100644 index 0000000..90c79fb --- /dev/null +++ b/drivers/clk/clk-fixed-rate.c @@ -0,0 +1,82 @@ +/*
- Copyright (C) 2010-2011 Canonical Ltd jeremy.kerr@canonical.com
- Copyright (C) 2011-2012 Mike Turquette, 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.
- Fixed rate clock implementation
- */
+#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h>
+/*
- DOC: basic fixed-rate clock that cannot gate
- Traits of this clock:
- prepare - clk_(un)prepare only ensures parents are prepared
- enable - clk_enable only ensures parents are enabled
- rate - rate is always a fixed value. No clk_set_rate support
- parent - fixed parent. No clk_set_parent support
- */
+#define to_clk_fixed_rate(_hw) container_of(_hw, struct clk_fixed_rate, hw)
+static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
+{
- return to_clk_fixed_rate(hw)->fixed_rate;
+} +EXPORT_SYMBOL_GPL(clk_fixed_rate_recalc_rate);
+struct clk_ops clk_fixed_rate_ops = {
- .recalc_rate = clk_fixed_rate_recalc_rate,
+}; +EXPORT_SYMBOL_GPL(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_fixed_rate *fixed;
- char **parent_names = NULL;
- u8 len;
- fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL);
- if (!fixed) {
- pr_err("%s: could not allocate fixed clk\n", __func__);
- return ERR_PTR(-ENOMEM);
- }
- /* struct clk_fixed_rate assignments */
- fixed->fixed_rate = fixed_rate;
- if (parent_name) {
- parent_names = kmalloc(sizeof(char *), GFP_KERNEL);
- if (! parent_names)
- goto out;
- len = sizeof(char) * strlen(parent_name);
- parent_names[0] = kmalloc(len, GFP_KERNEL);
- if (!parent_names[0])
- goto out;
- strncpy(parent_names[0], parent_name, len);
- }
+out:
- return clk_register(dev, name,
- &clk_fixed_rate_ops, &fixed->hw,
- parent_names,
- (parent_name ? 1 : 0),
- flags);
+} diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c new file mode 100644 index 0000000..5d50efa --- /dev/null +++ b/drivers/clk/clk-gate.c @@ -0,0 +1,157 @@ +/*
- Copyright (C) 2010-2011 Canonical Ltd jeremy.kerr@canonical.com
- Copyright (C) 2011-2012 Mike Turquette, 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.
- Gated clock implementation
- */
+#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/string.h>
+/**
- DOC: basic gatable clock which can gate and ungate it's ouput
- Traits of this clock:
- prepare - clk_(un)prepare only ensures parent is (un)prepared
- enable - clk_enable and clk_disable are functional & control gating
- rate - inherits rate from parent. No clk_set_rate support
- parent - fixed parent. No clk_set_parent support
- */
+#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
+static void clk_gate_set_bit(struct clk_gate *gate) +{
- u32 reg;
- unsigned long flags = 0;
- if (gate->lock)
- spin_lock_irqsave(gate->lock, flags);
- reg = readl(gate->reg);
- reg |= BIT(gate->bit_idx);
- writel(reg, gate->reg);
- if (gate->lock)
- spin_unlock_irqrestore(gate->lock, flags);
+}
+static void clk_gate_clear_bit(struct clk_gate *gate) +{
- u32 reg;
- unsigned long flags = 0;
- if (gate->lock)
- spin_lock_irqsave(gate->lock, flags);
- reg = readl(gate->reg);
- reg &= ~BIT(gate->bit_idx);
- writel(reg, gate->reg);
- if (gate->lock)
- spin_unlock_irqrestore(gate->lock, flags);
+}
+static int clk_gate_enable(struct clk_hw *hw) +{
- struct clk_gate *gate = to_clk_gate(hw);
- if (gate->flags & CLK_GATE_SET_TO_DISABLE)
- clk_gate_clear_bit(gate);
- else
- clk_gate_set_bit(gate);
- return 0;
+} +EXPORT_SYMBOL_GPL(clk_gate_enable);
+static void clk_gate_disable(struct clk_hw *hw) +{
- struct clk_gate *gate = to_clk_gate(hw);
- if (gate->flags & CLK_GATE_SET_TO_DISABLE)
- clk_gate_set_bit(gate);
- else
- clk_gate_clear_bit(gate);
+} +EXPORT_SYMBOL_GPL(clk_gate_disable);
+static int clk_gate_is_enabled(struct clk_hw *hw) +{
- u32 reg;
- unsigned long flags = 0;
- struct clk_gate *gate = to_clk_gate(hw);
- if (gate->lock)
- spin_lock_irqsave(gate->lock, flags);
- reg = readl(gate->reg);
- if (gate->lock)
- spin_unlock_irqrestore(gate->lock, flags);
ditto.
- /* if a set bit disables this clk, flip it before masking */
- if (gate->flags & CLK_GATE_SET_TO_DISABLE)
- reg ^= BIT(gate->bit_idx);
- reg &= BIT(gate->bit_idx);
- return reg ? 1 : 0;
+} +EXPORT_SYMBOL_GPL(clk_gate_is_enabled);
+struct clk_ops clk_gate_ops = {
- .enable = clk_gate_enable,
- .disable = clk_gate_disable,
- .is_enabled = clk_gate_is_enabled,
+}; +EXPORT_SYMBOL_GPL(clk_gate_ops);
+struct clk *clk_register_gate(struct device *dev, const char *name,
- const char *parent_name, unsigned long flags,
- void __iomem *reg, u8 bit_idx,
- u8 clk_gate_flags, spinlock_t *lock)
+{
- struct clk_gate *gate;
- struct clk *clk;
- gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
- if (!gate) {
- pr_err("%s: could not allocate gated clk\n", __func__);
- return NULL;
- }
- /* struct clk_gate assignments */
- gate->reg = reg;
- gate->bit_idx = bit_idx;
- gate->flags = clk_gate_flags;
- gate->lock = lock;
- if (parent_name) {
- gate->parent[0] = kstrdup(parent_name, GFP_KERNEL);
- if (!gate->parent[0])
- goto out;
- }
- clk = clk_register(dev, name,
- &clk_gate_ops, &gate->hw,
- gate->parent,
- (parent_name ? 1 : 0),
- flags);
- if (clk)
- return clk;
+out:
- kfree(gate->parent[0]);
- kfree(gate);
- return NULL;
+} diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c new file mode 100644 index 0000000..6fc0878 --- /dev/null +++ b/drivers/clk/clk-mux.c @@ -0,0 +1,123 @@ +/*
- Copyright (C) 2011 Sascha Hauer, Pengutronix s.hauer@pengutronix.de
- Copyright (C) 2011 Richard Zhao, Linaro richard.zhao@linaro.org
- Copyright (C) 2011-2012 Mike Turquette, 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.
- Simple multiplexer clock implementation
- */
+#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h>
+/*
- DOC: basic adjustable multiplexer clock that cannot gate
- Traits of this clock:
- prepare - clk_prepare only ensures that parents are prepared
- enable - clk_enable only ensures that parents are enabled
- rate - rate is only affected by parent switching. No clk_set_rate support
- parent - parent is adjustable through clk_set_parent
- */
+#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw)
+static u8 clk_mux_get_parent(struct clk_hw *hw) +{
- struct clk_mux *mux = to_clk_mux(hw);
- u32 val;
- unsigned long flags = 0;
- if (mux->lock)
- spin_lock_irqsave(mux->lock, flags);
- /*
- * FIXME need a mux-specific flag to determine if val is bitwise or numeric
- * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1
- * to 0x7 (index starts at one)
- * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
- * val = 0x4 really means "bit 2, index starts at bit 0"
- */
- val = readl(mux->reg) >> mux->shift;
- val &= (1 << mux->width) - 1;
- if (mux->lock)
- spin_unlock_irqrestore(mux->lock, flags);
ditto
- if (val && (mux->flags & CLK_MUX_INDEX_BIT))
- val = ffs(val) - 1;
- if (val && (mux->flags & CLK_MUX_INDEX_ONE))
- val--;
- if (val >= __clk_get_num_parents(hw->clk))
- return -EINVAL;
- return val;
+} +EXPORT_SYMBOL_GPL(clk_mux_get_parent);
+static int clk_mux_set_parent(struct clk_hw *hw, u8 index) +{
- struct clk_mux *mux = to_clk_mux(hw);
- u32 val;
- unsigned long flags = 0;
- if (mux->flags & CLK_MUX_INDEX_BIT)
- index = (1 << ffs(index));
- if (mux->flags & CLK_MUX_INDEX_ONE)
- index++;
- if (mux->lock)
- spin_lock_irqsave(mux->lock, flags);
- val = readl(mux->reg);
- val &= ~(((1 << mux->width) - 1) << mux->shift);
- val |= index << mux->shift;
- writel(val, mux->reg);
- if (mux->lock)
- spin_unlock_irqrestore(mux->lock, flags);
- return 0;
+} +EXPORT_SYMBOL_GPL(clk_mux_set_parent);
+struct clk_ops clk_mux_ops = {
- .get_parent = clk_mux_get_parent,
- .set_parent = clk_mux_set_parent,
+}; +EXPORT_SYMBOL_GPL(clk_mux_ops);
+struct clk *clk_register_mux(struct device *dev, const char *name,
- char **parent_names, u8 num_parents, unsigned long flags,
- void __iomem *reg, u8 shift, u8 width,
- u8 clk_mux_flags, spinlock_t *lock)
+{
- struct clk_mux *mux;
- mux = kmalloc(sizeof(struct clk_mux), GFP_KERNEL);
- if (!mux) {
- pr_err("%s: could not allocate mux clk\n", __func__);
- return ERR_PTR(-ENOMEM);
- }
- /* struct clk_mux assignments */
- mux->reg = reg;
- mux->shift = shift;
- mux->width = width;
- mux->flags = clk_mux_flags;
- mux->lock = lock;
- return clk_register(dev, name, &clk_mux_ops, &mux->hw,
- parent_names, num_parents, flags);
+} diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index 33bf6a7..9d5c4b1 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -45,6 +45,130 @@ struct clk { #endif };
+/*
- DOC: Basic clock implementations common to many platforms
- Each basic clock hardware type is comprised of a structure describing the
- clock hardware, implementations of the relevant callbacks in struct clk_ops,
- unique flags for that hardware type, a registration function and an
- alternative macro for static initialization
- */
+extern struct clk_ops clk_fixed_rate_ops;
+#define DEFINE_CLK_FIXED_RATE(_name, _flags, _rate, \
- _fixed_rate_flags) \
- static struct clk _name; \
- static char *_name##_parent_names[] = {}; \
- static struct clk_fixed_rate _name##_hw = { \
- .hw = { \
- .clk = &_name, \
- }, \
- .fixed_rate = _rate, \
- .flags = _fixed_rate_flags, \
- }; \
- static struct clk _name = { \
- .name = #_name, \
- .ops = &clk_fixed_rate_ops, \
- .hw = &_name##_hw.hw, \
- .parent_names = _name##_parent_names, \
- .num_parents = \
- ARRAY_SIZE(_name##_parent_names), \
- .flags = _flags, \
- };
+extern struct clk_ops clk_gate_ops;
+#define DEFINE_CLK_GATE(_name, _parent_name, _parent_ptr, \
- _flags, _reg, _bit_idx, \
- _gate_flags, _lock) \
- static struct clk _name; \
- static char *_name##_parent_names[] = { \
- _parent_name, \
- }; \
- static struct clk *_name##_parents[] = { \
- _parent_ptr, \
- }; \
- static struct clk_gate _name##_hw = { \
- .hw = { \
- .clk = &_name, \
- }, \
- .reg = _reg, \
- .bit_idx = _bit_idx, \
- .flags = _gate_flags, \
- .lock = _lock, \
- }; \
- static struct clk _name = { \
- .name = #_name, \
- .ops = &clk_gate_ops, \
- .hw = &_name##_hw.hw, \
- .parent_names = _name##_parent_names, \
- .num_parents = \
- ARRAY_SIZE(_name##_parent_names), \
- .parents = _name##_parents, \
- .flags = _flags, \
- };
+extern struct clk_ops clk_divider_ops;
+#define DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \
- _flags, _reg, _shift, _width, \
- _divider_flags, _lock) \
- static struct clk _name; \
- static char *_name##_parent_names[] = { \
- _parent_name, \
- }; \
- static struct clk *_name##_parents[] = { \
- _parent_ptr, \
- }; \
- static struct clk_divider _name##_hw = { \
- .hw = { \
- .clk = &_name, \
- }, \
- .reg = _reg, \
- .shift = _shift, \
- .width = _width, \
- .flags = _divider_flags, \
- .lock = _lock, \
- }; \
- static struct clk _name = { \
- .name = #_name, \
- .ops = &clk_divider_ops, \
- .hw = &_name##_hw.hw, \
- .parent_names = _name##_parent_names, \
- .num_parents = \
- ARRAY_SIZE(_name##_parent_names), \
- .parents = _name##_parents, \
- .flags = _flags, \
- };
+extern struct clk_ops clk_mux_ops;
+#define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags, \
- _reg, _shift, _width, \
- _mux_flags, _lock) \
- static struct clk _name; \
- static struct clk_mux _name##_hw = { \
- .hw = { \
- .clk = &_name, \
- }, \
- .reg = _reg, \
- .shift = _shift, \
- .width = _width, \
- .flags = _mux_flags, \
- .lock = _lock, \
- }; \
- static struct clk _name = { \
- .name = #_name, \
- .ops = &clk_mux_ops, \
- .hw = &_name##_hw.hw, \
- .parent_names = _parent_names, \
- .num_parents = \
- ARRAY_SIZE(_parent_names), \
- .parents = _parents, \
- .flags = _flags, \
- };
/** * __clk_init - initialize the data structures in a struct clk * @dev: device initializing this clk, placeholder for now diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 09dea1f..853d526 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -129,6 +129,133 @@ struct clk_ops { void (*init)(struct clk_hw *hw); };
+/*
- DOC: Basic clock implementations common to many platforms
- Each basic clock hardware type is comprised of a structure describing the
- clock hardware, implementations of the relevant callbacks in struct clk_ops,
- unique flags for that hardware type, a registration function and an
- alternative macro for static initialization
- */
+/**
- struct clk_fixed_rate - fixed-rate clock
- @hw: handle between common and hardware-specific interfaces
- @fixed_rate: constant frequency of clock
- */
+struct clk_fixed_rate {
- struct clk_hw hw;
- unsigned long fixed_rate;
- u8 flags;
+};
+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_gate - gating clock
- @hw: handle between common and hardware-specific interfaces
- @reg: register controlling gate
- @bit_idx: single bit controlling gate
- @flags: hardware-specific flags
- @lock: register lock
- Clock which can gate its output. Implements .enable & .disable
- Flags:
- CLK_GATE_SET_DISABLE - by default this clock sets the bit at bit_idx to
- enable the clock. Setting this flag does the opposite: setting the bit
- disable the clock and clearing it enables the clock
- */
+struct clk_gate {
- struct clk_hw hw;
- void __iomem *reg;
- u8 bit_idx;
- u8 flags;
- spinlock_t *lock;
- char *parent[1];
+};
+#define CLK_GATE_SET_TO_DISABLE BIT(0)
+struct clk *clk_register_gate(struct device *dev, const char *name,
- const char *parent_name, unsigned long flags,
- void __iomem *reg, u8 bit_idx,
- u8 clk_gate_flags, spinlock_t *lock);
+/**
- struct clk_divider - adjustable divider clock
- @hw: handle between common and hardware-specific interfaces
- @reg: register containing the divider
- @shift: shift to the divider bit field
- @width: width of the divider bit field
- @lock: register lock
- Clock with an adjustable divider affecting its output frequency. Implements
- .recalc_rate, .set_rate and .round_rate
- Flags:
- CLK_DIVIDER_ONE_BASED - by default the divisor is the value read from the
- register plus one. If CLK_DIVIDER_ONE_BASED is set then the divider is
- the raw value read from the register, with the value of zero considered
- invalid
- CLK_DIVIDER_POWER_OF_TWO - clock divisor is 2 raised to the value read from
- the hardware register
- */
+struct clk_divider {
- struct clk_hw hw;
- void __iomem *reg;
- u8 shift;
- u8 width;
- u8 flags;
- spinlock_t *lock;
- char *parent[1];
+};
+#define CLK_DIVIDER_ONE_BASED BIT(0) +#define CLK_DIVIDER_POWER_OF_TWO BIT(1)
+struct clk *clk_register_divider(struct device *dev, const char *name,
- const char *parent_name, unsigned long flags,
- void __iomem *reg, u8 shift, u8 width,
- u8 clk_divider_flags, spinlock_t *lock);
+/**
- struct clk_mux - multiplexer clock
- @hw: handle between common and hardware-specific interfaces
- @reg: register controlling multiplexer
- @shift: shift to multiplexer bit field
- @width: width of mutliplexer bit field
- @num_clks: number of parent clocks
- @lock: register lock
- Clock with multiple selectable parents. Implements .get_parent, .set_parent
- and .recalc_rate
- Flags:
- CLK_MUX_INDEX_ONE - register index starts at 1, not 0
- CLK_MUX_INDEX_BITWISE - register index is a single bit (power of two)
- */
+struct clk_mux {
- struct clk_hw hw;
- void __iomem *reg;
- u8 shift;
- u8 width;
- u8 flags;
- spinlock_t *lock;
+};
+#define CLK_MUX_INDEX_ONE BIT(0) +#define CLK_MUX_INDEX_BIT BIT(1)
+struct clk *clk_register_mux(struct device *dev, const char *name,
- char **parent_names, u8 num_parents, unsigned long flags,
- void __iomem *reg, u8 shift, u8 width,
- u8 clk_mux_flags, spinlock_t *lock);
/** * clk_register - allocate a new clock, register it and return an opaque cookie
linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
On 03/12/2012 03:58 PM, Turquette, Mike wrote:
On Mon, Mar 12, 2012 at 1:18 PM, Rob Herring robherring2@gmail.com wrote:
On 03/10/2012 01:54 AM, Mike Turquette wrote:
Many platforms support simple gateable clocks, fixed-rate clocks, adjustable divider clocks and multi-parent multiplexer clocks.
This patch introduces basic clock types for the above-mentioned hardware which share some common characteristics.
Based on original work by Jeremy Kerr and contribution by Jamie Iles. Dividers and multiplexor clocks originally contributed by Richard Zhao & Sascha Hauer.
snip
+static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
+{
struct clk_divider *divider = to_clk_divider(hw);
unsigned int div;
unsigned long flags = 0;
if (divider->lock)
spin_lock_irqsave(divider->lock, flags);
div = readl(divider->reg) >> divider->shift;
div &= (1 << divider->width) - 1;
if (divider->lock)
spin_unlock_irqrestore(divider->lock, flags);
What are you locking against? You are only reading the register.
Hi Rob,
These register-level locks originally came in from the divider & multiplexer patches from Richard and Sascha and I'm sure they can give you more details than I.
Basically on their platform they have some 32-bits regs that have a lot of overlapping clock functions in them, such as enable/disable and adjusting a divider all in one reg. Those operations are protected by different locks (enable spinlock and prepare mutex, respectively) so some synchronization mechanism is necessary. On OMAP we don't use this since we have a billion registers that typically only map to one clock each. I also wonder if having device type memory for the affected regions makes a this irrelevant on ARM... but that wouldn't matter for non-ARM architectures. Just a thought.
In fact, I pointed out that locking for a register access was needed in an early version of this series as well. However, locking is only needed if you are doing a read-mod-write on a field in a shared register or reading from multiple registers. It makes no sense if you are *only* reading a single shared register as is the case here. That's already an atomic operation.
Rob
Hi Mike,
Can I suggest/we discuss that we support fractional (i.e. represented by fixed point value with integer and fractional part) dividers in the common divider clock case, simplistically just adding a divider fractional width and shifting all the calculations by it (and fixing the "maxdiv" calculation as in a fractional case width of the divider area in the register is not an indicator of the actual maximum divider)? (I guess for the standard integer divider case, it would be continually shifting by 0 which might make the code a bit bigger, I don't think that would truly be a concern though?)
Is there a particular reason why this case also cannot support set_parent?
I have a use case here (i.MX51/53/6 IPU DI output "pixel" clock) which could be handled by this code if only those two were solved, it would save reimplementing the whole thing as a special case. I am at a loss to think of another particular case in any other SoC where there is a fractional divider on a clock where it might come in handy, though, I thought maybe someone could speak up and give an example that would come in handy for them (I can think of Marvel PXA and OMAP DSS display units having the exact same need which could be implemented using the clock API rather than opencoded inside the framebuffer drivers, but whether anyone actually cares about that is another matter entirely...)
On Mon, Mar 12, 2012 at 10:50:09PM -0500, Matt Sealey wrote:
Hi Mike,
Can I suggest/we discuss that we support fractional (i.e. represented by fixed point value with integer and fractional part) dividers in the common divider clock case, simplistically just adding a divider fractional width and shifting all the calculations by it (and fixing the "maxdiv" calculation as in a fractional case width of the divider area in the register is not an indicator of the actual maximum divider)? (I guess for the standard integer divider case, it would be continually shifting by 0 which might make the code a bit bigger, I don't think that would truly be a concern though?)
I have patches for this, see
git://git.pengutronix.de/git/imx/linux-2.6.git imx/work/imx-clkv6
Sascha
Hi Mike,
+static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate)
+{
- struct clk_divider *divider = to_clk_divider(hw);
- int i, bestdiv = 0;
- unsigned long parent_rate, best = 0, now, maxdiv;
- maxdiv = (1 << divider->width);
- if (divider->flags & CLK_DIVIDER_ONE_BASED)
maxdiv--;
- if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
bestdiv = parent_rate / rate;
bestdiv = bestdiv == 0 ? 1 : bestdiv;
bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
goto out;
- }
- /*
* The maximum divider we can use without overflowing
* unsigned long in rate * i below
*/
- maxdiv = min(ULONG_MAX / rate, maxdiv);
- for (i = 1; i <= maxdiv; i++) {
int div;
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
rate * i);
div = parent_rate / rate;
div = div > maxdiv ? maxdiv : div;
div = div < 1 ? 1 : div;
now = parent_rate / div;
if (now <= rate && now >= best) {
bestdiv = div;
best = now;
*best_parent_rate = parent_rate;
if (now == rate) break; we don't need it to loop to end, and smaller parent_rate is better.
}
- }
- if (!bestdiv) {
bestdiv = (1 << divider->width);
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
- } else {
parent_rate = best * bestdiv;
- }
+out:
- if (best_parent_rate)
*best_parent_rate = parent_rate;
- return bestdiv;
+}
On Fri, Mar 09, 2012 at 11:54:24PM -0800, Mike Turquette wrote:
Many platforms support simple gateable clocks, fixed-rate clocks, adjustable divider clocks and multi-parent multiplexer clocks.
This patch introduces basic clock types for the above-mentioned hardware which share some common characteristics.
Based on original work by Jeremy Kerr and contribution by Jamie Iles. Dividers and multiplexor clocks originally contributed by Richard Zhao & Sascha Hauer.
Signed-off-by: Mike Turquette mturquette@linaro.org Signed-off-by: Mike Turquette mturquette@ti.com Cc: Russell King linux@arm.linux.org.uk Cc: Jeremy Kerr jeremy.kerr@canonical.com Cc: Thomas Gleixner tglx@linutronix.de Cc: Arnd Bergman arnd.bergmann@linaro.org Cc: Paul Walmsley paul@pwsan.com Cc: Shawn Guo shawn.guo@freescale.com Cc: Sascha Hauer s.hauer@pengutronix.de Cc: Jamie Iles jamie@jamieiles.com Cc: Richard Zhao richard.zhao@linaro.org Cc: Saravana Kannan skannan@codeaurora.org Cc: Magnus Damm magnus.damm@gmail.com Cc: Rob Herring rob.herring@calxeda.com Cc: Mark Brown broonie@opensource.wolfsonmicro.com Cc: Linus Walleij linus.walleij@stericsson.com Cc: Stephen Boyd sboyd@codeaurora.org Cc: Amit Kucheria amit.kucheria@linaro.org Cc: Deepak Saxena dsaxena@linaro.org Cc: Grant Likely grant.likely@secretlab.ca Cc: Andrew Lunn andrew@lunn.ch
Changes since v5:
- standardized the hw-specific locking in the basic clock types
- export the individual ops for each basic clock type
- improve registration for single-parent basic clocks (thanks Sascha)
- fixed bugs in gate clock's static initializers (thanks Andrew)
drivers/clk/Makefile | 3 +- drivers/clk/clk-divider.c | 204 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/clk-fixed-rate.c | 82 +++++++++++++++++ drivers/clk/clk-gate.c | 157 ++++++++++++++++++++++++++++++++ drivers/clk/clk-mux.c | 123 +++++++++++++++++++++++++ include/linux/clk-private.h | 124 +++++++++++++++++++++++++ include/linux/clk-provider.h | 127 ++++++++++++++++++++++++++ 7 files changed, 819 insertions(+), 1 deletions(-) create mode 100644 drivers/clk/clk-divider.c create mode 100644 drivers/clk/clk-fixed-rate.c create mode 100644 drivers/clk/clk-gate.c create mode 100644 drivers/clk/clk-mux.c
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index ff362c4..1f736bc 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o -obj-$(CONFIG_COMMON_CLK) += clk.o +obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \
clk-mux.o clk-divider.o
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c new file mode 100644 index 0000000..c0c4e0b --- /dev/null +++ b/drivers/clk/clk-divider.c @@ -0,0 +1,204 @@ +/*
- Copyright (C) 2011 Sascha Hauer, Pengutronix s.hauer@pengutronix.de
- Copyright (C) 2011 Richard Zhao, Linaro richard.zhao@linaro.org
- Copyright (C) 2011-2012 Mike Turquette, 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.
- Adjustable divider clock implementation
- */
+#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/string.h>
+/*
- DOC: basic adjustable divider clock that cannot gate
- Traits of this clock:
- prepare - clk_prepare only ensures that parents are prepared
- enable - clk_enable only ensures that parents are enabled
- rate - rate is adjustable. clk->rate = parent->rate / divisor
- parent - fixed parent. No clk_set_parent support
- */
+#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
+static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
+{
- struct clk_divider *divider = to_clk_divider(hw);
- unsigned int div;
- unsigned long flags = 0;
- if (divider->lock)
spin_lock_irqsave(divider->lock, flags);
- div = readl(divider->reg) >> divider->shift;
- div &= (1 << divider->width) - 1;
- if (divider->lock)
spin_unlock_irqrestore(divider->lock, flags);
- if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
div++;
- return parent_rate / div;
+} +EXPORT_SYMBOL_GPL(clk_divider_recalc_rate);
+static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate)
+{
- struct clk_divider *divider = to_clk_divider(hw);
- int i, bestdiv = 0;
- unsigned long parent_rate, best = 0, now, maxdiv;
- maxdiv = (1 << divider->width);
We need a check for rate == 0 here:
if (rate == 0) rate = 1;
Otherwise we divide by zero below.
- if (divider->flags & CLK_DIVIDER_ONE_BASED)
maxdiv--;
- if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
bestdiv = parent_rate / rate;
It's a bit strange but due to integer maths you must use DIV_ROUND_UP in round_rate and div = parent_rate / rate in set_rate.
Example:
parent_rate = 100 rate = 34
Now the best divider would be 3 (100/3 = 33), but the above results in 2. With DIV_ROUND_UP round_rate correctly returns 33. Now when you use DIV_ROUND_UP in set_rate the resulting divider would be 4 which is wrong whereas 100/33 returns the correct result.
Sascha
On 03/14/2012 01:23 PM, Sascha Hauer wrote:
On Fri, Mar 09, 2012 at 11:54:24PM -0800, Mike Turquette wrote:
Many platforms support simple gateable clocks, fixed-rate clocks, adjustable divider clocks and multi-parent multiplexer clocks.
This patch introduces basic clock types for the above-mentioned hardware which share some common characteristics.
Based on original work by Jeremy Kerr and contribution by Jamie Iles. Dividers and multiplexor clocks originally contributed by Richard Zhao & Sascha Hauer.
Signed-off-by: Mike Turquette mturquette@linaro.org Signed-off-by: Mike Turquette mturquette@ti.com Cc: Russell King linux@arm.linux.org.uk Cc: Jeremy Kerr jeremy.kerr@canonical.com Cc: Thomas Gleixner tglx@linutronix.de Cc: Arnd Bergman arnd.bergmann@linaro.org Cc: Paul Walmsley paul@pwsan.com Cc: Shawn Guo shawn.guo@freescale.com Cc: Sascha Hauer s.hauer@pengutronix.de Cc: Jamie Iles jamie@jamieiles.com Cc: Richard Zhao richard.zhao@linaro.org Cc: Saravana Kannan skannan@codeaurora.org Cc: Magnus Damm magnus.damm@gmail.com Cc: Rob Herring rob.herring@calxeda.com Cc: Mark Brown broonie@opensource.wolfsonmicro.com Cc: Linus Walleij linus.walleij@stericsson.com Cc: Stephen Boyd sboyd@codeaurora.org Cc: Amit Kucheria amit.kucheria@linaro.org Cc: Deepak Saxena dsaxena@linaro.org Cc: Grant Likely grant.likely@secretlab.ca Cc: Andrew Lunn andrew@lunn.ch
Changes since v5:
- standardized the hw-specific locking in the basic clock types
- export the individual ops for each basic clock type
- improve registration for single-parent basic clocks (thanks Sascha)
- fixed bugs in gate clock's static initializers (thanks Andrew)
drivers/clk/Makefile | 3 +- drivers/clk/clk-divider.c | 204 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/clk-fixed-rate.c | 82 +++++++++++++++++ drivers/clk/clk-gate.c | 157 ++++++++++++++++++++++++++++++++ drivers/clk/clk-mux.c | 123 +++++++++++++++++++++++++ include/linux/clk-private.h | 124 +++++++++++++++++++++++++ include/linux/clk-provider.h | 127 ++++++++++++++++++++++++++ 7 files changed, 819 insertions(+), 1 deletions(-) create mode 100644 drivers/clk/clk-divider.c create mode 100644 drivers/clk/clk-fixed-rate.c create mode 100644 drivers/clk/clk-gate.c create mode 100644 drivers/clk/clk-mux.c
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index ff362c4..1f736bc 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o -obj-$(CONFIG_COMMON_CLK) += clk.o +obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \
clk-mux.o clk-divider.o
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c new file mode 100644 index 0000000..c0c4e0b --- /dev/null +++ b/drivers/clk/clk-divider.c @@ -0,0 +1,204 @@ +/*
- Copyright (C) 2011 Sascha Hauer, Pengutronix s.hauer@pengutronix.de
- Copyright (C) 2011 Richard Zhao, Linaro richard.zhao@linaro.org
- Copyright (C) 2011-2012 Mike Turquette, 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.
- Adjustable divider clock implementation
- */
+#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/string.h>
+/*
- DOC: basic adjustable divider clock that cannot gate
- Traits of this clock:
- prepare - clk_prepare only ensures that parents are prepared
- enable - clk_enable only ensures that parents are enabled
- rate - rate is adjustable. clk->rate = parent->rate / divisor
- parent - fixed parent. No clk_set_parent support
- */
+#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
+static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
+{
- struct clk_divider *divider = to_clk_divider(hw);
- unsigned int div;
- unsigned long flags = 0;
- if (divider->lock)
spin_lock_irqsave(divider->lock, flags);
- div = readl(divider->reg) >> divider->shift;
- div &= (1 << divider->width) - 1;
- if (divider->lock)
spin_unlock_irqrestore(divider->lock, flags);
- if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
div++;
- return parent_rate / div;
+} +EXPORT_SYMBOL_GPL(clk_divider_recalc_rate);
+static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate)
+{
- struct clk_divider *divider = to_clk_divider(hw);
- int i, bestdiv = 0;
- unsigned long parent_rate, best = 0, now, maxdiv;
- maxdiv = (1 << divider->width);
We need a check for rate == 0 here:
if (rate == 0) rate = 1;
Otherwise we divide by zero below.
- if (divider->flags & CLK_DIVIDER_ONE_BASED)
maxdiv--;
- if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
bestdiv = parent_rate / rate;
It's a bit strange but due to integer maths you must use DIV_ROUND_UP in round_rate and div = parent_rate / rate in set_rate.
Example:
parent_rate = 100 rate = 34
Now the best divider would be 3 (100/3 = 33), but the above results in 2. With DIV_ROUND_UP round_rate correctly returns 33. Now when you use DIV_ROUND_UP in set_rate the resulting divider would be 4 which is wrong whereas 100/33 returns the correct result.
This gets into the problem with round_rate. You can't specify whether to round up or down. For something like an SD card you would want to pass in the max freq for the card and get back something less than or equal to it. For something like an LCD pixel clock, you need a frequency greater than or equal to the requested freq to maintain a minimum refresh rate. There's been some discussion about this some time back.
But for now we shouldn't fix round_rate, and your solution is right (or at least safer).
Rob