设备树和平台设备的关系
满足如下条件的设备树节点将被转换为平台设备:
- 根节点下含有 compatile 属性的子节点会被转换为平台设备。
- 根节点的子节点中嵌套的子节点由它上一级节点所对应的驱动处理,但是根节点中 compatile 属性为"simple-bus"
“simple-mfd” “isa” “arm,amba-bus” 这4者之一的子节点下嵌套的子节点依然会被转换为平台设备。
实现一个LED的平台驱动
这个LED平台驱动基于3.2平台设备驱动改进而来,主要删除了platform_device描述,增加了设备树修改内容
编写LED驱动的设备树
在顶层设备树根节点中加入如下节点
platform_led {
compatible = "platform_led";/* 用于设备树与驱动进行匹配 */
status = "okay"; /* 状态 */
labe = "test_led"; /* 标签,对应设备文件名 */
config_info = <0xA28 /* 时钟控制寄存器相对于时钟寄存器组的偏移 */
8 /* GPIO时钟控制位的偏移 */
0>; /* 引脚号 */
reg = <0X50000000 4096 /* 时钟控制器的寄存器 */
0X5000A000 128>; /* GPIO控制寄存器 */
};
修改驱动程序
驱动程序主要修改了两个地方:
- 修改了pled_probe函数,将通过设备私有参数传递配置信息修改为通过设备树获取
//获取配置参数
result = of_property_read_u32_index(pdev->dev.of_node, "config_info", 0, &led_handle->led_config.rcc_offset);
if(result != 0)
{
printk("get config info failed\r\n");
return result;
}
result = of_property_read_u32_index(pdev->dev.of_node, "config_info", 1, &led_handle->led_config.rcc_shif);
if(result != 0)
{
printk("get config info failed\r\n");
return result;
}
result = of_property_read_u32_index(pdev->dev.of_node, "config_info", 2, &led_handle->led_config.pin_num);
if(result != 0)
{
printk("get config info failed\r\n");
return result;
}
result = of_property_read_string(pdev->dev.of_node, "labe", &led_handle->led_config.labe);
if(result != 0)
{
printk("get config info failed\r\n");
return result;
}
- 增加设备树匹配表,以便驱动长度能跟设备树创建而来的平台设备匹配成功
/* 匹配列表,用于设备树和平台驱动匹配 */
static const struct of_device_id led_of_match[] = {
{ .compatible = "platform_led" },
{ /* Sentinel */ }
};
//平台驱动
struct platform_driver led_drv = {
.driver = {
.name = "myled", //平台驱动名称
.owner = THIS_MODULE,
.pm = NULL,
.of_match_table = led_of_match,
},
.probe = pled_probe, //设备和驱动匹配成功执行
.remove = pled_remove, //设备或驱动卸载时执行
.shutdown = pled_shutdown, //系统关机前执行
.suspend = pled_suspend, //系统休眠前执行
.resume = pled_resume, //系统唤醒后执行
};
完整的驱动代码可以从这里下载