关键词:时钟、PLL、Mux、Divider、Gate、clk_summary等。
时钟和电源是各种设备的基础设施,整个时钟框架可以抽象为几种基本的元器件:负责提供晶振
Linux内核提供了良好的CCF(Common Clock Framework),框架的两端一个是provider,一个是consumer。
provider指的是提供时钟模块,包括晶振、PLL、Mux、Divider、Gate等,consumer指的是使用这些时钟的模块。
1. Linux时钟框架基础
相关文档对时钟框架做了详细的介绍:《Linux common clock framework(1)_概述》、《Linux common clock framework(2)_clock provider》、《Linux common clock framework(3)_实现逻辑分析》以及《Common Clock Framework系统结构》。
这里简单罗列一下相关知识。
1.1 编写时钟provider驱动
provider包含基本硬件元素:Oscillator/Crystal-提供时钟晶振、PLL-倍频、Mux-多路选择、Divider-分频器、Gate-控制开关,还有Fixed-Divider-固定分频器。
这些硬件都可以抽象成一种类型的时钟,所有类型的时钟都可以通过struct clk_hw描述。
struct clk_hw { struct clk_core *core; struct clk *clk; const struct clk_init_data *init; }; 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; unsigned long rate; unsigned long req_rate; unsigned long new_rate; struct clk_core *new_parent; struct clk_core *new_child; unsigned long flags; bool orphan; unsigned int enable_count; unsigned int prepare_count; unsigned long min_rate; unsigned long max_rate; unsigned long accuracy; int phase; struct hlist_head children; struct hlist_node child_node; struct hlist_head clks; unsigned int notifier_count; #ifdef CONFIG_DEBUG_FS struct dentry *dentry; struct hlist_node debug_node; #endif struct kref ref; }; struct clk_init_data { const char *name; const struct clk_ops *ops; const char * const *parent_names; u8 num_parents; unsigned long flags; };
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)(