Linux driver dts使用,实例驱动编写

Device Tree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码。
Device Tree由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子结点。所谓属性,其实就是成对出现的name和value。在Device Tree中,可描述的信息包括(原先这些信息大多被hard code到kernel中):
CPU的数量和类别
内存基地址和大小
总线和桥
外设连接
中断控制器和中断使用情况
GPIO控制器和GPIO使用情况
Clock控制器和Clock使用情况

DTS (device tree source)
.dts文件是一种ASCII 文本格式的Device Tree描述,易于阅读。在ARM Linux系统一个.dts文件对应一个ARM的machine,一般放置在内核的arch/arm/boot/dts/目录。由于一个SoC可能对应多个machine(一个SoC可以对应多个产品和电路板),势必这些.dts文件需包含许多共同的部分,Linux内核为了简化,把SoC公用的部分或者多个machine共同的部分一般提炼为.dtsi,类似于C语言的头文件。其他的machine对应的.dts就include这个.dtsi。譬如,对于VEXPRESS而言,vexpress-v2m.dtsi就被vexpress-v2p-ca9.dts所引用, vexpress-v2p-ca9.dts有如下一行:
/include/ “vexpress-v2m.dtsi”,.dtsi也可以include其他的.dtsi,譬如几乎所有的ARM SoC的.dtsi都引用了skeleton.dtsi。
.dts(或者其include的.dtsi)基本元素即为前文所述的结点和属性:

本文以Amlogic S905D平台
dts文件引用的头文件:
release_n_7.1_20170804\common\arch\arm\boot\dts\include\dt-bindings
|->clk
|->clock
|->dma
|->gpio
|->input
|->interrupt-controller
|->mfd
|->pinctrl
|->pwm
|->reset
|->sound
|->thermal

解析dts文件的相关函数,定义在of.h文件里:
release_n_7.1_20170804\common\include\linux\of.h

常用函数原型:

static inline bool of_property_read_bool(const struct device_node *np, 
                        const char *propname)

static inline int of_property_read_u8(const struct device_node *np, 
                        const char *propname, u8 *out_value)

static inline int of_property_read_u16(const struct device_node *np, 
                        const char *propname, u16 *out_value)

static inline int of_property_read_u32(const struct device_node *np, 
                        const char *propname, u32 *out_value)

static inline int of_property_read_string_array(struct device_node *np,
                        const char *propname, const char **out_strs,
                        size_t sz)

static inline int of_property_count_strings(struct device_node *np,
                        const char *propname)

static inline int of_property_read_string_index(struct device_node *np,
                        const char *propname,
                        int index, const char **output)

dts文件添加node:

//dts文件以“/”为根目录,以树形展开,要注意思大括号的匹配。
/* add by song for dvb widgets */
    dvb_widgets {
        compatible = "amlogic, dvb_widgets"; //platform_driver 指定的匹配表。
        status = "okay"; //设备状态
        dw_name = "dvb-widgets"; //字符串属性
        dw_num = <8>; //数值属性
        ant_power-gpio = <&gpio  GPIODV_15  GPIO_ACTIVE_HIGH>; //gpio 描述
        loops-gpio = <&gpio  GPIODV_13  GPIO_ACTIVE_HIGH>; //gpio 描述
        ch34-gpio = <&gpio  GPIODV_12  GPIO_ACTIVE_HIGH>; //gpio 描述
    };

驱动demo


#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/types.h>
#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/errno.h>
#include <linux/irq.h>
#include <linux/of_irq.h>
#include <linux/device.h>

#include <asm/irq.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <uapi/linux/input.h>
#include <linux/major.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/of.h>
#include <linux/amlogic/aml_gpio_consumer.h>
#include <linux/amlogic/gpio-amlogic.h>
#include <linux/amlogic/sd.h>
#include <linux/amlogic/iomap.h>
#include <dt-bindings/gpio/gxbb.h>
#include <linux/amlogic/cpu_version.h>
#include <linux/amlogic/pm.h>
#include <linux/of_address.h>

struct dw_dev {
    unsigned int ant_power_pin;
    unsigned int ant_overload_pin;
    unsigned int loops_pin;
    unsigned int ch3_4_pin;
};

struct dw_dev pdw_dev;


static int dvb_widgets_suspend(struct platform_device *pdev,  pm_message_t pm_status)
{
    pr_dbg("%s\n",__FUNCTION__);
    return 0;
}

static int dvb_widgets_resume(struct platform_device *pdev)
{
    pr_dbg("%s\n",__FUNCTION__);
    return 0;
}

static void dvb_widgets_shutdown(struct platform_device *pdev)
{
    pr_dbg("%s\n",__FUNCTION__);
}


static int dvb_widgets_remove(struct platform_device *pdev)
{
    pr_dbg("%s\n",__FUNCTION__);

#ifdef D_SUPPORT_CLASS_INTERFACE    
    class_unregister(&dvb_widgets_class);
#endif

    return 0;
}

static int dvb_widgets_probe(struct platform_device *pdev)
{
    const char *str = NULL;
    int dw_num = 0;
    bool ant_power_overload_one_ping;
    int error = -EINVAL;

    pr_dbg("%s\n",__FUNCTION__);

    //判断节点是否存在
    if (!pdev->dev.of_node) {
        pr_dbg("dvb_widgets pdev->dev.of_node is NULL!\n");
        error = -EINVAL;
        goto get_node_fail;
    }

    // read string
    error = of_property_read_string(pdev->dev.of_node, "dw_name", &str);
    pr_dbg("dw_name:%s\n",str);

    // read u32
    error = of_property_read_u32(pdev->dev.of_node, "dw_num", &dw_num);
    if (error) {
        pr_err("Filed to get  dw_num\n");
    }else{
        pr_dbg("dw_num:%d\n", dw_num);
    }

    // read bool 如果dts文件定义的有ant_power_overload_one_ping此属性:true
    ant_power_overload_one_ping = of_property_read_bool(pdev->dev.of_node, "ant_power_overload_one_ping");
    if (ant_power_overload_one_ping) {
        pr_dbg("ant_power_overload_one_ping : true\n");
    } else {
        pr_dbg("ant_power_overload_one_ping : false\n");
    }


#ifdef CONFIG_OF
    //GPIO读取
    error = of_property_read_string(pdev->dev.of_node, "loops-gpio", &str);
    if (!error) {
        pdw_dev.loops_pin =
            desc_to_gpio(of_get_named_gpiod_flags(pdev->dev.of_node,
                              "loops-gpio", 0, NULL));
        pr_dbg("%s: %s\n", "loops-gpio", str);
    } else {
        pdw_dev.loops_pin = -1;
        pr_dbg("cannot find loops-gpio \n");
    }

    error = of_property_read_string(pdev->dev.of_node, "ch34-gpio", &str);
    if (!error) {
        pdw_dev.ch3_4_pin = 
            desc_to_gpio(of_get_named_gpiod_flags(pdev->dev.of_node,
                            "ch34-gpio", 0, NULL));
        pr_dbg("%s: %s\n", "ch34-gpio", str);
    } else {
        pdw_dev.ch3_4_pin = -1;
        pr_dbg("cannot find ch3_4_gpio\n");
    }

    error = of_property_read_string(pdev->dev.of_node, "ant_power-gpio", &str);
    if (!error) {
        pdw_dev.ant_power_pin =
            desc_to_gpio(of_get_named_gpiod_flags(pdev->dev.of_node,
                            "ant_power-gpio", 0, NULL));
        pr_dbg("ant_power-gpio\n");
    } else {
        pdw_dev.ant_power_pin = -1;
        pr_dbg("cannt find ant_power-gpio\n");
    }

    //申请GPIO
    gpio_request(pdw_dev.ant_power_pin, MODULE_NAME);
    gpio_request(pdw_dev.loops_pin, MODULE_NAME);
    gpio_request(pdw_dev.ch3_4_pin, MODULE_NAME);

    //设置GPIO 上拉状态
    gpio_set_pullup(pdw_dev.ant_power_pin, 1);
    gpio_set_pullup(pdw_dev.loops_pin, 1);
    gpio_set_pullup(pdw_dev.ch3_4_pin, 1);

    //设置GPIO输出电平
    gpio_direction_output(pdw_dev.ant_power_pin, 1); //输出高电平
    gpio_direction_output(pdw_dev.loops_pin, 0); //输出低电平
    gpio_direction_output(pdw_dev.ch3_4_pin, 0); //输出低电平

#else
#endif

    return 0;

get_node_fail:  
    return error;
}




#ifdef CONFIG_OF 
static const struct of_device_id dvb_widgets_match[] = {
    { .compatible  = "amlogic, dvb_widgets"},
    {},
};
#else
#define dvb_widgets_match NULL
#endif


static struct platform_driver dvb_widgets_driver = {
    .probe = dvb_widgets_probe,
    .remove = dvb_widgets_remove,
    .shutdown = dvb_widgets_shutdown,
    .suspend = dvb_widgets_suspend,
    .resume = dvb_widgets_resume,
    .driver = { 
        .name = MODULE_NAME, //设备驱动名
        .of_match_table =   dvb_widgets_match,  
    },
};

static int __init dvb_widgets_init(void)
{
    pr_dbg("%s\n",__FUNCTION__);
    return platform_driver_register(&dvb_widgets_driver);
}

static void __exit dvb_widgets_exit(void)
{
    pr_dbg("%s\n",__FUNCTION__);
    platform_driver_unregister(&dvb_widgets_driver);
}

module_init(dvb_widgets_init);
module_exit(dvb_widgets_exit);


MODULE_AUTHOR("Song YuLong");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("AML DVB Widgets Driver.");
MODULE_AUTHOR("GOOD, Inc.");
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SongYuLong的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值