ARM linux 设备树 (根节点兼容性与设备节点兼容性,设备节点及label命名)


一、根节点兼容性

  1. .dts文件中,第二行根节点“/”的兼容属性compatible = “acme,coyotes-revenge”;定义了整个系统(设备级别)的名称,组织形式为:< manufacturer >,< modle >。
eg:
arch/arm/boot/dts/vexpress-v2p-ca9.dts兼容于arm,vexpress,v2p-ca9和"arm,vexpress":
compatible = "arm,vexpress,v2p-ca9","arm,vexpress";

进一步看arch/arm/boot/dts/exynos4210-origen.dts的兼容性字段如下:
compatible = "insignal,origen","samsung,exynos4210","samsung,exynos4";
第一个字符串是板子名字(很特定),第二个字符串是芯片名字(比较特定),第三个字段是芯片系列的名字(比较通用)
  1. 在Linux内核中,常常使用如下API来判断根节点的兼容性:
int of_machine_is_compatatible(const char *compat);

eg:以下是判断运行的CPU类型是exynos4210,exynos4212,exynos4412还是exynos5250的代码:
static int exynos_cpufreq_probe(struct platform_device *pdev)
{
    
    
	int ret = -EINVAL;
	exynos_info = kzalloc(sizeof(*exynos_info),GFP_KERNEL);
	if (!exynos_info)
		return -ENOMEM;
	
	exynos_info->dev = &pdev->dev;

	if (of_machine_is_compatatible("samsung,exynos4210"))
	{
    
    
		exynos_info->type = EXYNOS_SOC_4210;
		ret = exynos4210_cpufreq_init(exynos_info);
	}
	else if (of_machine_is_compatatible("samsung,exynos4212"))
	{
    
    
		exynos_info->type = EXYNOS_SOC_4212;
		ret = exynos4x12_cpufreq_init(exynos_info);
	}
	else if (of_machine_is_compatatible("samsung,exynos4412"))
	{
    
    
		exynos_info->type = EXYNOS_SOC_4412;
		ret = exynos4x12_cpufreq_init(exynos_info);
	}
	else if (of_machine_is_compatatible("samsung,exynos5250"))
	{
    
    
		exynos_info->type = EXYNOS_SOC_5250;
		ret = exynos5250_cpufreq_init(exynos_info);
	}
	else {
    
    
		pr_err("%s: Unknow SoC type\n",_func_);
		return -ENODEV;
	}
	...
}

二、设备节点兼容性

设备节点的兼容性和根节点的兼容性是类似的,都是“从具体到抽象”。

//此函数用于判断设备节点的兼容属性是否包含compat指定的字符串。
//这个API多用于一个驱动支持两个以上设备的时候。
int of_device_is_compatible(const struct device_node *device,const char *compat);

三、设备节点及lable命名

  1. 节点命名格式:< name >[@< unit-address >];< >中的内容是必选,[ ]中的内容为可选。

a. < name >为ASCLL字符串,多个同类设备节点的name可以一样,但是unit-address要不一样;
b. < unit-address >为设备的起始地址,也经常在对应节点的 reg 属性中给出;
c. 对于挂在内存空间的设备,此地址直接代表在内存中的地址.
d. 对于挂在I2C总线上的外设,@后面一般跟的是从设备的I2C地址.

注:节点名和属性名(@符号左边的字符)不能超过31个字符

  1. 可以给设备节点添加 lable,之后可以通过 &lable 的形式访问这个节点以获取该节点的设备地址(通过phandle,pointer handle进行的)。

a. 比如在音频machine驱动中的,设备树中节点定义:


audio_speaker{
    
    
    compatible = "zynq, audio_speaker";
    audio-codec = <&ssm2518_label>;
    cpu-dai = <&audio_i2s_label>;
};

b. 为了能够获取codec和platform节点,在machine driver的probe函数中需要如下操作:

static int audio_speaker_probe(struct platform_device *pdev)
{
    
    
    int rc = 0;
    .....
    struct device_node *of_node = pdev->dev.of_node;
    if(of_node == NULL)
    {
    
    
        return -ENXIO;
    }
    //获取设备树节点
    audio_speaker_link.codec_of_node = of_parse_phandle(of_node, "audio-codec" , 0);
    audio_speaker_link.cpu_of_node = of_parse_phandle(of_node, "cpu-dai" , 0);

    //得到设备
    struct device *codec_dev = &of_find_device_b_node(
            audio_speaker_link.codec_of_node)->dev;

    struct device *cpu_dev = &of_find_device_by_node(
            audio_speaker_link.cpu_of_node)->dev;
}

c. 同时设备树支持C语言的预处理过程,可以包含头文件并使用宏定义。

猜你喜欢

转载自blog.csdn.net/weixin_45639314/article/details/129894727