diff options
Diffstat (limited to 'Documentation/clk.txt')
-rw-r--r-- | Documentation/clk.txt | 225 |
1 files changed, 125 insertions, 100 deletions
diff --git a/Documentation/clk.txt b/Documentation/clk.txt index 5c4bc4d01d0c..be909ed45970 100644 --- a/Documentation/clk.txt +++ b/Documentation/clk.txt @@ -1,12 +1,16 @@ - The Common Clk Framework - Mike Turquette <mturquette@ti.com> +======================== +The Common Clk Framework +======================== + +:Author: 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 +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 @@ -31,24 +35,26 @@ 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 +is defined in struct clk_foo and pointed to within struct clk_core. This allows for easy navigation between the two discrete halves of the common clock interface. - Part 2 - common data structures and api +Common data structures and api +============================== -Below is the common struct clk definition from -include/linux/clk-private.h, modified for brevity: +Below is the common struct clk_core definition from +drivers/clk/clk.c, modified for brevity:: - struct clk { + struct clk_core { 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; + struct module *owner; + struct clk_core *parent; + const char **parent_names; + struct clk_core **parents; + u8 num_parents; + u8 new_parent_index; ... }; @@ -56,16 +62,19 @@ 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: +Platforms and devices utilizing the common struct clk_core use the struct +clk_ops pointer in struct clk_core to perform the hardware-specific parts of +the operations defined in clk-provider.h:: struct clk_ops { int (*prepare)(struct clk_hw *hw); void (*unprepare)(struct clk_hw *hw); + int (*is_prepared)(struct clk_hw *hw); + void (*unprepare_unused)(struct clk_hw *hw); int (*enable)(struct clk_hw *hw); void (*disable)(struct clk_hw *hw); int (*is_enabled)(struct clk_hw *hw); + void (*disable_unused)(struct clk_hw *hw); unsigned long (*recalc_rate)(struct clk_hw *hw, unsigned long parent_rate); long (*round_rate)(struct clk_hw *hw, @@ -84,32 +93,35 @@ the operations defined in clk.h: u8 index); unsigned long (*recalc_accuracy)(struct clk_hw *hw, unsigned long parent_accuracy); + int (*get_phase)(struct clk_hw *hw); + int (*set_phase)(struct clk_hw *hw, int degrees); void (*init)(struct clk_hw *hw); int (*debug_init)(struct clk_hw *hw, struct dentry *dentry); }; - Part 3 - hardware clk implementations +Hardware clk implementations +============================ -The strength of the common struct clk comes from its .ops and .hw pointers +The strength of the common struct clk_core 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: +drivers/clk/clk-gate.c:: -struct clk_gate { - struct clk_hw hw; - void __iomem *reg; - u8 bit_idx; - ... -}; + 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. +framework code and struct clk_core. -Let's walk through enabling this clk from driver code: +Let's walk through enabling this clk from driver code:: struct clk *clk; clk = clk_get(NULL, "my_gateable_clk"); @@ -117,74 +129,71 @@ Let's walk through enabling this clk from driver code: clk_prepare(clk); clk_enable(clk); -The call graph for clk_enable is very simple: +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); + 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: +And the definition of clk_gate_set_bit:: -static void clk_gate_set_bit(struct clk_gate *gate) -{ - u32 reg; + 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); -} + reg = __raw_readl(gate->reg); + reg |= BIT(gate->bit_idx); + writel(reg, gate->reg); + } -Note that to_clk_gate is defined as: +Note that to_clk_gate is defined as:: -#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, clk) + #define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) This pattern of abstraction is used for every clock hardware representation. - Part 4 - supporting your own clk hardware +Supporting your own clk hardware +================================ -When implementing support for a new type of clock it only necessary to -include the following header: +When implementing support for a new type of clock it is 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. + #include <linux/clk-provider.h> To construct a clk hardware structure for your platform you must define -the following: +the following:: -struct clk_foo { - struct clk_hw hw; - ... hardware specific data goes here ... -}; + 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: +for your clk:: -struct clk_ops clk_foo_ops { - .enable = &clk_foo_enable; - .disable = &clk_foo_disable; -}; + struct clk_ops clk_foo_ops { + .enable = &clk_foo_enable; + .disable = &clk_foo_disable; + }; -Implement the above functions using container_of: +Implement the above functions using container_of:: -#define to_clk_foo(_hw) container_of(_hw, struct clk_foo, hw) + #define to_clk_foo(_hw) container_of(_hw, struct clk_foo, hw) -int clk_foo_enable(struct clk_hw *hw) -{ - struct clk_foo *foo; + int clk_foo_enable(struct clk_hw *hw) + { + struct clk_foo *foo; - foo = to_clk_foo(hw); + foo = to_clk_foo(hw); - ... perform magic on foo ... + ... perform magic on foo ... - return 0; -}; + return 0; + }; Below is a matrix detailing which clk_ops are mandatory based upon the hardware capabilities of that clock. A cell marked as "y" means @@ -192,41 +201,56 @@ mandatory, a cell marked as "n" implies that either including that callback is invalid or otherwise unnecessary. 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 [1] | | | | -.determine_rate | | y [1] | | | | -.set_rate | | y | | | | - | | | | | | -.set_parent | | | n | y | n | -.get_parent | | | n | y | n | - | | | | | | -.recalc_accuracy| | | | | | - | | | | | | -.init | | | | | | - ----------------------------------------------------------- -[1] either one of round_rate or determine_rate is required. +.. table:: 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 [1]_ | | | | + +----------------+------+-------------+---------------+-------------+------+ + |.determine_rate | | y [1]_ | | | | + +----------------+------+-------------+---------------+-------------+------+ + |.set_rate | | y | | | | + +----------------+------+-------------+---------------+-------------+------+ + +----------------+------+-------------+---------------+-------------+------+ + |.set_parent | | | n | y | n | + +----------------+------+-------------+---------------+-------------+------+ + |.get_parent | | | n | y | n | + +----------------+------+-------------+---------------+-------------+------+ + +----------------+------+-------------+---------------+-------------+------+ + |.recalc_accuracy| | | | | | + +----------------+------+-------------+---------------+-------------+------+ + +----------------+------+-------------+---------------+-------------+------+ + |.init | | | | | | + +----------------+------+-------------+---------------+-------------+------+ + +.. [1] either one of round_rate or determine_rate is required. 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: +with a call to:: -clk_register(...) + clk_register(...) -See the basic clock types in drivers/clk/clk-*.c for examples. +See the basic clock types in ``drivers/clk/clk-*.c`` for examples. - Part 5 - Disabling clock gating of unused clocks +Disabling clock gating of unused clocks +======================================= Sometimes during development it can be useful to be able to bypass the default disabling of unused clocks. For example, if drivers aren't enabling @@ -237,7 +261,8 @@ are sorted out. To bypass this disabling, include "clk_ignore_unused" in the bootargs to the kernel. - Part 6 - Locking +Locking +======= The common clock framework uses two global locks, the prepare lock and the enable lock. |