设备树中时钟

时钟框图

 

先来看看S3C2440时钟的硬件框图:

设备树中时钟

 

 

将该图简化如下:

设备树中时钟

 

 我们只想作为消费者怎么去使用这些时钟,并不关心“提供者”内部的层级结构,只要知道“直接提供者”,也不关系“直接提供者”的实现,我们只需要发出请求就可以了。

 

晶振设备树描述

我们看看在2440的设备树里怎么描述这提供者和消费者。先来看看晶振:

    xti: xti_clock {
        compatible = "fixed-clock";
        clock-frequency = <12000000>;
        clock-output-names = "xti";
        #clock-cells = <0>;
    };

根据compatible可以找到对应的驱动,驱动程序将晶振的频率记录下来,以后作为计算的基准。

然后再是PLL的设备节点:

    clocks: clock-controller@4c000000 {
        compatible = "samsung,s3c2440-clock";
        reg = <0x4c000000 0x20>;
        #clock-cells = <1>;
    };

设备节点本身非常简单,复杂的是它对应的驱动程序。在驱动程序里面,肯定会根据reg获得寄存器的地址,然后设置各种内容。


大部分的芯片为了省电,它的外部模块时钟平时都是关闭的,只有在使用某个模块时,才设置相应的寄存器开启对应的时钟。


这些使用者各有不同,要怎么描述这些使用者呢?

我们可以为它们配上一个ID。在设备树中的#clock-cells = <1>;表示 用多少个u32位来描述消费者。在本例中使用一个u32来描述。


这些ID值由谁提供的?

是由驱动程序提供的,该节点会对应一个驱动程序,驱动程序给硬件(消费者)都分配了一个ID,所以说复杂的操作都留给驱动程序来做。

LCD时钟设备树描述

消费者想使用时钟时,首先要找到时钟的直接提供者,向它发出申请。以LCD为例:

    fb0: fb@4d000000{
        compatible = "jz2440,lcd";
        reg = <0x4D000000 0x60>;
        interrupts = <0 0 16 3>;
        clocks = <&clocks HCLK_LCD>;
        clock-names = "lcd";
        ……
    }

clock属性里,首先要确定向谁发出时钟申请,这里是向clocks发出申请,然后确定想要时钟提供者提供哪一路时钟,这里是HCLK_LCD,在驱动程序里定义了该宏,每种宏对应了一个时钟ID。

定义如下:

……
/* hclk-gates */
#define HCLK_LCD        32
#define HCLK_USBH        33
#define HCLK_USBD        34
#define HCLK_NAND        35
#define HCLK_CAM        36
……

因此,我们只需要在设备节点定义clocks这个属性,这个属性确定时钟提供者,然后确定时钟ID,也就是向时钟提供者申请哪一路时钟。

对应的内核文档可以参考这两个文件:

Documentation/devicetree/bindings/clock/clock-bindings.txt
Documentation/devicetree/bindings/clock/samsung,s3c2410-clock.txt

那么我这个设备驱动程序,怎么去使用这些时钟呢? 以前的驱动程序:clk_get(NULL, "name"); clk_prepare_enable(clk); 现在的驱动程序:of_clk_get(node, 0); clk_prepare_enable(clk);

总结

a. 设备树中定义了各种时钟, 在文档中称之为"Clock providers", 比如:

    clocks: clock-controller@4c000000 {
        compatible = "samsung,s3c2440-clock";
        reg = <0x4c000000 0x20>;
        #clock-cells = <1>;      // 想使用这个clocks时要提供1个u32来指定它, 比如选择这个clocks中发出的LCD时钟、PWM时钟
    };

b. 设备需要时钟时, 它是"Clock consumers", 它描述了使用哪一个"Clock providers"中的哪一个时钟(id), 比如:

    fb0: fb@4d000000{
        compatible = "jz2440,lcd";
        reg = <0x4D000000 0x60>;
        interrupts = <0 0 16 3>;
        clocks = <&clocks HCLK_LCD>;  // 使用clocks即clock-controller@4c000000中的HCLK_LCD        
    };

c. 驱动中获得/使能时钟:

    // 确定时钟个数
    int nr_pclks = of_count_phandle_with_args(dev->of_node, "clocks",
                        "#clock-cells");
    // 获得时钟
    for (i = 0; i < nr_pclks; i++) {
        struct clk *clk = of_clk_get(dev->of_node, i);
    }

    // 使能时钟
    clk_prepare_enable(clk);

    // 禁止时钟
    clk_disable_unprepare(clk);

 

 

 

第六课:在LCD驱动中使用设备树

上一篇:HDU 2254 奥运(矩阵高速幂+二分等比序列求和)


下一篇:c语言小游戏之加载数字(并且计算出加载所用时间)