Linux中的pinctrl和gpio子系统

举报
万里羊 发表于 2021/08/24 23:57:24 2021/08/24
【摘要】        基于设备树的Linux驱动其本质就是配置LED灯所使用的的GPIO寄存器,驱动开发方式和逻辑基本没啥区别。Linux是一个庞大和完善的系统,尤其...

       基于设备树的Linux驱动其本质就是配置LED灯所使用的的GPIO寄存器,驱动开发方式和逻辑基本没啥区别。Linux是一个庞大和完善的系统,尤其是驱动的框架,像GPIO这种最基本的驱动不可能采用“原始”的裸机驱动开发方式,否则就像我买了一辆自行车,结果每天推着自行车去上班。Linux内核提供了pinctrl和gpio子系统用于GPIO驱动,我们学会了pinctrl和gpio子系统就相当于学会了骑自行车的本领,来简化GPIO驱动开发。
       Linux驱动讲究驱动分离和分层,pinctrl和gpio子系统就是驱动分离与分层思想下的产物,驱动分离与分层就是按照面向对象编程的设计思想而设计的设备驱动框架。而pinctrl子系统重点是设置PIN(SOC或者PAD)的复用和电气属性,如果将pinctrl子系统将一个PIN服用为GPIO的话,接下来就需要用到GPIO子系统了。gpio子系统顾名思义就是用于初始化GPIO并且提供相应的API函数,比如设置GPIO为输入或者输出,读取GPIO的值等功能。
往期推荐:
       Linux设备树是什么?
       Linux字符设备驱动开发(2)——让开发板上的灯闪烁

文章目录

pinctrl子系统驱动

       基于设备树的LED灯驱动所使用的GPIO的步骤总结如下:

  • 修改设备树,添加设备树,添加相关的节点,节点里面设置reg属性,reg属性包括了GPIO相关的寄存器。
    1. #include <linux/fs.h>
  1. #include <linux/errno.h>

  2. #include <asm/current.h>

  3. #include <linux/sched.h> 35. MODULE_LICENSE(“GPL”);

static int major = 0;

  1. static int minor = 0;

  2. const int count = 3;

  3. #define DEVNAME “demo”

  4. static struct cdev *demop = NULL;

  5. //打开设备

  6. static int demo_open(struct inode *inode, struct file *filp)

  7. {

  8. printk(KERN_INFO “(%s:pid=%d), %s : %s : %d\n”, current->comm, current->pid, FILE, func, LINE);

  9. printk(KERN_INFO “(major=%d, minor=%d), %s : %s : %d\n”, imajor(inode), iminor(inode), FILE, func,

LINE);

  1. return 0;

  2. }

  3. static int demo_release(struct inode *inode, struct file *filp)

  4. {

printk(KERN_INFO “(%s:pid=%d), %s : %s : %d\n”, current->comm, current->pid, FILE, func, LINE);

  1. printk(KERN_INFO “(major=%d, minor=%d), %s : %s : %d\n”, imajor(inode), iminor(inode), FILE, func,

LINE);

  1. return 0;

  2. }

  3. //读设备

  4. static ssize_t demo_read(struct file *filp, char __user *buf, size_t size, loff_t *offset)

  5. {

  6. struct inode *inode = filp->f_path.dentry->d_inode;

printk(KERN_INFO “(%s:pid=%d), %s : %s : %d\n”, current->comm, current->pid, FILE, func, LINE);

  1. printk(KERN_INFO “(major=%d, minor=%d), %s : %s : %d\n”, imajor(inode), iminor(inode), FILE, func,

LINE);

  1. return 0;

  2. }

  3. //写设备

  4. static ssize_t demo_write(struct file *filp, const char __user *buf, size_t size, loff_t *offset)

  5. {

  6. struct inode *inode = filp->f_path.dentry->d_inode;

  7. printk(KERN_INFO “(%s:pid=%d), %s : %s : %d\n”, current->comm, current->pid, FILE, func, LINE);

printk(KERN_INFO “(major=%d, minor=%d), %s : %s : %d\n”, imajor(inode), iminor(inode), FILE, func,

LINE);

  1. return 0;

  2. }

  3. //操作方法集

static struct file_operations fops = {

  1. .owner = THIS_MODULE, .open = demo_open,

  2. .release= demo_release,

  3. .read = demo_read,

  4. .write = demo_write,

};

  1. //cdev 设备模块初始化 79. static int __init demo_init(void)

  2. {

dev_t devnum; int ret;

  1. printk(KERN_INFO “(%s:pid=%d), %s : %s : %d\n”, current->comm, current->pid, FILE, func, LINE);

  2. demop = cdev_alloc();

  3. if(NULL == demop)

  4. {

return -ENOMEM;

  1. }

  2. cdev_init(demop, &fops);

  3. ret = alloc_chrdev_region(&devnum, minor, count, DEVNAME);

if(ret){

goto ERR_STEP;

  1. }

  2. major = MAJOR(devnum);

ret = cdev_add(demop, devnum, count);

  1. if(ret){

goto ERR_STEP1;

  1. }

printk(KERN_INFO “(%s:pid=%d), %s : %s : %d - ok.\n”, current->comm, current->pid, FILE, func,

LINE);

return 0;

ERR_STEP1:

unregister_chrdev_region(devnum, count);

ERR_STEP:

cdev_del(demop);

printk(KERN_INFO “(%s:pid=%d), %s : %s : %d - fail.\n”, current->comm, current->pid, FILE, func,

LINE);

return ret;

}

static void __exit demo_exit(void)

{

printk(KERN_INFO “(%s:pid=%d), %s : %s : %d - leave.\n”, current->comm, current->pid, FILE, func,

LINE);

unregister_chrdev_region(MKDEV(major, minor), count);

cdev_del(demop);

}

module_init(demo_init);

  1. module_exit(demo_exit);

头文件 #include <linux/cdev.h> #include <linux/fs.h> Cdev 结构体 声明在 linux/cdev.h struct cdev {

struct kobject kobj; //主要是 kobj 的赋值 struct module *owner; //外部制定 THIS_MODULE struct file_operations *ops; //操作文件袋函数指针数组

struct list_head list;

//list 为了遍历,建立连接

}; 操作函数 void cdev_init(struct cdev *, struct file_operations *); struct cdev *cdev_alloc(void); int cdev_add(struct cdev *, dev_t, unsigned); void cdev_del(struct cdev *);

接口解析:

描述 Cdev 初始化 申请内存 添加 cdev 删除 cdev

主要是对 cdev 的操作;外部需要把结构体的 owner 和 ops 成员变量赋值; 利用接口函数 cdev_init 和 cdev_add 来添加到系统内核中; 用函数 cdev_del 删除设备;

需要声明一个 cdev 节点; static struct cdev *demop = NULL; //主要是通过 cdev 实现自己的文件操作,然后 cdev 挂载到系统中;

文章来源: wlybsy.blog.csdn.net,作者:万里羊,版权归原作者所有,如需转载,请联系作者。

原文链接:wlybsy.blog.csdn.net/article/details/113694962

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。