linux下common clock framework的使用

Linux内核Common Clock Framework架构与实践 时钟管理是嵌入式Linux系统稳定运行的基础支撑技术,其核心在于实现硬件时钟资源的抽象化、标准化与可移植性。基于分层设计原理,CCF(Common Clock Framework)通过Consumer-Provider解耦模型,将外设驱动与底层SoC时钟控制器隔离,显著提升驱动复用率与平台适配效率。该框架的技术价值体现在统一API接口、动态频率调节能力及精细化功耗控制等方面,广泛应用于ARM SoC的MMC、I2C、UART等外设驱动开发中。本文深入解析CCF三层架构、关键数据结构(如struct clk_ 阅读详情

转自:http://www.wowotech.net/pm_subsystem/clk_overview.html

1. 前言

common clock framework是用来管理系统clock资源的子系统,根据职能,可分为三个部分:

1)向其它driver提供操作clocks的通用API。

2)实现clock控制的通用逻辑,这部分和硬件无关。

3)将和硬件相关的clock控制逻辑封装成操作函数集,交由底层的platform开发者实现,由通用逻辑调用。

因此,蜗蜗会将clock framework的分析文章分为3篇:

第一篇为概述和通用API的使用说明,面向的读者是使用clock的driver开发者,目的是掌握怎么使用clock framework(就是本文);

第二篇为底层操作函数集的解析和使用说明,面向的读者是platform clock driver的开发者,目的是掌握怎么借助clock framework管理系统的时钟资源;

第三篇为clock framework的内部逻辑解析,面向的读者是linux kernel爱好者,目的是理解怎么实现clock framework。

注1:任何framework的职能分类都是如此,因此都可以按照这个模式分析。

2. 概述

如今,可运行Linux的主流处理器平台,都有非常复杂的clock tree,我们随便拿一个处理器的spec,查看clock相关的章节,一定会有一个非常庞大和复杂的树状图,这个图由clock相关的器件,以及这些器件输出的clock组成。下图是一个示例:

clock

clock相关的器件包括:用于产生clock的Oscillator(有源振荡器,也称作谐振荡器)或者Crystal(无源振荡器,也称晶振);用于倍频的PLL(锁相环,Phase Locked Loop);用于分频的divider;用于多路选择的Mux;用于clock enable控制的与门;使用clock的硬件模块(可称作consumer);等等。

common clock framework的管理对象,就是上图蓝色字体描述的clock(在软件中用struct clk抽象,以后就简称clk),主要内容包括(不需要所有clk都支持):

1)enable/disable clk。

2)设置clk的频率。

3)选择clk的parent,例如hw3_clk可以选择osc_clk、pll2_clk或者pll3_clk作为输入源。

3. common clock framework提供的通用API

管理clock的最终目的,是让device driver可以方便的使用,这些是通过include/linux/clk.h中的通用API实现的,如下:

1)struct clk结构

一个系统的clock tree是固定的,因此clock的数目和用途也是固定的。假设上面图片所描述的是一个系统,它的clock包括osc_clk、pll1_clk、pll2_clk、pll3_clk、hw1_clk、hw2_clk和hw3_clk。我们完全可以通过名字,抽象这7个clock,进行开/关、rate调整等操作。但这样做有一个缺点:不能很好的处理clock之间的级联关系,如hw2_clk和hw3_clk都关闭后,pll2_clk才能关闭。因此就引入struct clk结构,以链表的形式维护这种关系。

同样的道理,系统的struct clk,也是固定的,由clock driver在系统启动时初始化完毕,需要访问某个clock时,只要获取它对应的struct clk结构即可。怎么获取呢?可以通过名字索引啊!很长一段时间内,kernel及driver就是使用这种方式管理和使用clock的。

最后,设备(由struct device表示)对应的clock(由struct clk表示)也是固定的啊,可不可以找到设备就能找到clock?可以,不过需要借助device tree。

注2:对使用者(device driver)来说,struct clk只是访问clock的一个句柄,不用关心它内部的具体形态。

2)clock获取有关的API

device driver在操作设备的clock之前,需要先获取和该clock关联的struct clk指针,获取的接口如下:

   1: struct clk *clk_get(struct device *dev, const char *id);
   2: struct clk *devm_clk_get(struct device *dev, const char *id);
   3: void clk_put(struct clk *clk);
   4: void devm_clk_put(struct device *dev, struct clk *clk);
   5: struct clk *clk_get_sys(const char *dev_id, const char *con_id);
   6:  
   7: struct clk *of_clk_get(struct device_node *np, int index);
   8: struct clk *of_clk_get_by_name(struct device_node *np, const char *name);
   9: struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec);

a)clk_get,以device指针或者id字符串(可以看作name)为参数,查找clock。

        a1)dev和id的任意一个可以为空。如果id为空,则必须有device tree的支持才能获得device对应的clk; 
        a2)根据具体的平台实现,id可以是一个简单的名称,也可以 是一个预先定义的、唯一的标识(一般在平台提供的头文件中定义,如mach/clk.h); 
        a3)
不可以在中断上下文调用。

b)devm_clk_get,和clk_get一样,只是使用了device resource management,可以自动释放。

c)clk_put、devm_clk_put,get的反向操作,一般和对应的get API成对调用。

d)clk_get_sys,类似clk_get,不过使用device的name替代device结构。

e)of_clk_get、of_clk_get_by_name、of_clk_get_from_provider,device tree相关的接口,直接从相应的DTS node中,以index、name等为索引,获取clk,后面会详细说明。

3)clock控制有关的API

   1: int clk_prepare(struct clk *clk)
   2: void clk_unprepare(struct clk *clk)
   3:  
   4: static inline int clk_enable(struct clk *clk)
   5: static inline void clk_disable(struct clk *clk)
   6:  
   7: static inline unsigned long clk_get_rate(struct clk *clk)
   8: static inline int clk_set_rate(struct clk *clk, unsigned long rate)
   9: static inline long clk_round_rate(struct clk *clk, unsigned long rate)
  10:  
  11: static inline int clk_set_parent(struct clk *clk, struct clk *parent)
  12: static inline struct clk *clk_get_parent(struct clk *clk)
  13:  
  14: static inline int clk_prepare_enable(struct clk *clk)
  15: static inline void clk_disable_unprepare(struct clk *clk)

a)clk_enable/clk_disable,启动/停止clock。不会睡眠。

b)clk_prepare/clk_unprepare,启动clock前的准备工作/停止clock后的善后工作。可能会睡眠。

c)clk_get_rate/clk_set_rate/clk_round_rate,clock频率的获取和设置,其中clk_set_rate可能会不成功(例如没有对应的分频比),此时会返回错误。如果要确保设置成功,则需要先调用clk_round_rate接口,得到和需要设置的rate比较接近的那个值。

d)获取/选择clock的parent clock。

e)clk_prepare_enable,将clk_prepare和clk_enable组合起来,一起调用。clk_disable_unprepare,将clk_disable和clk_unprepare组合起来,一起调用。

注2:prepare/unprepare,enable/disable的说明。

这两套API的本质,是把clock的启动/停止分为atomic和non-atomic两个阶段,以方便实现和调用。因此上面所说的“不会睡眠/可能会睡眠”,有两个角度的含义:一是告诉底层的clock driver,请把可能引起睡眠的操作,放到prepare/unprepare中实现,一定不能放到enable/disable中;二是提醒上层使用clock的driver,调用prepare/unprepare接口时可能会睡眠哦,千万不能在atomic上下文(例如中断处理中)调用哦,而调用enable/disable接口则可放心。

另外,clock的开关为什么需要睡眠呢?这里举个例子,例如enable PLL clk,在启动PLL后,需要等待它稳定。而PLL的稳定时间是很长的,这段时间要把CPU交出(进程睡眠),不然就会浪费CPU。

最后,为什么会有合在一起的clk_prepare_enable/clk_disable_unprepare接口呢?如果调用者能确保是在non-atomic上下文中调用,就可以顺序调用prepare/enable、disable/unprepared,为了简单,framework就帮忙封装了这两个接口。

4)其它接口

   1: int clk_notifier_register(struct clk *clk, struct notifier_block *nb);
   2: int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);

这两个notify接口,用于注册/注销 clock rate改变的通知。例如某个driver关心某个clock,期望这个clock的rate改变时,通知到自己,就可以注册一个notify。后面会举个例子详细说明。

   1: int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
   2:                         struct device *dev);

这是一个非主流接口,用于给某个clk起个别名。无论出于何种原因,尽量不要它,保持代码的简洁,是最高原则!

4. 通用API的使用说明

结合一个例子(摘录自“Documentation/devicetree/bindings/clock/clock-bindings.txt”),说明driver怎么使用clock通用API。

1)首先,在DTS(device tree source)中,指定device需要使用的clock,如下:

   1: /* DTS */
   2: device {
   3:     clocks = <&osc 1>, <&ref 0>;
   4:     clock-names = "baud", "register";
   5: };

该DTS的含义是:

device需要使用两个clock,“baud”和“regitser”,由clock-names关键字指定;

baud取自“osc”的输出1,register取自“ref”的输出0,由clocks关键字指定。

那么问题来了,clocks关键字中,<&osc 1>样式的字段是怎么来的?是由clock的provider,也就是底层clock driver规定的(具体会在下一篇文章讲述)。所以使用clock时,一定要找clock driver拿相关的信息(一般会放在“Documentation/devicetree/bindings/clock/”目录下)。

2)系统启动后,device tree会解析clock有关的关键字,并将解析后的信息放在platform_device相关的字段中。

3)具体的driver可以在probe时,以clock的名称(不提供也行)为参数,调用clk get接口,获取clock的句柄,然后利用该句柄,可直接进行enable、set rate等操作,如下:

   1: /* driver */
   2: int xxx_probe(struct platform_device *pdev)
   3: {
   4:         struct clk *baud_clk;
   5:         int ret; 
   6:  
   7:         baud_clk = devm_clk_get(&pdev->dev, “baud”);
   8:         if (IS_ERR(clk)) {
   9:                 …
  10:         } 
  11:  
  12:         ret = clk_prepare_enable(baud_clk);
  13:         if (ret) {
  14:                 …
  15:         } 
  16: }


从零开始之驱动发开、linux驱动(三十七、linux中common clock framework[2]_provider) 因为设备树这里还没学习,所以这一节属于provider章节的完全由蜗窝大神的文章来看。我在暂时只分析一些我知道的,同时对设备树这部分的原理和知识也也会尽快学习,补充这篇文章。 http://www.wowotech.net/pm_subsystem/clock_provider.html   下面就列出这几种时钟的描述 固定速率 比如晶振 门时钟 和... 阅读详情

相关推荐

从零开始之驱动发开、linux驱动(三十六、linux中common clock framework[1]_consoumer)

部分内容来自下面几位博主的文章,如有侵权,联系我删除。 http://www.wowotech.net/pm_subsystem/clk_overview.html https://blog.youkuaiyun.com/cc289123557/article/details/80098586   时钟管理模块是linux系统为统一管理各硬件的时钟而实现管理框架,负责所有模块的时钟调节和电源管理。时钟...

To_run_away的博客 2421

Linux common clock framework(1)_概述

1. 前言 common clock framework是用来管理系统clock资源的子系统,根据职能,可分为三个部分: 1)向其它driver提供操作clocks的通用API。 2)实现clock控制的通用逻辑,这部分和硬件无关。 3)将和硬件相关的clock控制逻辑封装成操作函数集,交由底层的platform开发者实现,由通用逻辑调用。 因此,蜗蜗会将clock framework的分析文章分为3篇: 第一篇为概述和通用API的使用说明,面向的读者是使用clock的driver开发者,目的是

乐于分享 776

手把手教你用Proteus仿真51单片机抢答器:倒计时+蜂鸣器报警完整项目

本文详细介绍了使用Proteus软件仿真51单片机智能抢答器的完整项目流程。通过系统架构设计、核心元件选型(如74LS30用于按键中断编码),结合状态机编程,实现了带可调倒计时、数码管显示和蜂鸣器报警的八路抢答器功能。项目涵盖了从原理图绘制到代码调试的全过程,是学习嵌入式系统开发的绝佳实践。

tcp8optimizer的博客 263

Linux common clock framework(3)_实现逻辑分析

和fixed rate类似,不再一一说明。

weixin_41028159的博客 610

ESP32-S3驱动PCA9685模块:I2C扩展16路舵机控制实战指南

本文提供了ESP32-S3通过I2C总线驱动PCA9685模块扩展16路PWM输出的完整实战指南。详细解析了PCA9685模块原理、硬件连接、I2C地址配置,并给出了核心驱动代码与角度控制函数,帮助开发者解决微控制器PWM引脚不足的问题,轻松实现多路舵机控制。

weixin_32005771的博客 523

PD虚拟机网络初始化失败的权限修复指南

本文针对Parallels Desktop虚拟机常见的“网络初始化失败”问题,提供了详细的权限修复指南。通过分析问题根源,指导用户安全备份并修改关键的`network.desktop.xml`和`dispatcher.desktop.xml`配置文件,以恢复PD虚拟机的网络连接。文章还包含了修复后的验证步骤及预防措施,帮助用户彻底解决并避免此类权限问题。

qqq44的博客 851

linux时钟框架

linux时钟框架

wujihong905的博客 1396

MATLAB实战:手把手教你搭建构网逆变器同步稳定性仿真模型(附避坑指南)

本文详细介绍了如何在MATLAB/Simulink平台上搭建构网逆变器同步稳定性仿真模型,涵盖从基础模块配置到虚拟同步机控制实现的完整流程。针对电力电子工程师常见的控制参数整定困难、仿真结果偏差等问题,提供了LCL滤波器谐振抑制、虚拟惯量优化等关键技术解决方案,并附有避坑指南和工程实践技巧,助力研究者高效完成仿真建模。

weixin_29051193的博客 297

linux clock头文件,Linux common clock framework(1)_概述

Linux common clock framework(1)_概述作者:wowo 发布于:2014-10-20 23:06分类:电源管理子系统1. 前言common clock framework是用来管理系统clock资源的子系统,根据职能,可分为三个部分:1)向其它driver提供操作clocks的通用API。2)实现clock控制的通用逻辑,这部分和硬件无关。3)将和硬件相关的clock控...

weixin_39756336的博客 419

2026年北京君正数字IC笔试试卷带答案

本文摘要:该文档是一份数字IC设计相关的考试试题,包含单选题、多选题、波形分析题和代码设计题。内容涵盖时序约束、半导体工艺、状态机设计、逻辑综合、异步FIFO设计等知识点。试题解析详细,重点考察数字电路基础、时序分析和Verilog代码实现能力。典型题目包括多周期路径设置、Moore/Mealy状态机区别、同步复位与异步复位特性、RISC-V架构特点等,并提供了异步FIFO的Verilog实现参考代码。(149字)

Open 114

CUDA&PCL 点云体素下采样

CUDA&PCL 点云体素下采样

dayuhaitang1的博客 1268

Linux common clock framework(2)_clock provider

我们在上面提到了clock provider的两种DTS定义方式,哪一种好呢?从规范化、条理性的角度,毫无疑问方式2是好的,它真正理解了Device Tree的精髓,并细致的执行。且可以利用很多clock framework的标准实现(后面会讲)。而方式1的优点是,DTS容易写,相应的clock driver也较为直观,只是注册一个一个clock provider即可,没有什么逻辑可言。换句话说,方式1比较懒。后面的API描述,蜗蜗会着重从方式2的角度,因为这样才能体会到软件设计中的美学。

weixin_41028159的博客 281

15张图详解三方支付:总架构、5大核心业务处理流程、备付金管理

用户可以将银行卡与零钱账户绑定,建立银行结算账户与支付账户的连接,然后将银行账户资金充值到零钱账户中,或将零钱账号中的余额提现至绑定的银行卡。因此,用户在A支付机构的零钱一般只能支付给A支付机构的商户,如支付宝的零钱不能支付给微信的商户。这五大业务的协同运作,使得第三方支付机构这一庞大的支付服务平台能够为市场提供卓越的支付能力。到了结算时间,网联会向备付金集中存管账户提交结算指令,在第三方支付机构备付金集中存管账户内完成最终的结算,并将结算结果及额度变动情况通知给第三方支付机构,具体流程如图13所示。

银行信息系统应用架构详解 1044

Exynos4412的Linux时钟驱动开发(三)——Common Clock Framework(CCF)简介

介绍CCF的三大部分:CCF core、设备树和驱动。

weixin_42408707的博客 1128

Android 10.0 SystemUI 屏蔽状态栏消息推送弹出的悬浮通知

在状态栏中,有一些通知类似 消息推送 弹出的 悬浮通知,弹出30秒之后会消失掉 要想屏蔽掉这些通知,首选知道这些通知是怎么产生的 通知类型 NotificationContentInflater.java 详细的介绍各种通知的类型 frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java /** * The defau

安卓兼职framework和app工程师的博客 1542

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Linux common clock framework(2)_概述

1. 前言 本文接上篇文章,从clock driver的角度,分析怎么借助common clock framework管理系统的时钟资源。换句话说,就是怎么编写一个clock driver。 由于kernel称clock driver为clock provider(相应的,clock的使用者为clock consumer),因此本文遵循这个规则,统一以clock provider命名。

michaelcao1980的专栏 653

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

上一篇: linux下uart应用编程
下一篇: UML简介
EmSoftEn
博客等级 码龄12年 40粉丝 63原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值