Common Clock Framework
Common Clock Framework
The clock struct structure. Here’s how clk, clk_core, clk_hw, clk_ops are related to each other:
clk
- clk_core *core
- char *name
- clk_ops *ops
- (pointers to functions)
- clk_hw *hw
- clk_core *core (points back to clk_core)
- clk *clk (points back to clk)
- device *dev
- *dev_id
- *con_id
struct clk in clk.c
Parent of clk_core Pointers to clk_node in an hlist Points to struct device (differnet from hw?)
struct clk {
struct clk_core *core;
struct device *dev;
const char *dev_id;
const char *con_id;
unsigned long min_rate;
unsigned long max_rate;
unsigned int exclusive_count;
struct hlist_node clks_node;
};
struct clk_core in clk.c
Most of the clk details Has OF node and parent/child nodes Settings like rate, enable count/accuracy/phase Pointers to debug_node hlist, gets added there.
struct clk_core {
const char *name;
const struct clk_ops *ops;
struct clk_hw *hw;
struct module *owner;
struct clk_core *parent;
const char **parent_names;
struct clk_core **parents;
u8 num_parents;
u8 new_parent_index;
...
}
struct clk_ops 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,
unsigned long rate,
unsigned long *parent_rate);
int (*determine_rate)(struct clk_hw *hw,
struct clk_rate_request *req);
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 rate,
unsigned long parent_rate);
int (*set_rate_and_parent)(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate,
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);
void (*debug_init)(struct clk_hw *hw,
struct dentry *dentry);
};
struct clk_hw in clk-provider.h
Kernel comments:
- 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
Basically link back from driver specific clocks back to the generic clk structure
struct clk_hw {
struct clk_core *core;
struct clk *clk;
const struct clk_init_data *init;
};
Driver-specific clk structures include this
struct clk_main_osc {
struct clk_hw hw;
struct regmap *regmap;
};
...
struct clk_sam9260_slow {
struct clk_hw hw;
struct regmap *regmap;
};
Driver code implemets these ops functions with driver-specific names. For example:
static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw)
A clk_ops “overlay” struct specifies the functions that are implemeted:
static const struct clk_ops sam9260_slow_ops = {
.get_parent = clk_sam9260_slow_get_parent,
};
A register function creates a clk_init_data struct and feeds it to clk_hw_register()
at91_clk_register_sam9260_slow(...) {
struct clk_init_data init;
...
init.name = name;
init.ops = &sam9260_slow_ops
slowck->hw.init = &init;
slowck->regmap = regmap;
...
ret = clk_hw_register(NULL, &slowck->hw);
}
clk_hw_register() wraps clk_register() which builds a struct clk_core
__clk_create_clk(hw, NULL, NULL);
__clk_core_init(core);
__clk_free_clk(hw->clk);
__clk_create_clk()
creates struct clk from clk_hw, dev_id con_id
But, it is called with NULL dev_id and con_id
Finally, a macro links of_nodes to this clock type
CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow",
of_at91sam9260_clk_slow_setup);
The of_at91sam9260_clk_slow_setup is a wrapper around at91_clk_register_sam9260_slow