設備樹DTS 學習:5-基於設備樹的驅動編寫實戰


背景

講完設備樹的有關概念以及語法以后,我們接下來就讓 我們的驅動 使用 設備樹。
ref : 《內核學習筆記14:內核設備樹學習》《u-boot對設備樹的支持》

測試代碼

本文使用的設備樹節點如下:

/ {
// 專門用於測試dts的示例,沒實例用途
    // 名稱可以有“,”、“-”,如“ll,i2c-enable”
    myfoo {
        compatible = "ll,jimkent-foo";
        status = "okay"; // string
        enable; // bool,無須值
        myvalue = <250>; // 默認是32位,如果使用8位讀取,結果為0
        value = /bits/ 8 <88>; // 8位單獨賦值
        value16 = /bits/ 16 <166>; // 16位單獨賦值
        a-cell = <1 2 3 4 5>; // 數組
        // 子節點
        foo {
            label = "foo";
            note = "this is foo";
        };
        bar {
            label = "bar";
            note = "this is bar";
        };
    };
 
 // 其中compatible與驅動使用的名稱必須一致(這樣才能匹配上)。其它內容比較簡單,分別是字符串、布爾類型、不同位數的數值、數組、子節點。
}

驅動實例如下:

/**
 * @file   foo_drv.c
 * @author Late Lee <latelee@163.com>
 * @date   Wed Jun  7 22:21:19 2019
 * 
 * @brief  測試dts示例
 * 
 * @note   讀取dts的值,學習dts。代碼有部分警告,不影響
 */

#include <linux/module.h>
#include <linux/kernel.h>       /**< printk() */
#include <linux/init.h>

#include <linux/types.h>        /**< size_t */
#include <linux/errno.h>        /**< error codes */
#include <linux/string.h>

#include <linux/of.h>
#include <linux/of_device.h>

static int foo_remove(struct platform_device *dev)
{
    printk(KERN_NOTICE "remove...\n");

    return 0;
}

static int foo_probe(struct platform_device *dev)
{
    int ret = 0;
    struct device_node* np = dev->dev.of_node;
    struct device_node* child = NULL;
    const char* str = NULL;
    bool enable = false;
    u8 value = 0;
    u16 value16 = 0;
    u32 value32 = 0;
    
    // 測試dts讀取API
    if(np == NULL)
    {
        pr_info("of_node is NULL\n");
        return 0;
    }
    
    of_property_read_string(np, "status", &str); // 讀字符串

    enable = of_property_read_bool(np, "enable"); // bool類型,可判斷某字段存在不存在
    of_property_read_u32(np, "myvalue", &value32); // 一般地,都使用u32讀取數值
    of_property_read_u8(np, "value", &value);
    of_property_read_u16(np, "value16", &value16);
    
    u32 data[3] = {0};
	u32 tag = 0;
    // a-cell是一個數組,默認讀第1個。
    of_property_read_u32(np, "a-cell", &tag);
    // 也可以讀取指定大小的數組(不一定是全部的)
    of_property_read_u32_array(np, "a-cell", data, ARRAY_SIZE(data));
    
    printk("of read status: %s enable: %d value: %d %d %d\n", str, enable, value, value16, value32);
    printk("of read tag: %d data: %d %d %d\n", tag, data[0], data[1], data[2]);
    
    // 獲取子節點個數
    int count = of_get_available_child_count(np);
    
    // 遍歷所有子節點,按格式讀取屬性
    int index = 0;
    for_each_available_child_of_node(np,child)
    {
        const char* label = of_get_property(child,"label",NULL) ? : child->name;
        const char* note = of_get_property(child,"note",NULL) ? : child->name;
        printk("of read: label: %s note: %s\n", label, note);
    }
    return ret;
}

static struct of_device_id foo_of_match[] = {
	{ .compatible = "ll,jimkent-foo", },
	{ /* sentinel */ }
};

static struct platform_driver foo_driver = {
	.driver = {
		.name = "foo",
		.of_match_table = of_match_ptr(foo_of_match),
	},
	.probe  = foo_probe,
    .remove = foo_remove,
};

static int __init foo_drv_init(void)
{
    int ret = 0;

    ret = platform_driver_register(&foo_driver);
    if (ret)
    {
        pr_info("platform_driver_register failed!\n");
        return ret;
    }
    
    pr_info("Init OK!\n");
    
    return ret;
}

static void __exit foo_drv_exit(void)
{
    platform_driver_unregister(&foo_driver);
}

module_init(foo_drv_init);
module_exit(foo_drv_exit);

MODULE_AUTHOR("Late Lee");
MODULE_DESCRIPTION("Simple platform driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:foo");

示例的代碼是一個簡單的模板,除了學習dts外,沒什么用處。但是可以以此展開復雜的、有實際用途的驅動。
與以前的platform驅動不同,platform_driver中指定of_match_tablefoo_of_match結構體的.compatible必須與設備樹的compatible一致。

本驅動涉及到的讀取設備樹節點信息的函數如下,更多函數,參考內核源碼的include/linux/of.h頭文件:

of_property_read_string // 讀取字符串
of_property_read_bool // 判斷某個字段是否存在,無須賦值
of_property_read_u8 // 讀取8比特
of_property_read_u16 // 讀取16比特
of_property_read_u32 // 讀取32比特

如果存在多個子節點,用of_get_available_child_count獲取個數(可用於開辟內存),然后調用for_each_available_child_of_node遍歷所有子節點,注意,of_get_propertyof_property_read_string有相同效果。只是用法不同而已。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM