123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- 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.
|