当前位置: 首页 > 工具软件 > Clock View > 使用案例 >

linux 电源管理 --- clock

宗安翔
2023-12-01

一、时钟的概念

时钟是以固定频率传输的信号发生器。

二、为什么要使用时钟呢?

因为在数据传输过程中,只有对时序进行严格的定义和要求,才能保证数据在传输的过程中不出差错,而在此期间时钟信号充当了这一时序的基准。我们可以用它来确认其他信号的宽度,也用它来保证收发数据的同步。
还要看外设是挂在什么总线上,比如AHB APB AXI…不同的外设可能挂在不同的总线上,基准时钟就会不一样。

三、clock相关器件

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

四、作为consumer,怎么使用clock

1、dts

(1)配置dts

作为clock consumer,需要owner自己根据需求选择时钟配置

device:sgo_device {
	clocks = <&sgo_clk 8>,
        	 <&g12_pll 5>,
         	 <&ext_26m>;
	clock-names = "sgo_core", "sgo_core_source",
				  "sgo_core_default";
};

(2)解释

clocks 解释:该属性是一个数组,每一个entry对应clock consumer设备使用的clock source(可能不止一个哦)。
clocks后面的<>括起来的3个参数,代表3个clock source,真正使用的时候可能是其中一个。sgo_clk 8:代表使用sgo_clk的输出8。
clock-names代表时钟对应的名字,可以用devm_clk_get通过name得到clock source。

而clock source是由phandle和clock specifier这2个参数来描述。phandle指向一个clock provider的device node,如果该provider的#clock-cells等于0,那么说明该provider就一个output,那么就不需要clock specifier来进一步描述。如果该provider的#clock-cells不等于0,那么clock specifier必须提供,以便指明本设备到底使用provider输出时钟源的哪一路。

clock provider即编写clock驱动的人会提供如下dts。
固定时钟 fixed-clock

ext_26m: ext-26m {//---该主板有一个外接的26M晶振,ext_26m即外部的26M晶振
	compatible = "fixed-clock";
	#clock-cells = <0>; //-----------0表示只有1个输出,1表示有多余1个输出
	clock-frequency = <26000000>;
	clock-output-names = "ext-26m"; //本时钟的输出名称,在consumer时钟中可以使用此名称来获得该时钟的struct clk结构体
};
sgo_clk: clock-controller@20000000 {//时钟name是sgo_clk
	compatible = "hahaha-sgo-clk";
	reg = <0 0x20000000 0 0x1000>;
	clocks = <&ext_26m>; //-----------------父时钟是ext_26m, sgo_clk这个时钟来源于ext_26m
	#clock-cells = <1>; //------------------表示有多个输出
};
g12_pll: g12-pll { //-----------------从aon_clk分出来的,aon_clk又是从ext_26m分出来的
	compatible = "hahaha-g12-pll";
	reg = <0 0x31000000 0 0x3000>; /* 0x32414000 */
	clocks = <&aon_clk 2>;//g12_pll取自aon_clk的输出2
	#clock-cells = <1>;
};
aon_clk: clock-controller@30000000 {
	compatible = "hahaha-aonapb-clk";
	reg = <0 0x30000000 0 0x1000>;
	clocks = <&ext_26m>;//aon_clk来源于ext_26m
	#clock-cells = <1>;//代表aon_clk有多个输出
};

2、相关函数

(1)、clock driver在系统启动时初始化完毕,如若consumer需要访问某个clock时,只要获取他对应的struct clk结构就行。
如何获取呢?可以使用 devm_clk_get
(2)、上下电的时候,可能会有不同的需求,所以可以通过调用 clk_set_parent,来设置clock
clk是由parent分出来的。那么如果parent关闭了,当前clk也就没有了。

举个例子:sgo作为外设
上电:配置上电相关寄存器之后,clk_set_parent(drv->sgo_core_clk, drv->sgo_core_parent);
这里就算cpu下电了,sgo也要能使用,将sgo core这个时钟继承sgo_core_parent(ext_26->aon->g12_pll)
下电:先clk_set_parent(drv->sgo_core_clk, drv->sgo_core_default);再配下电相关寄存器。

五、clock的选择

有一个晶振 26m,可以进行倍频,分频,hz数为26M,T=1/26M,1/26M就会产生一个波,就是一个指令…所以HZ数越高,速度就越快。
如何选择用多大的HZ?
(1)比如说i2c协议,他内部有个限制,速度过快或过慢,对解析都有问题…。
(2)比如说外设,cpu下电的时候,我们要求外设还能工作,看哪个clock能满足这个条件,就选择哪个。

疑惑???
为什么只调用了devm_clk_get clk_set_parent(上下电设置的parent也不同), 不用调用enable prepare 这些接口?

六、参考

(1)http://www.wowotech.net/pm_subsystem/clk_overview.html
(2)时钟概念:https://wenku.baidu.com/view/ef648efc915f804d2a16c17e.html

 类似资料: