在Linux驱动中设备树用于指定硬件的信息。
开发板加载时,u-boot 先运行,它的作用是启动内核。U-boot 会把内核和设备树文件都读入内存,然后启动内核。在启动内核时会把设备树在内存中的地址告诉内核。
当设备树节点被转换成platform_device
platfrom_device
可用于指定设备资源
struct platform_device {
const char*name;
int id;
bool id_auto;
struct device dev;
u32 num_resources;
struct resource *resource;
const struct platform_device_id *id_entry;
char *driver_override; /* Driver name to force a match */
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
platfrom_driver
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;
bool prevent_deferred_probe;
};
在驱动的入口函数中注册platform_driver 结构体,platfrom_device结构体。
匹配规则
最先比较的:
platform_device. driver_override 和 platform_driver.driver.name
然后比较:
platform_device. name 和 platform_driver.id_table[i].name
最后比较:
platform_device.name 和 platform_driver.driver.name
关于函数的调用关系分析及需要查看Linux源码,逐步分析;
可以得出的结论是:当dev和drv匹配时,自动调用drv的probe函数。
常用的函数:
platform_device_register (参数为一个platform_device 结构体)
platform_driver_register (参数为一个platform_driver结构体)
platform_get_resource(dev, type, num); 获取资源
设备树的基础
常用属性:
address-cells:address 要用多少个 32 位数来表示地址;
size-cells:size 要用多少个 32 位数来表示大小。
compatible:兼容,在设备树经内核解析后与drv匹配,用来指定内核中哪个 machine_desc 可以支持本设备
status :用于描述设备的状态,如:okay;disabled;fail等
reg:寄存器地址
设备树只允许有一个根节点,和许多子节点。
1、DTS在PC机(ubuntu中)被编译为DTB文件;
2、将DTB拷贝到开发板 /boot目录下,u-boot会将dtb文件传送给内核zImage;
3、内核将DTB文件中的每一个节点都转换成 struct device_node结构体;
4、将子节点中含有compatile 属性,若子节点中compatile属性的值为“simple-bus",“simple-mfd”,“isa”,“arm,amba-bus”,子节点的子节点也可转换成platform_device。
(ps:总线中I2C、SPI节点下的子节点不转换成platform_device)
对于如何转换这个问题,的比较复杂,能力有限,暂不能窥测。
设备树节点转换成platfrom_device后与platfrom_driver配对
根据这个分析
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
return 1;
/* Then try ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;
/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);
}
简单描述设备树与drv配对:
1、pdev.driver_overrided和pdrv.drv.name
2、比较设备树信息pdev.dev.of_node 和pdrv.drv.of_match_table
3、pdev.name和pdrv.id_table[].name
4、pdev.name和pdrv.name
得出的结论为:
使用platform_driver.driver_driver.of_device_id->compatible和设备树中的compatible进行匹配,所以想要添加驱动,只需要在设备树文件中添加节点,指定device的compatible,然后在代码中再指定driver的compatible即可完成匹配,执行probe函数。
最新修改时间:2020/7/12 17:00