Linux common clock framework(2)_clock provider 作者:蜗蜗 发布于
来源:互联网 发布:冰种翡翠手镯价格知乎 编辑:程序博客网 时间:2024/04/29 16:00
原文地址 http://www.wowotech.net/linux_kenrel/clock_provider.html
Linux common clock framework(2)_clock provider
作者:蜗蜗 发布于:2014-10-23 23:49 分类:Linux内核分析
1. 前言
本文接上篇文章,从clock driver的角度,分析怎么借助common clock framework管理系统的时钟资源。换句话说,就是怎么编写一个clock driver。
由于kernel称clock driver为clock provider(相应的,clock的使用者为clock consumer),因此本文遵循这个规则,统一以clock provider命名。
2. clock有关的DTS
我们在“Linux common clock framework(1)_概述”中讲述clock consumer怎么使用clock时,提到过clock consumer怎么在DTS中指定所使用的clock。这里再做进一步说明。
2.1 clock provider的DTS
我们知道,DTS(Device Tree Source)是用来描述设备信息的,那系统的clock资源,是什么设备呢?换句话,用什么设备表示呢?这决定了clock provider的DTS怎么写。
通常有两种方式:
方式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: };
clock,该clock设备的名称,clock consumer可以根据该名称引用clock;
#clock-cells,该clock的cells,1表示该clock有多个输出,clock consumer需要通过ID值指定所要使用的clock(很好理解,系统那么多clock,被抽象为1个设备,因而需要额外的ID标识)。
方式2,每一个可输出clock的器件,如“Linux common clock framework(1)_概述”所提及的Oscillator、PLL、Mux等等,都是一个设备,用一个DTS node表示。每一个器件,即是clock provider,也是clock consumer(根节点除外,如OSC),因为它需要接受clock输入,经过处理后,输出clock。参考如下例子(如果能拿到对应的datasheet会更容易理解):
1: /* arch/arm/boot/dts/sun4i-a10.dtsi */
2: clocks {
3: #address-cells = <1>;
4: #size-cells = <1>;
5: ranges;
6:
7: /*
8: * This is a dummy clock, to be used as placeholder on
9: * other mux clocks when a specific parent clock is not
10: * yet implemented. It should be dropped when the driver
11: * is complete.
12: */
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: };
38:
39: /* dummy is 200M */
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: };
46:
47: axi: axi@01c20054 {
48: #clock-cells = <0>;
49: compatible = "allwinner,sun4i-axi-clk";
50: reg = <0x01c20054 0x4>;
51: clocks = <&cpu>;
52: };
53:
54: axi_gates: axi_gates@01c2005c {
55: #clock-cells = <1>;
56: compatible = "allwinner,sun4i-axi-gates-clk";
57: reg = <0x01c2005c 0x4>;
58: clocks = <&axi>;
59: clock-output-names = "axi_dram";
60: };
61:
62: ahb: ahb@01c20054 {
63: #clock-cells = <0>;
64: compatible = "allwinner,sun4i-ahb-clk";
65: reg = <0x01c20054 0x4>;
66: clocks = <&axi>;
67: };
68:
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: };
86:
87: apb0: apb0@01c20054 {
88: #clock-cells = <0>;
89: compatible = "allwinner,sun4i-apb0-clk";
90: reg = <0x01c20054 0x4>;
91: clocks = <&ahb>;
92: };
93:
94: apb0_gates: apb0_gates@01c20068 {
95: #clock-cells = <1>;
96: compatible = "allwinner,sun4i-apb0-gates-clk";
97: reg = <0x01c20068 0x4>;
98: clocks = <&apb0>;
99: clock-output-names = "apb0_codec", "apb0_spdif",
100: "apb0_ac97", "apb0_iis", "apb0_pio", "apb0_ir0",
101: "apb0_ir1", "apb0_keypad";
102: };
103:
104: /* dummy is pll62 */
105: apb1_mux: apb1_mux@01c20058 {
106: #clock-cells = <0>;
107: compatible = "allwinner,sun4i-apb1-mux-clk";
108: reg = <0x01c20058 0x4>;
109: clocks = <&osc24M>, <&dummy>, <&osc32k>;
110: };
111:
112: apb1: apb1@01c20058 {
113: #clock-cells = <0>;
114: compatible = "allwinner,sun4i-apb1-clk";
115: reg = <0x01c20058 0x4>;
116: clocks = <&apb1_mux>;
117: };
118:
119: apb1_gates: apb1_gates@01c2006c {
120: #clock-cells = <1>;
121: compatible = "allwinner,sun4i-apb1-gates-clk";
122: reg = <0x01c2006c 0x4>;
123: clocks = <&apb1>;
124: clock-output-names = "apb1_i2c0", "apb1_i2c1",
125: "apb1_i2c2", "apb1_can", "apb1_scr",
126: "apb1_ps20", "apb1_ps21", "apb1_uart0",
127: "apb1_uart1", "apb1_uart2", "apb1_uart3",
128: "apb1_uart4", "apb1_uart5", "apb1_uart6",
129: "apb1_uart7";
130: };
131: };
osc24M和osc32k是两个root clock,因此只做clock provider功能。它们的cells均为0,因为直接使用名字即可引用。另外,增加了“clock-frequency”自定义关键字,这样在板子使用的OSC频率改变时,如变为12M,不需要重新编译代码,只需更改DTS的频率即可(这不正是Device Tree的核心思想吗!)。话说回来了,osc24M的命名不是很好,如果频率改变,名称也得改吧,clock consumer的引用也得改吧;
pll1即是clock provider(cell为0,直接用名字引用),也是clock consumer(clocks关键字,指定输入clock为“osc24M”);
再看一个复杂一点的,ahb_gates,它是clock provider(cell为1),通过clock-output-names关键字,描述所有的输出时钟。同时它也是clock consumer(由clocks关键字可知输入clock为“ahb”)。需要注意的是,clock-output-names关键字只为了方便clock provider编程方便(后面会讲),clock consumer不能使用(或者可理解为不可见);
也许您会问,这些DTS描述,怎么使用?怎么和代码关联起来?先不着急,我们慢慢看。
2.2 clock consumer的DTS
在2.1中的方法二,我们已经看到clock consumer的DTS了,因为很多clock provider也是clock consumer。这里再举几个例子,做进一步说明。
例子1(对应2.1中的方式1,来自同一个DTS文件):
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: };
clocks,指明该设备的clock列表,clk_get时,会以它为关键字,去device_node中搜索,以得到对应的struct clk指针;
clocks需要指明的信息,由clock provider的“#clock-cells”规定:为0时,只需要提供一个clock provider name(称作phandle);为1时,表示phandle有多个输出,则需要额外提供一个ID,指明具体需要使用那个输出。这个例子直接用立即数表示,更好的做法是,将系统所有clock的ID,定义在一个头文件中,而DTS可以包含这个头文件,如“clocks = <&clock CLK_SPI0>”;
clock-names,为clocks指定的那些clock分配一些易于使用的名字,driver可以直接以名字为参数,get clock的句柄(具体可参考“Linux common clock framework(1)_概述”中clk_get相关的接口描述)。
例子2,如果clock provider的“#clock-cells”为0,可直接引用该clock provider的名字,具体可参考2.1中的方式2。
例子3,2.1中方式2有一个clock provider的名字为apb0_gates,它的“#clock-cells”为1,并通过clock-output-names指定了所有的输出clock,那么,clock consumer怎么引用呢?如下(2和.1中的方式2,来自同一个DTS文件):
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一样,指定phandle为“aph0_gates”,ID为5。
2.3 DTS相关的讨论和总结
我们在上面提到了clock provider的两种DTS定义方式,哪一种好呢?
从规范化、条理性的角度,毫无疑问方式2是好的,它真正理解了Device Tree的精髓,并细致的执行。且可以利用很多clock framework的标准实现(后面会讲)。
而方式1的优点是,DTS容易写,相应的clock driver也较为直观,只是注册一个一个clock provider即可,没有什么逻辑可言。换句话说,方式1比较懒。
后面的API描述,蜗蜗会着重从方式2的角度,因为这样才能体会到软件设计中的美学。
注1:上面例子中用到了两个公司的代码,方式1是三星的,方式2是全志的。说实话,全志的代码写的真漂亮,一个默默无闻的白牌公司,比三星这种国际大公司强多了。从这里,我们可以看到中国科技业的未来,还是很乐观的。
3. clock provider有关的API汇整
4. 使用clock framework编写clock驱动的步骤
TODO。
- Linux common clock framework(2)_clock provider 作者:蜗蜗 发布于
- Linux common clock framework(2)_clock provider
- Linux common clock framework(2)_clock provider
- Linux common clock framework(2)_clock provider
- Linux功耗管理(15)_Linux common clock framework(2)_clock provider
- Linux common clock framework(2)_概述
- Linux common clock framework(1)_概述
- linux下common clock framework的使用
- Linux common clock framework(1)_概述
- Linux common clock framework(1)_概述
- Linux common clock framework(3)_概述
- Linux common clock framework(1)_概述
- Linux common clock framework(1)_概述
- Linux common clock framework(3)_实现逻辑分析
- Linux common clock framework(3)_实现逻辑分析
- Linux common clock framework(3)_实现逻辑分析
- Common Clock Framework系统结构
- Common Clock Framework系统结构
- linux kernel的中断子系统之(七):GIC代码分析
- linux kernel的中断子系统之(八):softirq
- 【基础算法】排序-复杂排序之一(归并排序的两种优化讨论)
- 模拟post提交json
- Linux common clock framework(1)_概述
- Linux common clock framework(2)_clock provider 作者:蜗蜗 发布于
- JFinal / JFinal
- 项目中的好代码
- 常见的windows自启动方式
- 为什么程序员总是在熬夜?
- c# 连接mysql数据库
- Android Junitest(干货)
- Google-APAC2015-"cut tiles"
- 采访Nastycloud:来自布宜诺斯艾利斯的侏儒冒险记