dtc设备树编译器,将exynos4412-fs4412.dts编译成exynos4412.dtb这个文件,把设备树文件下载到42000000然后bootm 41000000-42000000。
一开始的驱动不优雅,因为把硬件信息直接编码到驱动中。
我们后来将设备和驱动进行了分离,这样驱动尽量与硬件无关,硬件变化,只需要修改设备中的资源,这样一来,系统移植的工作主要就是修改系统中的大量设备中的资源(硬件信息)。整个过程重复率高,代码不优雅。设备树应运而生。
系统启动时会扫描设备树来生成很多设备,这样一来,一旦硬件变化我们只需要修改设备树,不用去创建并修改设备。
传统的方法,用c语言来编写各种设备,比较繁琐,一旦硬件有变化,得修改c代码,重新编译。如果直接编译到内核,需要重启,编程模块需要加载。
我们希望只用少量的语句就能创建设备,可能不需要像c语言这么复杂的语法,因为我们只是描述一下硬件信息,理想状态,做硬件的人,就可以搞定。
编写使用设备树的LED驱动
创建fsled目录,里面只需要写驱动,不用写设备,那么如何得到设备?我们需要修改设备树,在设备树中添加led,这样系统启动以后,就会生成led设备的。
首先要做的就是在设备树文件中添加相应的LED设备树节点,修改arch/arm/boot/dts/exynos4412.dts加入以下代码。
我们将硬件信息放到设备树中的节点,系统启动时,会扫描里面的硬件信息。
第一个LED节点
//节点名字@地址
fsled2@11000c40{
//和驱动匹配的字符串
compatible = "fs4412 fsled";
//从0x11000c40开始,占8个字节
reg = <0x11000c40,0x8>;
id = <2>;
pin = <7>;
};
第二个LED节点
//名字@地址
fsled2@11000c20{
//总线负责匹配设备和驱动
compatible = "fs4412 fsled";
//从0x11000c40开始,占8个字节,标准硬件信息,内核中用struct resource来表示。
reg = <0x11000c20,0x8>;
//id和pin是自定义的特殊信息
id = <3>;
pin = <0>;//led的管脚号
};
系统启动时,会将每个节点生成一个设备,当加载驱动时会进行匹配,用compatible来进行匹配。
将信息放到设备树中arch/arm/boot/dts/exynos4412.dts
然后make dtbs
将生成的设备树复制到/tftpboot,重启开发板。
接下来修改驱动,让他使用设备树。
使用设备的驱动,获取标准硬件信息的方法和以前是一样的,不用修改。用platform_get_resource.
本例中id和pin是自定义属性,要获取这两个属性的值,要使用of_property_read_u32
函数。
int of_property_read_u32(const struct device_node *np,const char *propname,u32 *out_value);
np:设备节点地址
propname:属性的名字
out_value:将获取到的属性值,存在这个指针所指向的单元里成功返回0,失败返回非0;
比如,这里要获取id值;
int id; //id这里是随机值
of_property_read_u32(pdev->dev.of_node,"id",&id);
这样就能得到id的值。
//从设备树中获取id号,存入pdev->id里面
of_property_read_u32(pdev->dev.of_node,"id",&pdev->id);
//从设备树中获取pin,存入fsled->pin
of_property_read_u32(pdev->dev.of_node,"pin",&pdev->pin);
使用设备树的驱动,通常需要一个struct of_device_id数组,里面的compatible
用于和设备树的节点进行匹配,并且在平台驱动中将of_match_table进行相应的赋值。
static const struct of_device_id fsled_of_matches[]={
{ .compatible = "fs4412,fsled",}, //要和设备树里面的compatible匹配上才行。
{/*sentine*/},
};
MODULE_DEVICE_TABLE(of,fsled_of_matches);
struct platform_driver fsled_drv = {
.driver = {
.name = "fsled",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(fsled_of_matchs);
}
.probe = fsled_probe,
.remove = fsled_remove,
}