设备树结构
主要有节点组成(节点里面还可以包含子节点),节点里面可以设备各种属性
(1)属性的值可以是字符串数组、cells(u32整数组成)、二进制数
(2)节点@后,一般表示节点的地址
(3)#address-cells =<1> #size-cells=<1> 分别描述子节点reg属性的 起始地址和地址长度
reg 示例:reg = < address length>
#address-cells =<1> :表示 address 是一个值
#address-cells =<2> :表示 address 是两个个值
#size-cells=<0> :表示没有length
#size-cells=<1>:表示length 是一个值
#address-cells =<2> #size-cells=<1>
子节点reg属性
reg = <0 0 0x1000> :第一个0 表示片选,第二个0 表示相对该片选的基地址,0x1000 为length
(4)compatible 用于和driver 进行匹配
获取节点
通过of_device_id 结构体数组里面的元素进行匹配(匹配表匹配)
(device_node 表示dts中的一个节点)
用于probe 函数中,根据dev和match_id 匹配,得到of_device_id。然后可以匹配对应的data,这个常用dts有多个compatible能够匹配,但是不同compatible的data不一样,这样就可以根据不同的compatible选择不同的data
extern const struct of_device_id *of_match_node(
const struct of_device_id *matches, const struct device_node *node);
举例
platform_device 下有一个 struce device,这个下面又有一个 struce device_node (这个就是用来和设备树匹配的)
类似函数:of_match_device (里面调用的是of_match_node)
const struct of_device_id *of_match_device(const struct of_device_id *matches,
const struct device *dev)
{
if (!matches || !dev->of_node || dev->of_node_reused)
return NULL;
return of_match_node(matches, dev->of_node);
}
判断具体设备
当一个驱动要支持多个设备时,就可以通过这个函数判断具体是哪个设备
static inline int of_device_is_compatible(const struct device_node *device,
const char *name)
{
return 0;
}
补充获取节点的api
指定起始搜索device_node 的匹配函数
下面函数和of_match_node 的差异就是可以指定从哪个节点开始搜索
通过对应的of_device_id ,找到匹配到的device_node
static inline struct device_node *of_find_matching_node(
struct device_node *from,
const struct of_device_id *matches)
{
return of_find_matching_node_and_match(from, matches, NULL);
}
补充device_node
它是device结构体下的一个成员(关联的设备树节点),名字叫做of_node
所有的probe函数的参数都是一个platform_device结构体,它里面有一个dev成员(是一个device结构体,表示的就是dts节点对应的一个device
通过alias找到对应的编号
比如SoC上有如果多個i2c控制器,alias的相當於給每個i2c控制器分配一個唯一的編號,如上面的i2c@13880000對應的alias是i2c2,那麼這個編號就是2,將來就可以在/dev下看到名爲i2c-2的設備節點
of_alias_get_id(dev->of_node, drv_data->dev_name);//dev_name: 名字
在內核中可以看到很多地方都會調用of_alias_get_id,他的作用就是根據傳入的device node,在alias中找到對應的唯一編號,如:
比如下面的dev_name 就是 csi2dphy
下面有三个compatible都一样的节点,然后还有一个aliases中有这三个节点。但是driver 中只能匹配到一个节点,所以就使用of_alias_get_id或得到匹配到的是哪一个节点,返回的是索引。
aliases 节点下就会有多个dev_name的别名,这样就能获取到对应设备的序号
通过父节点的属性名字获取子节点
np = of_parse_phandle(dev->of_node, "rockchip,hw", 0);// 通过名字获取该节点下子节点的device_node
根据字符串和索引从device_node对应的节点中(该节点下有一个属性引用了另一个节点)获取另一个device_node。然后使用下面这个函数就可以根据device_node获取对应的platform_device
static inline struct platform_device *of_find_device_by_node(struct device_node *np)
static inline void of_node_put(struct device_node *node)//释放device_node
举例
下面csi2_dphy0节点下rockchip,hw 属性引用了另一个节点csi2_dphy_hw,
然后下面的代码就可以从csi2_dphy0的driver中获取csi2_dphy_hw 对应的driver中的platform_device
device_node 相关
判断device_node 是否可用
bool of_device_is_available(const struct device_node *device)
减少device_node 的引用计数
void of_node_put(struct device_node *node)
获取节点属性
根据节点和属性名或者属性值
(1)整形
```c
static inline int of_property_read_u32_array(const struct device_node *np,
const char *propname,
u32 *out_values, size_t sz)
static inline int of_property_read_u32(const struct device_node *np,
const char *propname,
u32 *out_value)
(2)字符串
extern int of_property_read_string(const struct device_node *np,
const char *propname,
const char **out_string);
4 platform 驱动单独的
5 irq
当配置了多个irq 时,可以用下面这个函数通过名字获取某一个irq号
还可以通过下面这个函数获取第几个中断号
extern int platform_get_irq(struct platform_device *, unsigned int);
注册irq
devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler,
unsigned long irqflags, const char *devname, void *dev_id)
{
return devm_request_threaded_irq(dev, irq, handler, NULL, irqflags,
devname, dev_id);
}
include
dts 和 dtsi 中不仅可以include dtsi 文件,还可以include .h 文件
使用预处理
dts dtsi 中也可以定义宏 #if #else 等
#define VM311XS_IN
#ifdef VM311XS_IN
#endif
#if 1
#else
#endif