芯灵思Sinlinx A64 linux 通过设备树写LED驱动(附参考代码,未测试)

开发平台 芯灵思Sinlinx A64

内存: 1GB 存储: 4GB
详细参数 https://m.tb.cn/h.3wMaSKm
开发板交流群 641395230

全志A64设备树结构体

#include <linux/of.h> //设备树里的每个设备及每个设备子节点都用此结构体描述

struct device_node
{
    const char *name;
    const char *type;
    phandle phandle;
    const char *full_name;
    struct property *properties; //属性
    struct property *deadprops; /* removed properties */
    struct device_node *parent; //在设备子节点对象,指向属于的设备对象
    struct device_node *child; //在设备对象,指向子节点
    struct device_node *sibling; //指向同级的下一个对象.
    struct device_node *next; /* next device of same type */ //应是指向device_type是同样的对象
    struct device_node *allnext; /* next in list of all nodes */ ...
};

//下面函数用于获取设备树里的设备节点及设备子节点
extern struct device_node *of_find_node_by_name(struct device_node *from, const char *name);
//通过名字查找相应的设备节点
static inline int of_get_child_count(const struct device_node *np);
//获取指定设备的子节点个数
extern struct device_node *of_find_node_by_path(const char *path);
//通过路径来获取设备节点,可用于获取设备子节点
extern struct device_node *of_find_node_by_type(struct device_node *from, const char *type); //通过指定的device_type来获取设备节点

//下面函数用于获取设备节点或设备子节点的属性

static inline int of_property_read_u32(const struct device_node *np, const char *propname, u32 *out_value)
extern int of_property_read_u32_index(const struct device_node *np, const char *propname, u32 index, u32 *out_value);
extern int of_property_read_u8_array(const struct device_node *np, const char *propname, u8 *out_values, size_t sz);
extern int of_property_read_u16_array(const struct device_node *np, const char *propname, u16 *out_values, size_t sz);
extern int of_property_read_u32_array(const struct device_node *np, const char *propname, u32 *out_values, size_t sz);
extern int of_property_read_u64(const struct device_node *np, const char *propname, u64 *out_value);
extern int of_property_read_string(struct device_node *np, const char *propname, const char **out_string)

首先增加节点,修改dtsi文件。
vim /lichee/linux-3.10/arch/arm64/boot/dts/sun50iw1p1-pinctrl.dtsi

驱动代码:

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/fs.h>
    #include <linux/device.h>
    #include <linux/slab.h>
    #include <linux/cdev.h>
    #include <asm/uaccess.h>
    #include <linux/io.h>
    #include <linux/of.h>
    #include <linux/of_gpio.h>
    #include <linux/gpio.h>
    #include <linux/sys_config.h>  

    #define MY_DEVICE_NAME "my_led_device"
    // 获取到设备树中到节点
    static int gpio = -1;
    int get_irqno_from_node(void)
    {  

        struct gpio_config config;
        struct device_node *np = of_find_node_by_path("/leds");
        if(np){
            printk("find node ok\n");
        }
        else{
            printk("find node failed\n");
        }  

        gpio = of_get_named_gpio_flags(nd, "gpios", i, (enum of_gpio_flags *)&config);// 从设备树中读取gpios的GPIO配置编号和标志
        if(!gpio_is_valid(gpio)){
            //判断该 GPIO 编号是否有效,有效gpio_request 则申请占用该 GPIO。如果初始化过程出错,需要调用 gpio_free 来释放之前申请过且成功的 GPIO
            printk("gpio isn‘t valid\n");
            return -1;
        }
        if(gpio_request(gpio, "leds") < 0)
            printk("gpio request failed %d\n", gpio);
        gpio_direction_output(gpio, 1); //关灯  

        return 0;   

    }  

    static int my_open (struct inode *node, struct file *filp)
    {
        if(gpio)
        {
            printk("open ok\n");
        }
        else
        {
            return -EINVAL;
        }
        return 0;
    }  

    static ssize_t my_write (struct file *filp, const char __user *buf, size_t size, loff_t *off)
    {
        unsigned char val;
        copy_from_user(&val, buf, 1);
        printk(" gpl_dat address   0x%x\n",gpl_dat);
        if (val)
        {
            gpio_direction_output(gpio, 0); //关灯
            printk("led on\n");
        }
        else
        {
           gpio_direction_output(gpio, 1); //关灯
            printk("led off\n");
        }  

        return 1;
    }  

    static const struct file_operations my_led_fops = {
        //step 1 :定义file_operations结构体
        .open = my_open,
        .write = my_write,
    };  

    //step 1 :
    static struct class *led_class;
    static struct cdev *pcdev;      //定义一个cdev指针
    static dev_t n_dev;            //第一个设备号(包含了主和次)
    static int __init led_device_init(void)
    {//step 2 :注册
        int ret = -1;
        pcdev = cdev_alloc();//分配cdev结构空间
        if(pcdev == NULL) {
            printk(KERN_EMERG" cdev_alloc  error\n");
            ret = -ENOMEM;   /* 分配失败 */
            return ret;
        }
        //2. 动态申请设备号
        ret = alloc_chrdev_region(&n_dev, 0 , 2, MY_DEVICE_NAME);
        if(ret < 0 ) {
            //释放前面成功的资源
            kfree(pcdev);                              /*释放cdev结构空间 */
            printk(KERN_EMERG"alloc_chrdev_region  error\n");
            return ret;
        }
        cdev_init(pcdev, &my_led_fops);     //初始化cdev结构           /* 建立cdev和file_operations之间的连接 */
        /*
            或这样初始化cdev结构
            pcdev->owner = THIS_MODULE;
            pcdev->ops = &my_led_fops;
        */
        ret = cdev_add(pcdev, n_dev, 2) ;// 向内核里面添加一个驱动,注册驱动
        if(ret < 0 ) {
            //释放前面成功的资源
            unregister_chrdev_region(n_dev,  2);       /*  释放前面申请的调和号*/
            kfree(pcdev);                               /* 释放cdev结构空间 */
            printk(KERN_EMERG"alloc_chrdev_region  error\n");
            return ret;
        }  

        /*自动创建设备节点/dev/SinlinxA64_LED*/
        led_class = class_create(THIS_MODULE, "myled");
        device_create(led_class, NULL, n_dev, NULL, "SinlinxA64_LED");   

        get_irqno_from_node();
        printk(KERN_EMERG"cdev ok\n");
        return 0;
    }  

    static void __exit led_device_exit(void)
    {    //step 2 :注销  

        //注销cdev结构
        cdev_del(pcdev);
        //释放设备号
        unregister_chrdev_region(n_dev, 2); /*起始设备号(主、次) 连续的次设备号数量*/
        //释放cdev结构空间
        kfree(pcdev);  

        device_destroy(led_class, n_dev);
        class_destroy(led_class);
        gpio_free(gpio);
        printk(KERN_EMERG"cdev_del ok\n");
    }  

    module_init(led_device_init);
    module_exit(led_device_exit);
    MODULE_LICENSE("GPL");  

参考文章:https://blog.csdn.net/jklinux/article/details/82382066

原文地址:https://blog.51cto.com/14199070/2359688

时间: 2024-10-11 22:33:56

芯灵思Sinlinx A64 linux 通过设备树写LED驱动(附参考代码,未测试)的相关文章

芯灵思Sinlinx A64 Linux&amp;qt编译安装

开发平台 芯灵思Sinlinx A64 内存: 1GB 存储: 4GB 详细参数 https://m.tb.cn/h.3wMaSKm 开发板交流群 641395230 前提条件搭建好CentOS环境 光盘目录 :芯灵思SIN-A64光盘资料\Linux & QT\source 将这些光盘资料拷贝到虚拟机解压 tar -xvf SINLINX-A64_lichee-src.tar.gz tar -xvf SINLINX_qt-4.8.7_src.tar.gz tar -xvf SINLINX_qt

芯灵思Sinlinx A64开发板 Linux内核等待队列poll ---阻塞与非阻塞

开发平台 芯灵思Sinlinx A64内存: 1GB 存储: 4GB开发板详细参数 https://m.tb.cn/h.3wMaSKm开发板交流群 641395230 阻塞:阻塞调用是指调用结果返回之前,当前进程程会被挂起(休眠).函数只有在得到结果之后才会返回.默认情况下,文件都是以这种方式打开.非阻塞:指在不能立刻得到结果之前,该函数不会阻塞当前进程程,而会立刻返回.应用程序可选择以阻塞或非阻塞方式打开设备文件,然后设备进行读写操作,如果驱动的读写函数支持阻塞和非阻塞功能,这两种打开方式才会

芯灵思Sinlinx A64 开发板移植SQLite3

开发平台 芯灵思Sinlinx A64 内存: 1GB 存储: 4GB 开发板详细参数 https://m.tb.cn/h.3wMaSKm 开发板交流群 641395230 首先到 http://www.sqlite.org/download.html 下载linux版本的源码 我下载的是 sqlite-autoconf-3270200.tar.gz 新建目录 /work/install 用于存放后来生成的lib库函数和可执行文件 解压缩tar -zxvf sqlite-autoconf-327

Linux内核 设备树操作常用API【转】

本文转载自:http://www.cnblogs.com/xiaojiang1025/p/6368260.html Linux设备树语法详解一文中介绍了设备树的语法,这里主要介绍内核中提供的操作设备树的API,这些API通常都在"include/of.h"中声明. device_node 内核中用下面的这个结构描述设备树中的一个节点,后面的API都需要一个device_node对象作为参数传入. //include/of.h 46 struct device_node { 47 con

Linux 获取设备树源文件(DTS)里描述的资源【转】

转自:http://www.linuxidc.com/Linux/2013-07/86839.htm 转自:http://blog.sina.com.cn/s/blog_636a55070101mced.html 在linux使用platform_driver_register() 注册  platform_driver 时, 需要在 platform_driver 的probe() 里面知道设备的中断号, 内存地址等资源. 这些资源的描述信息存放在 resource 数据结构中, 相同的资源存

基于设备树的led驱动程序

1 #include <linux/module.h> 2 #include <linux/kernel.h> 3 #include <linux/fs.h> 4 #include <linux/init.h> 5 #include <linux/delay.h> 6 #include <asm/io.h> 7 #include <linux/cdev.h> 8 #include <linux/device.h>

Linux设备树语法详解

Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离.在设备树出现以前,所有关于设备的具体信息都要写在驱动里,一旦外围设备变化,驱动代码就要重写.引入了设备树之后,驱动代码只负责处理驱动的逻辑,而关于设备的具体信息存放到设备树文件中,这样,如果只是硬件接口信息的变化而没有驱动逻辑的变化,驱动开发者只需要修改设备树文件信息,不需要改写驱动代码.比如在ARM Linux内,一个.dts(device tree source)文件对应一个ARM的machine,一般放置在内核的

Linux设备树语法详解【转】

本文转载自:http://www.cnblogs.com/xiaojiang1025/p/6131381.html 概念 Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离.在设备树出现以前,所有关于设备的具体信息都要写在驱动里,一旦外围设备变化,驱动代码就要重写.引入了设备树之后,驱动代码只负责处理驱动的逻辑,而关于设备的具体信息存放到设备树文件中,这样,如果只是硬件接口信息的变化而没有驱动逻辑的变化,驱动开发者只需要修改设备树文件信息,不需要改写驱动代码.比如在AR

我眼中的Linux设备树(一 概述)

一 概述 设备树(Device tree)是一套用来描述硬件属相的规则.ARM Linux采用设备树机制源于2011年3月份Linux创始人Linus Torvalds发的一封邮件,在这封邮件中他提倡ARM平台应该参考其他平台如PowerPC的设备树机制描述硬件.因为在此之前,ARM平台还是采用旧的机制,在kernel/arch/arm/plat-xxx目录和kernel/arch/arm/mach-xxx目录下用代码描述硬件,如注册platform设备,声明设备的resource等.因为这些代