16244|0

139

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

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

开发平台 芯灵思Sinlinx A64
内存: 1GB   存储: 4GB
详细参数 https://m.tb.cn/h.3wMaSKm
开发板交流群 641395230
此内容由EEWORLD论坛网友babyking原创,如需转载或用于商业用途需征得作者同意并注明出处


全志A64设备树结构体
#include //设备树里的每个设备及每个设备子节点都用此结构体描述
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

gpio = <&pio 1 1 1 1 1 0>;
|            |    |  |   |  |  | |-------------------表示有效电平
|            |    |  |   |  |  |----------------------上下拉, 0关闭功能, 1上拉, 2下拉, 3保留
|            |    |  |   |  |-------------------------驱动力,电流等级(0 - 3),级别越高,输出电流越大
|            |    |  |   |----------------------------gpio功能类型,0输入, 1输出, 6和外部中断,7关闭功能(具体查手册)
|            |    |  |------------------------------pin bank 内偏移(即组内第几个io口).
|            |    |---------------------------------哪组gpio,PA(0),PB(1),PC(2),PD(3),PE(4),PF(5),PG(6),PH(7),PI(8),PJ(9),PK(10),PL(11)
|            |--------------------------------------指向哪个gpio控制器, pio / r_pio(PL组) |-----------------------------------------------------属性名字(随便命名)

驱动代码:

  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/fs.h>
  4. #include <linux/device.h>
  5. #include <linux/slab.h>
  6. #include <linux/cdev.h>
  7. #include <asm/uaccess.h>
  8. #include <linux/io.h>
  9. #include <linux/of.h>
  10. #include <linux/of_gpio.h>
  11. #include <linux/gpio.h>
  12. #include <linux/sys_config.h>

  13. #define MY_DEVICE_NAME "my_led_device"
  14. // 获取到设备树中到节点
  15. static int gpio = -1;
  16. int get_irqno_from_node(void)
  17. {
  18.        
  19.         struct gpio_config config;
  20.         struct device_node *np = of_find_node_by_path("/leds");
  21.         if(np){
  22.                 printk("find node ok\n");
  23.         }
  24.         else{
  25.                 printk("find node failed\n");
  26.         }

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

  38. }

  39. static int my_open (struct inode *node, struct file *filp)
  40. {
  41.     if(gpio)
  42.     {
  43.                 printk("open ok\n");
  44.     }
  45.     else
  46.     {
  47.         return -EINVAL;
  48.     }
  49.     return 0;
  50. }

  51. static ssize_t my_write (struct file *filp, const char __user *buf, size_t size, loff_t *off)
  52. {
  53.     unsigned char val;        
  54.     copy_from_user(&val, buf, 1);
  55.     printk(" gpl_dat address   0x%x\n",gpl_dat);
  56.     if (val)
  57.     {   
  58.                 gpio_direction_output(gpio, 0); //关灯
  59.                 printk("led on\n");
  60.     }
  61.     else
  62.     {
  63.        gpio_direction_output(gpio, 1); //关灯
  64.                 printk("led off\n");
  65.     }

  66.     return 1;
  67. }


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

  73. //step 1 :
  74. static struct class *led_class;
  75. static struct cdev *pcdev;      //定义一个cdev指针
  76. static dev_t n_dev;            //第一个设备号(包含了主和次)
  77. static int __init led_device_init(void)
  78. {//step 2 :注册
  79.     int ret = -1;
  80.     pcdev = cdev_alloc();//分配cdev结构空间
  81.     if(pcdev == NULL) {
  82.         printk(KERN_EMERG" cdev_alloc  error\n");
  83.         ret = -ENOMEM;   /* 分配失败 */
  84.         return ret;
  85.     }
  86.     //2. 动态申请设备号
  87.     ret = alloc_chrdev_region(&n_dev, 0 , 2, MY_DEVICE_NAME);
  88.     if(ret < 0 ) {
  89.         //释放前面成功的资源
  90.         kfree(pcdev);                              /*释放cdev结构空间 */
  91.         printk(KERN_EMERG"alloc_chrdev_region  error\n");
  92.         return ret;
  93.     }   
  94.     cdev_init(pcdev, &my_led_fops);     //初始化cdev结构           /* 建立cdev和file_operations之间的连接 */
  95.     /*
  96.         或这样初始化cdev结构
  97.         pcdev->owner = THIS_MODULE;
  98.         pcdev->ops = &my_led_fops;
  99.     */
  100.     ret = cdev_add(pcdev, n_dev, 2) ;// 向内核里面添加一个驱动,注册驱动
  101.     if(ret < 0 ) {
  102.         //释放前面成功的资源
  103.         unregister_chrdev_region(n_dev,  2);       /*  释放前面申请的调和号*/
  104.         kfree(pcdev);                               /* 释放cdev结构空间 */
  105.         printk(KERN_EMERG"alloc_chrdev_region  error\n");
  106.         return ret;
  107.     }

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

  111.         get_irqno_from_node();
  112.     printk(KERN_EMERG"cdev ok\n");   
  113.     return 0;
  114. }

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

  117.     //注销cdev结构
  118.     cdev_del(pcdev);
  119.     //释放设备号
  120.     unregister_chrdev_region(n_dev, 2); /*起始设备号(主、次) 连续的次设备号数量*/
  121.     //释放cdev结构空间
  122.     kfree(pcdev);
  123.    
  124.     device_destroy(led_class, n_dev);
  125.     class_destroy(led_class);
  126.     gpio_free(gpio);
  127.     printk(KERN_EMERG"cdev_del ok\n");
  128. }

  129. module_init(led_device_init);
  130. module_exit(led_device_exit);
  131. MODULE_LICENSE("GPL");
复制代码





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

点赞 关注

回复
举报
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表