Linux时钟子系统架构与驱动开发实践 ## 1. Linux时钟子系统架构解析 ### 1.1 核心组件构成 Linux时钟子系统采用CCF(Common Clock Framework)框架包含三个关键层级 - **Consumer层**提供标准API接口clk_get/clk_enable等 - **CCF核心层**通过clk_core结构体管理时钟拓扑 - **Provider层**实现硬件具体操作clk_hw/clk_ops ### 1.2 关键数据结构 c struct clk_hw { struct clk_core *core; const struct clk_init_data *init; }; struct clk_init_data { const char *name; const struct clk_ops *ops; // 硬件操作函数集 const char **parent_names; // 父时钟名称 u8 num_parents; };2. 时钟硬件类型分类2.1 固定频率时钟(Fixed Clock)典型应用晶振、PLL输出static const struct clk_ops fixed_clk_ops { .recalc_rate xx_pll_recalc_rate, };2.2 分频时钟(Factor Clock)实现要点必须实现rate相关操作需处理父时钟频率传递static const struct clk_ops factor_clk_ops { .recalc_rate xx_factor_recalc, .round_rate xx_factor_round, .set_rate xx_factor_set, };2.3 门控时钟(Gate Clock)关键操作static const struct clk_ops gate_clk_ops { .enable xx_gate_enable, .disable xx_gate_disable, };3. 设备树配置规范3.1 时钟节点定义clocks { osc24M: osc24M { compatible fixed-clock; #clock-cells 0; clock-frequency 24000000; }; pll0: pll0 { compatible vendor,fixed-clk; clocks osc24M; clock-frequency 100000000; }; };3.2 时钟消费者配置mmc0: mmc12345678 { compatible vendor,mmc; clocks pll0; clock-names mmc0; };4. 驱动开发实践4.1 时钟注册流程初始化clk_init_data结构实现clk_ops操作集调用clk_register注册添加OF providerstatic void __init of_clock_init(struct device_node *np) { struct clk_init_data init { .name pll0, .ops pll_ops, .parent_names parent_name, .num_parents 1, }; clk clk_register(NULL, hw); of_clk_add_provider(np, of_clk_src_simple_get, clk); }4.2 典型驱动实现4.2.1 PLL时钟驱动static unsigned long pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct pll_clock *pll to_pll_clock(hw); u32 val readl(pll-reg); return parent_rate * (val 0xFF); }4.2.2 分频时钟驱动static int factor_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct factor_clock *factor to_factor_clock(hw); u32 div parent_rate / rate; writel(div, factor-reg); return 0; }5. 时钟API使用规范5.1 基础操作流程struct clk *clk devm_clk_get(dev, mmc0); clk_prepare_enable(clk); clk_set_rate(clk, 50000000); unsigned long rate clk_get_rate(clk);5.2 错误处理模式if (IS_ERR(clk)) { dev_err(dev, Clock get failed: %ld\n, PTR_ERR(clk)); return PTR_ERR(clk); } ret clk_prepare_enable(clk); if (ret) { dev_err(dev, Clock enable failed: %d\n, ret); goto err_put_clk; }6. 调试与优化6.1 时钟树查看cat /sys/kernel/debug/clk/clk_summary6.2 频率调整验证pr_info(Current rate: %lu Hz\n, clk_get_rate(clk));6.3 电源管理集成static int suspend(struct device *dev) { struct driver_data *data dev_get_drvdata(dev); clk_disable(data-clk); return 0; }