zoukankan      html  css  js  c++  java
  • 在设备树中描述platform_device

    在设备树中描述platform_device

    背景

    在高通平台做gpio按键配置的时候,根据之前的经验,想从设备树中对应的关键字找到实际的驱动解析实现,以此加深对设备树属性配置的理解。

    但是我并没有找到,只是知道在drivers/input/keyboard/gpio_keys.c解析了那一段的配置。翻阅以前自己整理的文章,也没发现一个所以然。

    看来,对设备树的学习还是不能停下。

    Reference:

    介绍

    定义:在设备树的dts文件里,带有compatible属性的节点就是表示一个platform_device.

    用法:在设备树里增加一个设备节点,在内核里的dts文件里描述设备节点;此后,编写驱动代码完成对其的解析即可。

    接口函数

    在设备驱动里获取设备树中的设备资源需要一套接口函数来实现:

    #include <linux/property.h>
    

    函数以device开头表示读取设备的属性, 以fwnode开头表示读取子节点的属性。

    参数propname代表指定要获取值的属性名。

    设备属性

    判断属性是否存在

    bool device_property_present(struct device *dev, const char *propname);
    

    常见用法1:作为指定的属性

        nvmem->read_only = device_property_present(config->dev, "read-only") |
                   config->read_only;
    	//...;
    
    	if (nvmem->read_only) {
            //...;
        }
    

        /* Retrieve the PHY configuration properties */
        if (device_property_present(pdata->phy_dev, XGBE_BLWC_PROPERTY)) {
            ret = device_property_read_u32_array(pdata->phy_dev,
                                 XGBE_BLWC_PROPERTY,
                                 phy_data->blwc,
                                 XGBE_SPEEDS);
            if (ret) {
                dev_err(pdata->dev, "invalid %s property
    ",
                    XGBE_BLWC_PROPERTY);
                return ret;
            }   
        } else {
            memcpy(phy_data->blwc, xgbe_phy_blwc,
                   sizeof(phy_data->blwc));
        }
    

    获取整数值

    int device_property_read_u8_array(struct device *dev, const char *propname,
                      u8 *val, size_t nval);
    int device_property_read_u16_array(struct device *dev, const char *propname,
                       u16 *val, size_t nval);
    int device_property_read_u32_array(struct device *dev, const char *propname,
                       u32 *val, size_t nval);
    int device_property_read_u64_array(struct device *dev, const char *propname,
                       u64 *val, size_t nval);
    

    nval 代表 返回的数组成员个数。

    文本值

    获取
    int device_property_read_string(struct device *dev, const char *propname,
                    const char **val);
    

    注:获取到的值会放进val中;

    常见用法:

        device_property_read_string(dev, "label", &pdata->name);
    
    
    		my_key {
    			label = "btn1";
    			gpios = <&tlmm 102 0x1>;
    	
    			linux,input-type = <1>;
    			linux,code = <59>;
    	
    			debounce-interval = <15>;
    	
    			linux,can-disable;
    			gpio-key,wakeup;
    		};
    
    判断文本值是否匹配
    int device_property_match_string(struct device *dev,
                     const char *propname, const char *string);
    

    例如:

        if (!device_property_match_string(dev, "rotary-encoder,encoding",
                             "binary")) {
            dev_info(dev, "binary");
            encoder->encoding = ROTENC_BINARY;
        } else {
            dev_err(dev, "unknown encoding setting
    ");
            return -EINVAL;
        } 
    

    获取子节点

    /* 获取个数 */
    unsigned int device_get_child_node_count(struct device *dev); //获取设备的子节点个数
    
    /* 获取下一个子节点 */
    struct fwnode_handle *device_get_next_child_node(struct device *dev,
                             struct fwnode_handle *child);
    
    
    

    子节点属性

    fwnode是表示子节点的对象地址,因为和上面的用法类似,因此不再详细说明。

    /* 用于获取设备子节点的属性值函数.   */
    bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname);
    int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
                      const char *propname, u8 *val,
                      size_t nval);
    int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
                       const char *propname, u16 *val,
                       size_t nval);
    int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
                       const char *propname, u32 *val,
                       size_t nval);
    int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
                       const char *propname, u64 *val,
                       size_t nval);
    int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
                          const char *propname, const char **val,
                          size_t nval);
    int fwnode_property_read_string(struct fwnode_handle *fwnode,
                    const char *propname, const char **val);
    int fwnode_property_match_string(struct fwnode_handle *fwnode,
                     const char *propname, const char *string);
    

    例子

    设备树

    举一个例子,如在某个被编译的.dts文件里加入以下内容:

    mynodes@77885566 {  /* 则创建出来的platform_device的名为mynodes@77885566  */
        compatible = "mynodes";  /* 设备节点的属性 */
        autorepeat = <1>;
    
        /* 设备子节点 */
        btn1 {
            label = "btn1";   /* 设备子节点的属性 */ 
            code  = <0x11>;
        };    
        btn2 {
            label = "btn2";
            code  = <0x22>;
        };
    };
    

    增加内容后,则重编设备树:

    make dtbs ARCH=arm64 CROSS_COMPILE=...
    

    再把编译出来的dtb替换板上所用的dtb文件,重启系统后,可以查看到内容:

    # ls /sys/bus/platform/devices/mynodes@77885566/
    driver_override  of_node/         subsystem/
    modalias         power/           uevent
    
    # ls /sys/bus/platform/devices/mynodes@77885566/of_node/
    autorepeat  btn1/       btn2/       compatible  name123456
    

    在dst设备树文件描述设备后就需要与platform_driver进行匹配和驱动了。

    驱动代码

    用于获取mynodes设备资源的驱动源码:

    /* mydrv.c */
    
    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/platform_device.h>
    #include <linux/property.h>
    
    //产生一个for循环用于检查所有的子节点
    #define device_for_each_child_node(dev, child)              
         for (child = device_get_next_child_node(dev, NULL); child;  
              child = device_get_next_child_node(dev, child))
    
    int myprobe(struct platform_device *pdev)
    {
        struct fwnode_handle *fwhandle;
        const char *str;
        u32 val;
    
        //获取设备子节点的个数
        printk("child node count : %d
    ", device_get_child_node_count(&pdev->dev));
        //获取设备属性autorepeat的值
        printk("%d
    ", device_property_read_bool(&pdev->dev, "autorepeat"));
    
        //遍历设备的每个子节点
        device_for_each_child_node(&pdev->dev, fwhandle) {
            //获取设备子节点的label属性值
            fwnode_property_read_string(fwhandle, "label", &str);
            printk("label = %s
    ",  str);
            //获取设备子节点的code属性值
            fwnode_property_read_u32(fwhandle, "code", &val);
            printk("code = %x
    ", val);
        };
    
        return 0;
    }
    
    int myremove(struct platform_device *pdev)
    {
        printk("in myremove ...
    ");
        return 0;
    }
    
    struct of_device_id ids[] = {
        {.compatible = "mynodes"},
        {},
    };
    
    struct platform_driver mydrv = {
        .probe = myprobe,
        .remove = myremove,
    
        .driver = {
            .owner = THIS_MODULE,
            .name = "mydrv" ,
    
            .of_match_table = ids,
        },
    };
    
    module_platform_driver(mydrv);
    MODULE_LICENSE("GPL");
    

    编译驱动模块加载后的输出结果:

    [  111.222065] child node count : 2
    [  111.222429] 1
    [  111.223054] label = btn1
    [  111.223690] code = 11
    [  111.224000] label = btn2
    [  111.224623] code = 22
    
  • 相关阅读:
    tomcat启动失败日志
    Windows环境卸载tomcat
    JAVA教程_Windows环境Java安装部署教程
    Tomcat和JDK版本的对应关系
    tomcat启动窗口乱码问题_解决办法
    Windows环境Tomcat安装及环境部署_官方教程
    perl + 匹配前导模式一次或者多次
    5.3.5 聚簇索引:
    freshStartTail 第一次启动时 抛弃旧的日志
    tomcat docBase 和 path
  • 原文地址:https://www.cnblogs.com/schips/p/describe_platform_device_in_dts.html
Copyright © 2011-2022 走看看