概述
时钟框架:
方式1:
将系统所有的clock,抽象为一个虚拟的设备,用一个DTS node表示。这个虚拟的设备称作clock controller
1: /* arch/arm/boot/dts/exynos4210.dtsi */
2: clock: clock-controller@0x10030000 {
3: compatible = “samsung,exynos4210-clock”;
4: reg = <0x10030000 0x20000>;
5: #clock-cells = <1>;
6: };
1: /* arch/arm/boot/dts/exynos4210.dtsi */
2: mct@10050000 {
3: compatible = “samsung,exynos4210-mct”;
4: …
5: clocks = <&clock 3>, <&clock 344>;
6: clock-names = “fin_pll”, “mct”;
7: …
8: };
1)clocks,指明该设备的clock列表,clk_get时,会以它为关键字,去device_node中搜索
2)更好的做法是,将系统所有clock的ID,定义在一个头文件中,而DTS可以包含这个头文件,
如“clocks = <&clock CLK_SPI0>”;
3)clock-names,为clocks指定的那些clock分配一些易于使用的名字,driver可以直接以名字为参数,
get clock的句柄
4),如果clock provider的“#clock-cells”为0,可直接引用该clock provider的名字
方式2:
见下文
同样的道理,系统的struct clk,也是固定的,由clock driver在系统启动时初始化完毕,
需要访问某个clock时,只要获取它对应的struct clk结构即可。
这两套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就帮忙封装了这两个接口。
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: /* 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关键字指定。
每一个可输出clock的器件,如“Linux common clock framework(1)_概述”所提及的Oscillator、PLL、Mux等等,
都是一个设备,用一个DTS node表示。每一个器件,即是clock provider,也是clock consumer(根节点除外,如OSC),因为它需要接受clock输入,经过处理后,输出clock。
13: dummy: dummy {
14: #clock-cells = <0>;
15: compatible = “fixed-clock”;
16: clock-frequency = <0>;
17: };
18:
19: osc24M: osc24M@01c20050 {
20: #clock-cells = <0>;
21: compatible = “allwinner,sun4i-osc-clk”;
22: reg = <0x01c20050 0x4>;
23: clock-frequency = <24000000>;
24: };
25:
26: osc32k: osc32k {
27: #clock-cells = <0>;
28: compatible = “fixed-clock”;
29: clock-frequency = <32768>;
30: };
31:
32: pll1: pll1@01c20000 {
33: #clock-cells = <0>;
34: compatible = “allwinner,sun4i-pll1-clk”;
35: reg = <0x01c20000 0x4>;
36: clocks = <&osc24M>;
37: };
1) osc24M和osc32k是两个root clock,因此只做clock provider功能。它们的cells均为0
2)“clock-frequency”自定义关键字,这样在板子使用的OSC频率改变时,如变为12M,不需要重新编译代码,
只需更改DTS的频率即可
40: cpu: cpu@01c20054 {
41: #clock-cells = <0>;
42: compatible = “allwinner,sun4i-cpu-clk”;
43: reg = <0x01c20054 0x4>;
44: clocks = <&osc32k>, <&osc24M>, <&pll1>, <&dummy>;
45: };
47: axi: axi@01c20054 {
48: #clock-cells = <0>;
49: compatible = “allwinner,sun4i-axi-clk”;
50: reg = <0x01c20054 0x4>;
51: clocks = <&cpu>;
52: };
62: ahb: ahb@01c20054 {
63: #clock-cells = <0>;
64: compatible = “allwinner,sun4i-ahb-clk”;
65: reg = <0x01c20054 0x4>;
66: clocks = <&axi>;
67: };
69: ahb_gates: ahb_gates@01c20060 {
70: #clock-cells = <1>;
71: compatible = “allwinner,sun4i-ahb-gates-clk”;
72: reg = <0x01c20060 0x8>;
73: clocks = <&ahb>;
74: clock-output-names = “ahb_usb0”, “ahb_ehci0”,
75: “ahb_ohci0”, “ahb_ehci1”, “ahb_ohci1”, “ahb_ss”,
76: “ahb_dma”, “ahb_bist”, “ahb_mmc0”, “ahb_mmc1”,
77: “ahb_mmc2”, “ahb_mmc3”, “ahb_ms”, “ahb_nand”,
78: “ahb_sdram”, “ahb_ace”, “ahb_emac”, “ahb_ts”,
79: “ahb_spi0”, “ahb_spi1”, “ahb_spi2”, “ahb_spi3”,
80: “ahb_pata”, “ahb_sata”, “ahb_gps”, “ahb_ve”,
81: “ahb_tvd”, “ahb_tve0”, “ahb_tve1”, “ahb_lcd0”,
82: “ahb_lcd1”, “ahb_csi0”, “ahb_csi1”, “ahb_hdmi”,
83: “ahb_de_be0”, “ahb_de_be1”, “ahb_de_fe0”,
84: “ahb_de_fe1”, “ahb_mp”, “ahb_mali400”;
85: };
1)clock-output-names关键字只为了方便clock provider编程方便(后面会讲),clock consumer不能使用
2)通过clock-output-names指定了所有的输出clock,那么,clock consumer怎么引用呢?
1: /* arch/arm/boot/dts/sun4i-a10.dtsi */
2: soc@01c20000 {
3: compatible = "simple-bus";
4: ...
5:
6: pio: pinctrl@01c20800 {
7: compatible = "allwinner,sun4i-a10-pinctrl";
8: reg = <0x01c20800 0x400>;
9: clocks = <&apb0_gates 5>;
10: ...
11: }
12: }
最后
以上就是鲜艳小猫咪为你收集整理的linux时钟框架的全部内容,希望文章能够帮你解决linux时钟框架所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复