在查看zynq的clk时钟驱动时,在源码文件clkc.c中我们看到匹配属性字段”xlnx,ps7-clkc”,该字段匹配zynq-7000.dtsi的时钟子节点的compatible关键字属性相匹配,时钟的setup函数为zynq_clk_setup,查看整个源码包没有发现有调用该函数的痕迹,但是发现该函数被宏CLK_OF_DECLARE引用了。
首先看一下CLK_OF_DECLARE宏,它的定义位于“include/linux/clk-provider.h”中,负责在指定的section中(以__clk_of_table开始的位置),定义structof_device_id类型的变量,并由of_clk_init(在函数 zynq_timer_init (mach-zynq/common.c)中被调用)接口解析、匹配,如果匹配成功,则执行相应的回调函数(这里为of_fixed_clk_setup);初始化的时候,device tree负责读取DTS,并和这些变量的名字(这里为" xlnx,ps7-clkc ")匹配,如果匹配成功,则执行相应的回调函数(这里为of_fixed_clk_setup);of_fixed_clk_setup会解析两个DTS字段"clock-frequency"和"clock-output-names",然后调用clk_register_fixed_rate,注册clock。注意,注册时的flags为CLK_IS_ROOT,说明目前只支持ROOT类型的clock通过DTS注册;最后,调用of_clk_add_provider接口,将该clock添加到provider_list中,方便后续的查找使用。该接口会在后面再详细介绍。
在of_clk_init被调用之前,zynq_timer_init 先调用了zynq_clock_init函数,该函数实现功能如下:
1. 根据字段“compatible”匹配“xlnx,ps7-clkc”判断节点np是否存在
2. 判断np是否有地址内存定义
3. 判断np是否存在父节点slcr
4. 将节点np的物理地址赋值给全局变量zynq_clkc_base,该变量是void *指针,并通过__iomem修饰,强制定义链接区域
5. 通过of_node_put函数将np和slcr的refcount减1,我们查到of_node_put函数的说明,但我发现它调用了kobject_put,该函数简要说明如下:当一个kobject对象的引用ref被减少到0时,程序就会释放这个kobject相关的资源,所以在减少引用的函数中就应该有调用释放资源的相关代码,在下面内核代码中也可以看到。