linux时钟框架

时钟框架:
方式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: }
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值