<p><br>
On Feb 6, 2011 10:08 PM, "Jeremy Kerr" <<a href="mailto:jeremy.kerr@canonical.com">jeremy.kerr@canonical.com</a>> wrote:<br>
><br>
> We currently have ~21 definitions of struct clk in the ARM architecture,<br>
> each defined on a per-platform basis. This makes it difficult to define<br>
> platform- (or architecture-) independent clock sources without making<br>
> assumptions about struct clk, and impossible to compile two<br>
> platforms with different struct clks into a single image.<br>
><br>
> This change is an effort to unify struct clk where possible, by defining<br>
> a common struct clk, containing a set of clock operations. Different<br>
> clock implementations can set their own operations, and have a standard<br>
> interface for generic code. The callback interface is exposed to the<br>
> kernel proper, while the clock implementations only need to be seen by<br>
> the platform internals.<br>
><br>
> This allows us to share clock code among platforms, and makes it<br>
> possible to dynamically create clock devices in platform-independent<br>
> code.<br>
><br>
> Platforms can enable the generic struct clock through<br>
> CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure<br>
> consists of a common struct clk:<br>
><br>
> struct clk {<br>
> const struct clk_ops *ops;<br>
> unsigned int enable_count;<br>
> unsigned int prepare_count;<br>
> spinlock_t enable_lock;<br>
> struct mutex prepare_lock;<br>
> };<br>
><br>
> And a set of clock operations (defined per type of clock):<br>
><br>
> struct clk_ops {<br>
> int (*enable)(struct clk *);<br>
> void (*disable)(struct clk *);<br>
> unsigned long (*get_rate)(struct clk *);<br>
> [...]<br>
> };<br>
><br>
> To define a hardware-specific clock, machine code can "subclass" the<br>
> struct clock into a new struct (adding any device-specific data), and<br>
> provide a set of operations:<br>
><br>
> struct clk_foo {<br>
> struct clk clk;<br>
> void __iomem *some_register;<br>
> };<br>
><br>
> struct clk_ops clk_foo_ops = {<br>
> .get_rate = clk_foo_get_rate,<br>
> };<br>
><br>
> The common clock definitions are based on a development patch from Ben<br>
> Herrenschmidt <<a href="mailto:benh@kernel.crashing.org">benh@kernel.crashing.org</a>>.<br>
><br>
> Signed-off-by: Jeremy Kerr <<a href="mailto:jeremy.kerr@canonical.com">jeremy.kerr@canonical.com</a>><br>
><br>
> ---<br>
> drivers/clk/Kconfig | 3<br>
> drivers/clk/Makefile | 1<br>
> drivers/clk/clk.c | 134 +++++++++++++++++++++++++++++++<br>
> drivers/clk/clkdev.c | 5 +<br>
> include/linux/clk.h | 184 ++++++++++++++++++++++++++++++++++++++++---<br>
> 5 files changed, 318 insertions(+), 9 deletions(-)<br>
><br>
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig<br>
> index 4168c88..6e3ae54 100644<br>
> --- a/drivers/clk/Kconfig<br>
> +++ b/drivers/clk/Kconfig<br>
> @@ -2,3 +2,6 @@<br>
> config CLKDEV_LOOKUP<br>
> bool<br>
> select HAVE_CLK<br>
> +<br>
> +config USE_COMMON_STRUCT_CLK<br>
> + bool<br>
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile<br>
> index 07613fa..a1a06d3 100644<br>
> --- a/drivers/clk/Makefile<br>
> +++ b/drivers/clk/Makefile<br>
> @@ -1,2 +1,3 @@<br>
><br>
> obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o<br>
> +obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o<br>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c<br>
> new file mode 100644<br>
> index 0000000..12e0daf<br>
> --- /dev/null<br>
> +++ b/drivers/clk/clk.c<br>
> @@ -0,0 +1,134 @@<br>
> +/*<br>
> + * Copyright (C) 2010-2011 Canonical Ltd <<a href="mailto:jeremy.kerr@canonical.com">jeremy.kerr@canonical.com</a>><br>
> + *<br>
> + * This program is free software; you can redistribute it and/or modify<br>
> + * it under the terms of the GNU General Public License version 2 as<br>
> + * published by the Free Software Foundation.<br>
> + *<br>
> + * Standard functionality for the common clock API.<br>
> + */<br>
> +<br>
> +#include <linux/clk.h><br>
> +#include <linux/module.h><br>
> +<br>
> +int clk_prepare(struct clk *clk)<br>
> +{<br>
> + int ret = 0;<br>
> +<br>
> + if (!clk->ops->prepare)<br>
> + return 0;<br>
> +<br>
> + mutex_lock(&clk->prepare_lock);<br>
> + if (clk->prepare_count == 0)<br>
> + ret = clk->ops->prepare(clk);<br>
> +<br>
> + if (!ret)<br>
> + clk->prepare_count++;<br>
> + mutex_unlock(&clk->prepare_lock);<br>
> +<br>
> + return 0;</p>
<p>return ret;</p>
<p>> +}<br>
> +EXPORT_SYMBOL_GPL(clk_prepare);<br>
> +<br>
> +void clk_unprepare(struct clk *clk)<br>
> +{<br>
> + if (!clk->ops->unprepare)<br>
> + return;<br>
> +<br>
> + mutex_lock(&clk->prepare_lock);<br>
> + if (--clk->prepare_count == 0)<br>
> + clk->ops->unprepare(clk);<br>
> +<br>
> + mutex_unlock(&clk->prepare_lock);<br>
> +}<br>
> +EXPORT_SYMBOL_GPL(clk_unprepare);<br>
> +<br>
> +int clk_enable(struct clk *clk)<br>
> +{<br>
> + int ret = 0;<br>
> +<br>
> + if (!clk->ops->enable)<br>
> + return 0;<br>
> +<br>
> + spin_lock(&clk->enable_lock);<br>
> + if (!clk->enable_count)<br>
> + ret = clk->ops->enable(clk);<br>
> +<br>
> + if (!ret)<br>
> + clk->enable_count++;<br>
> + spin_unlock(&clk->enable_lock);<br>
> +<br>
> + return ret;<br>
> +}<br>
> +EXPORT_SYMBOL_GPL(clk_enable);<br>
> +<br>
> +void clk_disable(struct clk *clk)<br>
> +{<br>
> + if (!clk->ops->disable)<br>
> + return;<br>
> +<br>
> + spin_lock(&clk->enable_lock);<br>
> +<br>
> + WARN_ON(!clk->enable_count);<br>
> +<br>
> + if (!--clk->enable_count)<br>
> + clk->ops->disable(clk);<br>
> +<br>
> + spin_unlock(&clk->enable_lock);<br>
> +}<br>
> +EXPORT_SYMBOL_GPL(clk_disable);<br>
> +<br>
> +unsigned long clk_get_rate(struct clk *clk)<br>
> +{<br>
> + if (clk->ops->get_rate)<br>
> + return clk->ops->get_rate(clk);<br>
> + return 0;<br>
> +}<br>
> +EXPORT_SYMBOL_GPL(clk_get_rate);<br>
> +<br>
> +int __clk_get(struct clk *clk)<br>
> +{<br>
> + if (clk->ops->get)<br>
> + return clk->ops->get(clk);<br>
> + return 1;<br>
> +}<br>
> +EXPORT_SYMBOL_GPL(__clk_get);<br>
> +<br>
> +void clk_put(struct clk *clk)<br>
> +{<br>
> + if (clk->ops->put)<br>
> + clk->ops->put(clk);<br>
> +}<br>
> +EXPORT_SYMBOL_GPL(clk_put);<br>
> +<br>
> +long clk_round_rate(struct clk *clk, unsigned long rate)<br>
> +{<br>
> + if (clk->ops->round_rate)<br>
> + return clk->ops->round_rate(clk, rate);<br>
> + return -ENOSYS;<br>
> +}<br>
> +EXPORT_SYMBOL_GPL(clk_round_rate);<br>
> +<br>
> +int clk_set_rate(struct clk *clk, unsigned long rate)<br>
> +{<br>
> + if (clk->ops->set_rate)<br>
> + return clk->ops->set_rate(clk, rate);<br>
> + return -ENOSYS;<br>
> +}<br>
> +EXPORT_SYMBOL_GPL(clk_set_rate);<br>
> +<br>
> +int clk_set_parent(struct clk *clk, struct clk *parent)<br>
> +{<br>
> + if (clk->ops->set_parent)<br>
> + return clk->ops->set_parent(clk, parent);<br>
> + return -ENOSYS;<br>
> +}<br>
> +EXPORT_SYMBOL_GPL(clk_set_parent);<br>
> +<br>
> +struct clk *clk_get_parent(struct clk *clk)<br>
> +{<br>
> + if (clk->ops->get_parent)<br>
> + return clk->ops->get_parent(clk);<br>
> + return ERR_PTR(-ENOSYS);<br>
> +}<br>
> +EXPORT_SYMBOL_GPL(clk_get_parent);<br>
> diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c<br>
> index 0fc0a79..17619c7 100644<br>
> --- a/drivers/clk/clkdev.c<br>
> +++ b/drivers/clk/clkdev.c<br>
> @@ -84,12 +84,17 @@ struct clk *clk_get(struct device *dev, const char *con_id)<br>
> }<br>
> EXPORT_SYMBOL(clk_get);<br>
><br>
> +#ifndef CONFIG_USE_COMMON_STRUCT_CLK<br>
> +/* For the common struct clk case, clk_put is provided by clk.c */<br>
> +<br>
> void clk_put(struct clk *clk)<br>
> {<br>
> __clk_put(clk);<br>
> }<br>
> EXPORT_SYMBOL(clk_put);<br>
><br>
> +#endif<br>
> +<br>
> void clkdev_add(struct clk_lookup *cl)<br>
> {<br>
> mutex_lock(&clocks_mutex);<br>
> diff --git a/include/linux/clk.h b/include/linux/clk.h<br>
> index 1d37f42..e081ca1 100644<br>
> --- a/include/linux/clk.h<br>
> +++ b/include/linux/clk.h<br>
> @@ -3,6 +3,7 @@<br>
> *<br>
> * Copyright (C) 2004 ARM Limited.<br>
> * Written by Deep Blue Solutions Limited.<br>
> + * Copyright (c) 2010-2011 Jeremy Kerr <<a href="mailto:jeremy.kerr@canonical.com">jeremy.kerr@canonical.com</a>><br>
> *<br>
> * This program is free software; you can redistribute it and/or modify<br>
> * it under the terms of the GNU General Public License version 2 as<br>
> @@ -11,18 +12,189 @@<br>
> #ifndef __LINUX_CLK_H<br>
> #define __LINUX_CLK_H<br>
><br>
> +#include <linux/err.h><br>
> +#include <linux/mutex.h><br>
> +#include <linux/spinlock.h><br>
> +<br>
> struct device;<br>
><br>
> -/*<br>
> - * The base API.<br>
> +#ifdef CONFIG_USE_COMMON_STRUCT_CLK<br>
> +<br>
> +/* If we're using the common struct clk, we define the base clk object here */<br>
> +<br>
> +/**<br>
> + * struct clk - hardware independent clock structure<br>
> + * @ops: implementation-specific ops for this clock<br>
> + * @enable_count: count of clk_enable() calls active on this clock<br>
> + * @flags: platform-independent flags<br>
> + * @lock: lock for enable/disable or other HW-specific ops<br>
> + *<br>
> + * The base clock object, used by drivers for hardware-independent manipulation<br>
> + * of clock lines. This will be 'subclassed' by device-specific implementations,<br>
> + * which add device-specific data to struct clk. For example:<br>
> + *<br>
> + * struct clk_foo {<br>
> + * struct clk;<br>
> + * [device specific fields]<br>
> + * };<br>
> + *<br>
> + * The clock driver code will manage the device-specific data, and pass<br>
> + * clk_foo.clk to the common clock code. The clock driver will be called<br>
> + * through the @ops callbacks.<br>
> + *<br>
> + * The @lock member provides either a spinlock or a mutex to protect (at least)<br>
> + * @enable_count. The type of lock used will depend on @flags; if CLK_ATOMIC is<br>
> + * set, then the core clock code will use a spinlock, otherwise a mutex. This<br>
> + * lock will be acquired during clk_enable and clk_disable, so for atomic<br>
> + * clocks, these ops callbacks must not sleep.<br>
> + *<br>
> + * The choice of atomic or non-atomic clock depends on how the clock is enabled.<br>
> + * Typically, you'll want to use a non-atomic clock. For clocks that need to be<br>
> + * enabled/disabled in interrupt context, use CLK_ATOMIC. Note that atomic<br>
> + * clocks with parents will typically cascade enable/disable operations to<br>
> + * their parent, so the parent of an atomic clock *must* be atomic too.<br>
> */<br>
> +struct clk {<br>
> + const struct clk_ops *ops;<br>
> + unsigned int enable_count;<br>
> + unsigned int prepare_count;<br>
> + spinlock_t enable_lock;<br>
> + struct mutex prepare_lock;<br>
> +};<br>
> +<br>
> +/* static initialiser for non-atomic clocks */<br>
> +#define INIT_CLK(name, o) { \<br>
> + .ops = &o, \<br>
> + .enable_count = 0, \<br>
> + .prepare_count = 0, \<br>
> + .enable_lock = __SPIN_LOCK_UNLOCKED(name.enable_lock), \<br>
> + .prepare_lock = __MUTEX_INITIALIZER(name.prepare_lock), \<br>
> +}<br>
><br>
> +/**<br>
> + * struct clk_ops - Callback operations for clocks; these are to be provided<br>
> + * by the clock implementation, and will be called by drivers through the clk_*<br>
> + * API.<br>
> + *<br>
> + * @prepare: Prepare the clock for enabling. This must not return until<br>
> + * the clock is fully prepared, and it's safe to call clk_enable.<br>
> + * This callback is intended to allow clock implementations to<br>
> + * do any initialisation that may block. Called with<br>
> + * clk->prepare_lock held.<br>
> + *<br>
> + * @unprepare: Release the clock from its prepared state. This will typically<br>
> + * undo any work done in the @prepare callback. Called with<br>
> + * clk->prepare_lock held.<br>
> + *<br>
> + * @enable: Enable the clock atomically. This must not return until the<br>
> + * clock is generating a valid clock signal, usable by consumer<br>
> + * devices. Called with clk->enable_lock held.<br>
> + *<br>
> + * @disable: Disable the clock atomically. Called with clk->enable_lock held.<br>
> + *<br>
> + * @get: Called by the core clock code when a device driver acquires a<br>
> + * clock via clk_get(). Optional.<br>
> + *<br>
> + * @put: Called by the core clock code when a devices driver releases a<br>
> + * clock via clk_put(). Optional.<br>
> + *<br>
> + * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow<br>
> + * implementations to split any work between atomic (enable) and sleepable<br>
> + * (prepare) contexts. If a clock requires blocking code to be turned on, this<br>
> + * should be done in clk_prepare. Switching that will not block should be done<br>
> + * in clk_enable.<br>
> + *<br>
> + * Typically, drivers will call clk_prepare when a clock may be needed later<br>
> + * (eg. when a device is opened), and clk_enable when the clock is actually<br>
> + * required (eg. from an interrupt).<br>
> + *<br>
> + * For other callbacks, see the corresponding clk_* functions. Parameters and<br>
> + * return values are passed directly from/to these API functions, or<br>
> + * -ENOSYS (or zero, in the case of clk_get_rate) is returned if the callback<br>
> + * is NULL, see kernel/clk.c for implementation details. All are optional.<br>
> + */<br>
> +struct clk_ops {<br>
> + int (*prepare)(struct clk *);<br>
> + void (*unprepare)(struct clk *);<br>
> + int (*enable)(struct clk *);<br>
> + void (*disable)(struct clk *);<br>
> + int (*get)(struct clk *);<br>
> + void (*put)(struct clk *);<br>
> + unsigned long (*get_rate)(struct clk *);<br>
> + long (*round_rate)(struct clk *, unsigned long);<br>
> + int (*set_rate)(struct clk *, unsigned long);<br>
> + int (*set_parent)(struct clk *, struct clk *);<br>
> + struct clk * (*get_parent)(struct clk *);<br>
> +};<br>
> +<br>
> +/**<br>
> + * __clk_get - update clock-specific refcounter<br>
> + *<br>
> + * @clk: The clock to refcount<br>
> + *<br>
> + * Before a clock is returned from clk_get, this function should be called<br>
> + * to update any clock-specific refcounting.<br>
> + *<br>
> + * Returns non-zero on success, zero on failure.<br>
> + *<br>
> + * Drivers should not need this function; it is only needed by the<br>
> + * arch-specific clk_get() implementations.<br>
> + */<br>
> +int __clk_get(struct clk *clk);<br>
> +<br>
> +/**<br>
> + * clk_prepare - prepare clock for atomic enabling.<br>
> + *<br>
> + * @clk: The clock to prepare<br>
> + *<br>
> + * Do any blocking initialisation on @clk, allowing the clock to be later<br>
> + * enabled atomically (via clk_enable). This function may sleep.<br>
> + */<br>
> +int clk_prepare(struct clk *clk);<br>
> +<br>
> +/**<br>
> + * clk_unprepare - release clock from prepared state<br>
> + *<br>
> + * @clk: The clock to release<br>
> + *<br>
> + * Do any (possbly blocking) cleanup on clk. This function may sleep.<br>
> + */<br>
> +void clk_unprepare(struct clk *clk);<br>
> +<br>
> +/**<br>
> + * clk_common_init - initialise a clock for driver usage<br>
> + *<br>
> + * @clk: The clock to initialise<br>
> + *<br>
> + * Used for runtime intialization of clocks; you don't need to call this<br>
> + * if your clock has been (statically) initialized with INIT_CLK.<br>
> + */<br>
> +static inline void clk_common_init(struct clk *clk)<br>
> +{<br>
> + clk->enable_count = clk->prepare_count = 0;<br>
> + spin_lock_init(&clk->enable_lock);<br>
> + mutex_init(&clk->prepare_lock);<br>
> +}<br>
> +<br>
> +#else /* !CONFIG_USE_COMMON_STRUCT_CLK */<br>
><br>
> /*<br>
> - * struct clk - an machine class defined object / cookie.<br>
> + * Global clock object, actual structure is declared per-machine<br>
> */<br>
> struct clk;<br>
><br>
> +static inline void clk_common_init(struct clk *clk) { }<br>
> +<br>
> +/*<br>
> + * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity<br>
> + * requirements for clk_enable/clk_disable, so the prepare and unprepare<br>
> + * functions are no-ops<br>
> + */<br>
> +int clk_prepare(struct clk *clk) { return 0; }<br>
> +void clk_unprepare(struct clk *clk) { }<br>
> +<br>
> +#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */<br>
> +<br>
> /**<br>
> * clk_get - lookup and obtain a reference to a clock producer.<br>
> * @dev: device for clock "consumer"<br>
> @@ -83,12 +255,6 @@ unsigned long clk_get_rate(struct clk *clk);<br>
> */<br>
> void clk_put(struct clk *clk);<br>
><br>
> -<br>
> -/*<br>
> - * The remaining APIs are optional for machine class support.<br>
> - */<br>
> -<br>
> -<br>
> /**<br>
> * clk_round_rate - adjust a rate to the exact rate a clock can provide<br>
> * @clk: clock source<br>
</p>