一、根节点兼容性
- .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";
第一个字符串是板子名字(很特定),第二个字符串是芯片名字(比较特定),第三个字段是芯片系列的名字(比较通用)
- 在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命名
- 节点命名格式:< name >[@< unit-address >];< >中的内容是必选,[ ]中的内容为可选。
a. < name >为ASCLL字符串,多个同类设备节点的name可以一样,但是unit-address要不一样;
b. < unit-address >为设备的起始地址,也经常在对应节点的 reg 属性中给出;
c. 对于挂在内存空间的设备,此地址直接代表在内存中的地址.
d. 对于挂在I2C总线上的外设,@后面一般跟的是从设备的I2C地址.
注:节点名和属性名(@符号左边的字符)不能超过31个字符
- 可以给设备节点添加 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语言的预处理过程,可以包含头文件并使用宏定义。