Linux驱动学习记录-5.设备树介绍

        设备树是Linux驱动开发的必备技能。

1.什么是设备树

        设备树(Device Tree),描述设备树的文件叫做DTS(Device Tree Source),这个DTS文件采用树形结构描述板级信息如下图:

         设备树源文件DTS,将.dts文件编译后会得到二进制文件DTB,需要用到DTC工具。进入源码里,使用

make all

会编译Linux中所有的东西,包括zImage、.ko、.dts等。也可以只使用

make dtbs

只编译dts文件,会更快些。

2.设备树语法属性

        下面以一个小型模板设备树为例子,介绍其语法和各个属性。

/ {
	compatible = "fsl,imx6ull-alientek-evk", "fsl,imx6ull";
	cpus {
		#address-cells = <1>;
		#size-cells = <0>;
		
		cpu0: cpu@0{
			compatible = "arm,cortex-a7";
			device_type = "cpu";
			reg = <0>;
		};
	};
    
    soc {
        compatible = "simple-bus";
        #addre-cells = <1>;
        #size-cells = <1>;
        ranges = <0x0 0xe0000000 0x00100000>;
    };
	
	aips1:aips-bus@02000000 {
		compatible = "fsl,aips-bus", "simple-bus";
		#address-cells = <1>;
		#size-cells = <1>;
		reg = <0x2000000 0x100000>;
		ranges;
		
		ecspil:ecspi@02008000 {
			#address-cells = <1>;
			#size-cells = <0>;
			compatible = "fsl,imx6ul-ecspi","fsl,imx51-ecspi";
			reg = <0x02008000 0x4000>;
			status = "disabled";
		};
	};
}
  • /{ } 表示跟节点,在花括号里面添加子节点。
  • 子节点:label:node-name@unit-address,引入label为了方便访问节点,可以通过&label来访问,而不用输入整个名字。可以在子节点里面再添加子节点,格式一样。如aips1节点里面的ecspil节点。
  • compatible属性:兼容性属性,是一个字符串列表。格式如“manufacturer,model”。上面fsl表示飞思卡尔厂商。
  • model属性:也是字符串,描述设备模块信息,如modul =  "aops-bus"。
  • status属性:和设备状态有关。有四种状态:"okey"表示设备是可操作的;"disabled"设备不可操作,未来可操作;"fail"设备不可操作,未来也不可能操作;"fail-sss"和fail相同,sss表示检测到的错误信息。
  • #address-cells和#size-cells属性:都是无符号32位整型,前面决定节点的地址,后面表示长度。这两个表面子节点如何编写reg属性。两个都是<1>,表示后面的reg属性中地址占用1个字节,长度占用1个字节。如果长度<0>表示没有长度这个属性。
  • reg属性:一般为(address, length),用来描述设备地址空间资源信息。比如aips1中起始地址为0x2000000,地址长度为0x100000;
  • ranges属性:一般为空。或者按照(child-bus-address, parent-address, length)格式编写,每个项目由子地址、父地址、长度三部分组成。

其他属性在后续学习中再添加。

3.常用OF设备树操作函数

3.1查找节点

//通过节点名字查找指定节点
struct device_node *of_find_node_by_name(struct device_node *from, const char *name);

//通过device_type属性查找指定节点
struct device_node *of_find_node_by_type(struct device_node *from, const char *type);

//根据device_type和compatible两个属性查找
struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible);

//通过of_device_id匹配表查找
struct device_node *of_find_matching_node_and_match(struct device_node *from, const struct of_device_id *matches, const struct of_device_id **match);

//通过路径查找节点
inline struct device_node *of_find_node_by_path(const char *path);

各个参数说明:

  • from:开始查找的节点,为空则从根节点开始查找整个设备树
  • name:要查找节点的名字
  • type:要查找节点对应的type字符串,也就是device_type属性值
  • compatible:所对应的compatible属性列表
  • matches:of_device_id匹配表,也就是在匹配吧里查找节点
  • match:找到匹配的of_device_id
  • path:带有全路径的节点名
  • return:找到的节点

3.2查找父/子节点

//获取指定节点的父节点
struct device_node *of_get_parent(const struct device_node *node);

//用迭代的方式查找子节点
struct device_node *of_get_next_child (const struct device_node *node, struct device_node *prev);
  • node:要查找的父/子节点的节点
  • prev:前一个子节点
  • return:找到的父/子节点

3.3提取属性值函数

//查找指定属性
of_find_propetry(const struct device_node *np, const char *name, int *lenp)
  • np:设备jied
  • name:属性名字
  • lenp:属性值的字节数
  • return:找到的属性
//获取属性中元素的数量
int of_property_count_elems_of_size(const struct device_node *np, const char *propname, int elem_size);
  • np:设备节点
  • proname:需要统计元素数量的属性名字
  • elem_size:元素长度
  • return:属性元素数量
//从属性中获取指定标号的u32类型数据值
int of_property_read_u32_index(const struct device_node *np, const char *propname, u32 index, u32 *out_value)
  • index:要读取的值标号
  • out_value:读取的值
  • return:0读取成功;负值读取失败;-EINVAL 表示属性不存在; -ENODATA 表示没有
    要读取的数据; -EOVERFLOW 表示属性值列表太小。
//读取属性中u8、u16、u32、u64类型的数组数据
int of_property_read_u8_array(const struct device_node *np, const char *propname, u8 *out_values, size_t sz)

int of_property_read_u16_array(const struct device_node *np, const char *propname, u16 *out_values, size_t sz)

int of_property_read_u32_array(const struct device_node *np, const char *propname, u32 *out_values, size_t sz)

int of_property_read_u64_array(const struct device_node *np, const char *propname, u64 *out_values, size_t sz)
  • out_value:读取到的数组值,分别为u8、u16、u32、u64.
  • sz:要读取元素的数量
  • return:0读取成功;负值读取失败;-EINVAL 表示属性不存在; -ENODATA 表示没有
    要读取的数据; -EOVERFLOW 表示属性值列表太小。
//读取只有一个整型值的属性
int of_property_read_u8(const struct device_node *np, const char *propname, u8 *out_value)
int of_property_read_u16(const struct device_node *np, const char *propname, u16 *out_value)
int of_property_read_u32(const struct device_node *np, const char *propname, u32 *out_value)
int of_property_read_u64(const struct device_node *np, const char *propname, u64 *out_value)

参数和上一个一样

//读取属性中字符串值
int of_property_read_string(struct device_node *np, const char *propname, const char **out_string)
  • out_string:读取到的字符串
  • return:0读取成功;负值读取失败
//获取#address_cells
int of_n_addr_cells(struct device_node *np)

//获取#size_cells
int of_n_size_cells(struct device_node *np)
  • np:设备节点
  • return:获取的属性值

3.4其他常用函数

//获取地址相关属性
const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags)
  • dev:设备节点
  • index:要读取的地址标号
  • size:地址长度
  • flags:参数比如 IORESOURCE_IO、 IORESOURCE_MEM 等
  • return:读取到的首地址,NULL表示失败
//将设备树读取到的地址转换为物理dihzi
u64 of_translate_address(struct device_node *dev, const __be32 *in_addr)
  • in_addr:要转换的地址
  • return:得到的物理地址
//将reg属性值转换为resource结构体类型
int of_address_to_resource(struct device_node *dev, int index, struct resource *r)
  • dev:设备节点
  • index:地址资源标号
  • r:得到的resource类型的资源值
  • return:0成功;负值失败
//直接内存映射
void __iomem *of_iomap(struct device_node *np, int index);
  • np:设备节点
  • index:reg属性中要完成内存映射的段,如果reg属性只有一段则index是0
  • return:经过映射的虚拟地址首地址,为NULL则失败

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值