Hi Mike,

On Thu, Sep 22, 2011 at 03:26:56PM -0700, Mike Turquette wrote:
> From: Jeremy Kerr <jeremy.k...@canonical.com>
> 
> We currently have ~21 definitions of struct clk in the ARM architecture,
> each defined on a per-platform basis. This makes it difficult to define
> platform- (or architecture-) independent clock sources without making
> assumptions about struct clk, and impossible to compile two
> platforms with different struct clks into a single image.
> 
> This change is an effort to unify struct clk where possible, by defining
> a common struct clk, and a set of clock operations. Different clock
> implementations can set their own operations, and have a standard
> interface for generic code. The callback interface is exposed to the
> kernel proper, while the clock implementations only need to be seen by
> the platform internals.
> 
> The interface is split into two halves:
> 
>  * struct clk, which is the generic-device-driver interface. This
>    provides a set of functions which drivers may use to request
>    enable/disable, query or manipulate in a hardware-independent manner.
> 
>  * struct clk_hw and struct clk_hw_ops, which is the hardware-specific
>    interface. Clock drivers implement the ops, which allow the core
>    clock code to implement the generic 'struct clk' API.
> 
> This allows us to share clock code among platforms, and makes it
> possible to dynamically create clock devices in platform-independent
> code.
> 
> Platforms can enable the generic struct clock through
> CONFIG_GENERIC_CLK. In this case, the clock infrastructure consists of a
> common, opaque struct clk, and a set of clock operations (defined per
> type of clock):
> 
>   struct clk_hw_ops {
>       int             (*prepare)(struct clk_hw *);
>       void            (*unprepare)(struct clk_hw *);
>       int             (*enable)(struct clk_hw *);
>       void            (*disable)(struct clk_hw *);
>       unsigned long   (*recalc_rate)(struct clk_hw *);
>       int             (*set_rate)(struct clk_hw *,
>                                       unsigned long, unsigned long *);
>       long            (*round_rate)(struct clk_hw *, unsigned long);
>       int             (*set_parent)(struct clk_hw *, struct clk *);
>       struct clk *    (*get_parent)(struct clk_hw *);
>   };
> 
> Platform clock code can register a clock through clk_register, passing a
> set of operations, and a pointer to hardware-specific data:
> 
>   struct clk_hw_foo {
>       struct clk_hw clk;
>       void __iomem *enable_reg;
>   };
> 
>   #define to_clk_foo(c) offsetof(c, clk_hw_foo, clk)
> 
>   static int clk_foo_enable(struct clk_hw *clk)
>   {
>       struct clk_foo *foo = to_clk_foo(clk);
>       raw_writeb(foo->enable_reg, 1);
>       return 0;
>   }
> 
>   struct clk_hw_ops clk_foo_ops = {
>       .enable = clk_foo_enable,
>   };
> 
> And in the platform initialisation code:
> 
>   struct clk_foo my_clk_foo;
> 
>   void init_clocks(void)
>   {
>       my_clk_foo.enable_reg = ioremap(...);
> 
>       clk_register(&clk_foo_ops, &my_clk_foo, NULL);
>   }
> 
> Changes from Thomas Gleixner <t...@linutronix.de>.
> 
> The common clock definitions are based on a development patch from Ben
> Herrenschmidt <b...@kernel.crashing.org>.
> 
> TODO:
> 
>  * We don't keep any internal reference to the clock topology at present.
> 
> Signed-off-by: Jeremy Kerr <jeremy.k...@canonical.com>
> Signed-off-by: Thomas Gleixner <t...@linutronix.de>
> Signed-off-by: Mark Brown <broo...@opensource.wolfsonmicro.com>
> Signed-off-by: Mike Turquette <mturque...@ti.com>
> ---
> Changes since v1:
> Create a dummy clk_unregister and prototype/document it and clk_register
> Constify struct clk_hw_ops
> Remove spinlock.h header, include kernel.h
> Use EOPNOTSUPP instead of ENOTSUPP
> Add might_sleep to clk_prepare/clk_unprepare stubs
> Properly init children hlist and child_node
> Whitespace and typo fixes
> 
>  drivers/clk/Kconfig  |    3 +
>  drivers/clk/Makefile |    1 +
>  drivers/clk/clk.c    |  232 
> ++++++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/clk/clkdev.c |    7 ++
>  include/linux/clk.h  |  140 +++++++++++++++++++++++++++---
>  5 files changed, 371 insertions(+), 12 deletions(-)
>  create mode 100644 drivers/clk/clk.c
> 
[...]
> +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);
> +     __clk_disable(clk->parent);
> +}
> +
> +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;
> +
> +     if (!clk)
> +             return 0;
> +
> +     if (WARN_ON(clk->prepare_count == 0))
> +             return -ESHUTDOWN;
> +
> +
> +     if (clk->enable_count == 0) {
> +             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;
> +}
Could you expose __clk_enable/__clk_disable? I find it hard to implement
clk group. clk group means, when a major clk enable/disable, it want a set
of other clks enable/disable accordingly.
> +
> +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);
> +
[...]

Thanks
Richard 


_______________________________________________
linaro-dev mailing list
linaro-dev@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/linaro-dev

Reply via email to