驱动开发硬核特训 · Day 24(下篇):深入理解 Linux 内核时钟子系统结构

Linux 内核学习(1) --- 时钟子系统 使用clk_hw结构向 CCF 框架注册一个时钟设备,返回一个struct clk结构,其中clk_hw结构中 包含了结构,结构包含对时钟操作的具体函数集合为了简化操作,CCF将clock设备抽象为六中不同的类型,并且做了相应的接口封装,比如,对于Gate类型的设备,直接使用等类型的函数就可以进行注册CCF 框架会为每个注册的都分配一个结构,其中包含了操作函数的结构体结构,本质就是关联到init_data中的clk_opsconsumer通过clk_get等函数 获取的struct clk。 阅读详情

一、前言

在上一章节中,我们详细探讨了 SoC 中时钟控制器的硬件组成和功能。本篇将聚焦于 Linux 内核中的时钟子系统,深入解析其架构、关键数据结构、驱动实现以及与设备树的关系,帮助您全面掌握时钟子系统的工作原理和开发要点。


二、Linux 内核时钟子系统概述

Linux 内核中的时钟子系统主要由 Common Clock Framework(CCF)组成,旨在为各种硬件平台提供统一的时钟管理接口。CCF 通过抽象不同类型的时钟,简化了时钟的注册、配置和使用流程,增强了内核的可移植性和可维护性。

CCF 的核心理念是构建一棵“时钟树”,从根节点的时钟源(如晶振、PLL)开始,经过分频器、复用器、门控器等中间节点,最终分发到各个外设模块。这种结构使得时钟的管理更加灵活和高效。


三、时钟子系统的核心组件

3.1 时钟提供者(Clock Provider)

时钟提供者是指那些生成和管理时钟信号的模块,如 PLL、分频器、复用器等。在内核中,时钟提供者通过注册相应的 clk_hw 结构体,将自身的时钟功能暴露给时钟框架。

每个时钟提供者需要实现一组 clk_ops 操作函数,用于控制时钟的启用、禁用、频率设置等。这些操作函数通过 clk_hw 结构体中的 init 成员与时钟框架关联。

3.2 时钟消费者(Clock Consumer)

时钟消费者是指那些使用时钟信号的模块,如 I2C、SPI、UART 等外设驱动。这些模块通过调用 clk_get、clk_prepare、clk_enable 等接口,从时钟框架中获取并启用所需的时钟。

时钟消费者无需关心底层时钟的具体实现,只需通过统一的接口进行操作,增强了驱动的可移植性。

3.3 时钟框架(Clock Framework)

时钟框架是连接时钟提供者和时钟消费者的桥梁,负责管理所有注册的时钟,维护时钟之间的父子关系,并提供统一的操作接口。时钟框架通过构建一棵时钟树,确保时钟信号的正确分发和管理。
在这里插入图片描述


四、关键数据结构解析

4.1 struct clk_hw

clk_hw 是时钟硬件的抽象结构体,代表一个具体的时钟实例。它包含指向 clk_core 的指针,以及初始化数据 init。clk_hw 是时钟提供者注册到时钟框架的主要接口。

struct clk_hw {
    struct clk_core *core;
    struct clk *clk;
    const struct clk_init_data *init;
};

4.2 struct clk_init_data

clk_init_data 包含时钟的初始化信息,如名称、操作函数、父时钟名称等。时钟提供者在注册时,需要填充该结构体,以供时钟框架使用。

struct clk_init_data {
    const char *name;
    const struct clk_ops *ops;
    const char * const *parent_names;
    const struct clk_parent_data *parent_data;
    const struct clk_hw **parent_hws;
    u8 num_parents;
    unsigned long flags;
};

4.3 struct clk_ops

clk_ops 定义了一组操作函数,用于控制时钟的启用、禁用、频率设置等。时钟提供者需要根据自身功能,实现相应的操作函数,并在 clk_init_data 中进行绑定。

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);
    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 (*set_rate)(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate);
    int (*set_parent)(struct clk_hw *hw, u8 index);
    u8 (*get_parent)(struct clk_hw *hw);
};

五、时钟驱动的实现流程

5.1 定义时钟硬件结构体

根据时钟的类型,定义相应的结构体,并包含 clk_hw 作为成员。例如,对于固定频率的时钟,可以定义如下结构体:

struct clk_fixed_rate {
    struct clk_hw hw;
    unsigned long fixed_rate;
};

5.2 实现 clk_ops 操作函数

根据时钟的功能,实现相应的操作函数,并填充 clk_ops 结构体。例如,对于固定频率的时钟,只需实现 recalc_rate 函数:

static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) {
    struct clk_fixed_rate *fixed = container_of(hw, struct clk_fixed_rate, hw);
    return fixed->fixed_rate;
}

static const struct clk_ops clk_fixed_rate_ops = {
    .recalc_rate = clk_fixed_rate_recalc_rate,
};

5.3 填充 clk_init_data 并注册时钟

在驱动的初始化函数中,填充 clk_init_data 结构体,并调用 clk_register 函数将时钟注册到时钟框架中:

struct clk_fixed_rate *fixed;
struct clk_init_data init;

fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);
fixed->fixed_rate = 24000000;

init.name = "fixed_clk";
init.ops = &clk_fixed_rate_ops;
init.flags = 0;
init.parent_names = NULL;
init.num_parents = 0;

fixed->hw.init = &init;

clk_register(NULL, &fixed->hw);

六、设备树与时钟子系统的集成

在设备树中,可以通过定义 clock-controller 节点,描述时钟提供者的属性和结构。时钟消费者可以通过 phandle 引用相应的时钟提供者,获取所需的时钟。

例如,定义一个固定频率的时钟提供者:

fixed_clk: fixed-clock {
    compatible = "fixed-clock";
    #clock-cells = <0>;
    clock-frequency = <24000000>;
};

时钟消费者可以通过以下方式引用该时钟:

uart0: serial@1000 {
    clocks = <&fixed_clk>;
    clock-names = "uart_clk";
};

内核在解析设备树时,会根据 compatible 属性加载相应的驱动,并完成时钟的注册和绑定。


七、时钟子系统的调试与验证

Linux 提供了多种方式来调试和验证时钟子系统的工作状态:

  • 通过 cat /sys/kernel/debug/clk/clk_summary 命令,可以查看当前系统中所有时钟的状态、频率和启用情况。

  • 使用 clk_get_rate、clk_set_rate 等接口,可以在驱动中动态获取和设置时钟频率。

  • 通过内核日志,可以观察时钟的注册、启用和禁用过程,便于定位问题。


八、总结

本文系统地介绍了 Linux 内核时钟子系统的架构、关键数据结构、驱动实现流程以及与设备树的集成方式。通过理解时钟提供者、时钟消费者和时钟框架之间的关系,掌握 clk_hw、clk_init_data 和 clk_ops 等核心结构体的使用方法,开发者可以更加高效地实现和调试时钟相关的驱动程序。

时钟子系统作为 Linux 内核中至关重要的一部分,其稳定性和准确性直接影响到整个系统的性能和可靠性。因此,深入理解和掌握时钟子系统的工作原理,对于驱动开发者来说具有重要意义。


【linux kernel】一文总结linux的clk框架 本文浅析linux的clk框架 阅读详情

相关推荐

每天一个优秀提示词学习收藏 - 文本去AI化(四)

宝子们,今天不藏私啦!我把这段时间四处搜罗、潜心钻研出来的文本去AI化Prompt 提示词大礼包双手奉上,这可都是能让你的 AI 创作水平原地起飞的干货!走过路过不要错过,赶紧码住,开启你的 AI 创作进阶之旅吧!

2445

Linux下的clk学习

先看某主板的时钟dts描述,如 1.1固定时钟 fixed-clock ext_26m: ext-26m { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <26000000>; clock-output-names = "ext_26m"; }; ext_6m5: ex...

Android开发 3570

Zynq7000双核裸机开发实战:如何安全实现共享内存与乒乓RAM设计

本文深入探讨了Zynq7000双核裸机开发中的共享内存与乒乓RAM设计,重点解析了核间通信的Cache一致性处理机制和硬件级实现方案。通过实战代码示例和性能优化技巧,帮助开发者解决双核运行中的访问冲突问题,提升嵌入式系统开发效率。

weixin_29191669的博客 375

Linux设备树(device tree)

设备树(device tree)机制是Linux内核从linux-3.x版本开始引进的一种机制,目的是解决内核源码的arch/arm目录下代码混乱的问题:随着ARM生态的快速发展,在内核源码的arch/arm目录下,存放着几十种arm芯片和几百个开发板相关的源文件,很多开发板和处理器的中断、寄存器等相关硬件资源都在这个目录下以.c或.h的文件格式定义。而对于内核来说,与这些硬件耦合,会导致内核代码混乱不堪,每个开发板上运行的内核镜像都必须单独编译配置,无法通用。什么时候Linux内核能像Windows镜像那样,无论你的电脑什么配置,一个Windows安装包,都可以直接下载安装运行呢?设备树机制,实现了Linux内核和硬件平台的解耦:每个硬件平台的硬件资源使用一个设备树文件(xxx.dts)来描述,而不是在arch/arm下以.c 或 .h 文件来定义。Linux内核是一个通用的内核,在启动过程中,在通过解析设备树中的硬件资源来初始化某个具体的平台。 引入设备树后,很多和内核驱动开发的工作也发生了变化:以往驱动工程师关注的头文件宏定义、寄存器定义,现在这些基本上不用关注,关注的重点则转向了如何根据硬件平台去配置和修改设备树文件。很多驱动的编程接口也发生了变化,开始慢慢使用device tree提供的编程接口去开发驱动。本期课程主要面向嵌入式开发人员,分享Linux下驱动开发所需要的设备树知识和必备技能

使用STC15F104W产生PWM脉冲

最近的小项目中使用到了STC15F104W产生PWM脉冲

yeats1989的专栏 1万+

uniapp+renderJS+google map开发安卓版APP非小程序

uniapp+renderJS+google map开发安卓版APP非小程序,google map小叉号不显示,google map自定义marker右上角的小叉号如何去掉,uniapp+google map不显示

renkai721的专栏 667

Linux驱动开发 --- CCF时钟框架

linux内核的CCF时钟框架可以分为三层,每一层的职责以及彼此的关系如下图所示。

weixin_43604927的博客 1477

基于ESP32的AI 古琴:基于音频指纹的民族乐器智能校准系统设计与实现

硬件选型兼顾实用性与低成本,接线简单易实现;基于 MFCC 的音频指纹算法,能有效识别古琴弦的音高特征;人机交互友好,新手可快速上手。

weixin_42300449的博客 306

i.MX8MPlus中的CLK子系统

芯片手册中的clk框架 CCM(Clock Control Module)框架图 外部时钟的输入源有24MHz,32.768KHz以及四个EXT CLK。这7个输入源都可以直接连接到CCM,但是PLL只能以24MHz,32.768KHz作为输入。从PLL和分频器出来的时钟也可以作为CCM的输入。每一个Slice在经过MUX模块后,由分频器产生我们需要的时钟频率,然后再输出给Gate模块,以便控制时钟的开关。 CLK ROOT相关寄存器 每一个Slice都有自己的index、偏移地址和时钟源配置寄存器CC

Muggle的博客 1949

Python图像处理之光斑分析

光斑是工程中经常出现的图像数据,其特点是目标明确,分布清晰。对光斑图像的分析,主要包括质心定位、目标截取以及半径拟合等。

微小冷的学习笔记 2856

把 SAP 配置当成一张地图:用 IMG 把实施、变更与治理串成一条清晰的路

摘要 SAP IMG(Implementation Guide)是SAP实施的核心导航体系,它将客户需求转化为系统配置,提供结构化路径和文档化支持。IMG不是简单的菜单树,而是包含业务落地路径、标准化配置活动和文档化知识的实施语言。通过三种视图(Reference、Enterprise、Project)解决不同管理问题,其中Project IMG尤其重要,可管理项目范围、分工和进度。实际工作中应通过SPRO事务码访问IMG,将探索与执行分开管理。案例显示,跨国企业通过Project IMG可有效控制组织架构

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 228

正点原子-Linux嵌入式开发学习-第二期06

A7裸机开发

m0_55093622的博客 890

(持续更新中!)详解【计算机类&面试真题】军队文职考试 ——第二期(真题+解析)| 网络协议的三个核心要素;交互式系统中的非剥夺策略;中断和陷入的区别;可变分区管理中的硬件机制;数据库系统的优点

本篇博客将讨论军队文职面试(计算机类)的几个关键问题。我们将介绍网络协议的核心要素(帮助你理解网络通信的基本原理)、交互式系统中的非剥夺策略(解释为何这是一个优秀的策略以及其对用户体验、系统稳定性和可预测性的影响)、中断和陷入的区别(从引起原因、处理机制、权限级别和应用等方面进行阐述)、可变分区管理的硬件机制以及数据库系统与文件系统的优点比较。通过阅读本文,您将深入了解这些话题,为面试准备和实际应用提供有价值的知识。

追光者♂:记录、分享、总结、提升,现象级专栏《Python从入门到人工智能》作者,无惧黑暗,坚信曙光 1705

Exynos4412的Linux5.4.174时钟驱动开发(五)——时钟设备树的修改方法

关于时钟有2种设备:时钟使用者(clock consumer)例如pwm、adc、串口,时钟提供者(clock provider)例如晶振、PLL。本文介绍了这2种设备的设备树写法。

weixin_42408707的博客 1224

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Linux子系统系列-时钟子系统

年前处理了一个涉及linux时钟子系统比较麻烦的问题,问题虽然解决了,但在过程中遇到很多不太清晰地的地方,今天一起整理一下 由于本人涉猎不广,不思进取,所总结东西大部分来源于网络,希望能早日迈过这个层次,多有些自己的东西,一些自己在技术方面的积极思考。 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 目录: 1,时间在Linux的地位 2,Linux如何管理时间 3,时钟子系统的实现 4,在Linux中如何计时 5,Linux出了一

smilingjames的专栏 5252

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Linux CLK框架了解

了解学习下Linux CLK大体使用框架

qq_44495904的博客 1179

一文搞懂 | Linux 时钟子系统

Clock 时钟就是 SoC 中的脉搏,由它来控制各个部件按各自的节奏跳动。比如,CPU主频设置,串口的波特率设置,I2S的采样率设置,I2C的速率设置等等。这些不同的clock设置,都需...

Peter的专栏 2605

clk子系统 - 代码分析

通过clk驱动框架可以看出,clk主要分core和hardware两层,而core层的主要函数是clk_register,它是把clk注册到系统中,而hardware层的注册函数因种类而异,不过最终都会统一调用clk_register来注册,本文只拿gate来举例;另外本文介绍下操作clk的主要API的过程 1.clk_register clk_register首先分配一个结构体c...

多媒体开发者 3028

linux设备树_时钟绑定

linux设备树_时钟绑定

l531798151的博客 1542

linux通用时钟框架(CCF)

linux 内核版本 v4.19嵌入式平台rv1109 , 文中代码出处。CCF背后的主要思想是统一和抽象分布在不同SoC时钟驱动程序中的类似代码。这种标准化的方法引入了时钟提供者和时钟消费者的概念:提供者是Linux内核驱动程序,它连接到框架并提供对硬件的访问,从而根据SoC数据表提供(使这些对消费者可用)时钟树(由于可以转储整个时钟树);消费者是通过公共API访问框架的Linux内核驱动程序或子系统;

kerwin的专栏 1570

Linux 内核中用于注册时钟硬件设备(Clock Hardware)的函数之一devm_clk_hw_register

Linux 内核中用于注册时钟硬件设备的函数之一devm_clk_hw_register

weixin_44740132的博客 683

【嵌入式Linux】i.MX6ULL 时钟树——理论分析

本文章结合了正点原子的**i.mx6u嵌入式Linux开发指南**和笔者的理解。 本文章应配合《【嵌入式Linux】i.MX6ULL 时钟树——代码梳理(基础时钟初始化)》使用。

Witheart 的博客。 1718

Linux下时钟框架实践---一款芯片的时钟树配置

关键词:时钟、PLL、Mux、Divider、Gate、clk_summary等。 时钟和电源是各种设备的基础设施,整个时钟框架可以抽象为几种基本的元器件:负责提供晶振 Linux内核提供了良好的CCF(Common Clock Framework),框架的两端一个是provider,一个是consumer。 provider指的是提供时钟模块,包括晶振、PLL、Mux、Divider、Ga...

weixin_30477293的博客 833

Linux学习笔记22-主频和时钟配置实验

1、32.768khz的晶振,供给RTC使用,其并不会参与整个系统的时钟里面去2、在6U的T16和T17 这两个I上接了一个24MHZ的晶振。

m0_52546976的博客 507

linux查看时钟树,RK3288 查看时钟树

主控端可以通过指令查看时钟树,enable_cnt为1,表示时钟已使能。#cat d/clk/clk_summarycat d/clk/clk_summaryclock enable_cnt prepare_cnt rate--------------------------------------------------------------...

weixin_29952383的博客 2105

【嵌入式Linux】i.MX6ULL 时钟树——代码梳理(基础时钟初始化)

本文章结合了正点原子的**i.mx6u嵌入式Linux开发指南**和笔者的理解。 本文章应配合《【嵌入式Linux】i.MX6ULL 时钟树——理论分析》使用。

Witheart 的博客。 1317
上一篇: 驱动开发硬核特训 · Day 24(上篇):走进Linux内核时钟子系统 —— 硬件基础全解析
下一篇: C++每日训练 Day 18:构建响应式表单与数据验证(初学者友好)
嵌入式孙老师
博客等级 码龄7年 5686粉丝 899原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值