全志 A64 linux 通过设备树写LED驱动(附参考代码)-阿里云开发者社区

开发者社区> xiaobai12568> 正文

全志 A64 linux 通过设备树写LED驱动(附参考代码)

简介: 开发平台 芯灵思Sinlinx A64 内存: 1GB 存储: 4GB详细参数 https://m.tb.cn/h.3wMaSKm开发板交流群 641395230 全志A64设备树结构体 #include <linux/of.
+关注继续查看

开发平台 芯灵思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

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
嵌入式linux产品USB设备动态监控技术研究
  嵌入式linux产品USB设备动态监控技术研究   笔者最近在做PVR项目的开发工作,涉及到使用移动硬盘作为刻录节目的存储空间。
736 0
全志 A64 linux 通过设备树写LED驱动(附参考代码)
开发平台 芯灵思Sinlinx A64 内存: 1GB 存储: 4GB详细参数 https://m.tb.cn/h.3wMaSKm开发板交流群 641395230 全志A64设备树结构体 #include <linux/of.
2571 0
visual studio编写C#代码时“未能从程序集.....中加载类型”和“找不到方法”的一种可能的解决办法
编译前报错:$exception    {"未能从程序集“XSW.MySQLDAL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”中加载类型“XSW.MySQLDAL.EnterpriseLibraryProductDAL”。
1256 0
为什么java linkkit网关重启必须要调用添加设备方法
思考 : 控制台存在topo关系还需要调用添加设备方法吗? 添加设备接口做了那些事
155 0
ios监听输出设备变化(监听耳机插拔,蓝牙设备连接断开等)的实现
 在ios6以前,我们有如下的方法: #import       [[AVAudioSession sharedInstance] setDelegate:self];   AudioSessionAddPro...
1374 0
+关注
15
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载