Linux驱动学习—pinctl和gpio子系统

1、pinctl和gpio子系统(一)

1.1pinctrl 子系统主要工作内容

<1>获取设备树中 pin 信息,管理系统中所有的可以控制的 pin, 在系统初始化的时候, 枚举所有可以控制的 pin, 并标识这些 pin。
<2>根据获取到的 pin 信息来设置 pin 的复用功能,对于 SOC 而言, 其引脚除了配置成普通的 GPIO 之外,若干个引脚还可以组成一个 pin group, 形成特定的功能。
<3>根据获取到的 pin 信息来设置 pin 的电气特性,比如上/下拉、速度、驱动能力等。

对应使用者来说,只需要在设备树里面设置好某个 pin 的相关属性即可,其他的初始化工作均由 pinctrl 子系统来完成。

1.2gpio子系统主要工作内容

当使用 pinctrl 子系统将引脚的复用设置为 GPIO,可以使用 GPIO 子系统来操作GPIO,Linux 内核提供了 pinctrl 子系统和 gpio 子系统用于 GPIO 驱动。

通过 GPIO 子系统功能要实现:

<1>引脚功能的配置(设置为 GPIO,GPIO 的方向, 输入输出模式,读取/设置 GPIO 的值)
<2>实现软硬件的分离(分离出硬件差异, 有厂商提供的底层支持; 软件分层。 驱动只需要调用接口 API 即可操作 GPIO)
<3>iommu 内存管理(直接调用宏即可操作 GPIO)

gpio 子系统的主要目的就是方便驱动开发者使用 gpio,驱动开发者在设备树中添加 gpio 相关信息,然后就可以在驱动程序中使用 gpio 子系统提供的 API函数来操作 GPIO, Linux 内核向驱动开发者屏蔽掉了 GPIO 的设置过程,极大的方便了驱动开发者使用 GPIO。

1.3 不同soc厂家的pin contrller的节点

这些节点都是把某些引脚复用成功能。

1.4 不同soc厂家的pin contrller的节点里面的属性都是什么意思

可以通过在Documentation/devicetree/bindings/下的txt文档查看。

1.5 怎么在代码中使用pin contrller里面定义好的节点?

例1:

pinctrl-names = "default";//设备的状态,可以有多种状态,default为状态0
pinctrl-0 = <&pinctrl_hog_1>;/*第0个状态所对应的引脚配置,也就是default状态对应的引脚在pin controller里面定义好的节点pinctrl_hog_1里面的管脚配置。*/

例2:

pinctrl-names = "default","wake up";//设备的状态,可以有多种状态,default为状态0,wake up为状态1,
pinctrl-0 = <&pinctrl_hog_1>;/*第0个状态所对应的引脚配置,也就是default状态对应的引脚在pin controller里面定义好的节点pinctrl_hog_1里面的管脚配置。*/
pinctrl-1 = <&pinctrl_hog_2>;/*第1个状态所对应的引脚配置,也就是default状态对应的引脚在pin controller里面定义好的节点pinctrl_hog_2里面的管脚配置。*/

例3:

pinctrl-names = "default";//设备的状态,可以有多种状态,default为状态0,wake up为状态1,
pinctrl-0 = <&pinctrl_hog_1   &pinctrl_hog_2>;/*第0个状态所对应的引脚配置,也就是default状态对应的引脚在pin controller里面定义好的节点pinctrl_hog_1和pinctrl_hog_2这两个节点的管脚配置。*/

1.6 总结

总结:之前控制引脚的方法都是操作配置寄存器:

现在可以不用这种方法,linux有现成的框架,这个框架就是pinctl子系统和gpio子系统,可以pinctl子系统设置引脚的复用功能,设置引脚的电气属性。

2、pinctl和gpio子系统(二)

上一个小节我们学习了pinctrl子系统,Linux内核提供了pinctrl子系统和gpio子系统用于GPIO驱动,当然pinctrl子系统负责不仅仅是GPIO的驱动,而是所有pin脚配置。pinctrl子系统是随着设备树的加入而加入的,依赖设备树。GPIO子系统在之前的内核也是存在的,但是pinctrl子系统的加入使得GPIO子系统有很大的改变。

在以前的内核版本中,如果要配置GPIO的话一般要使用SOC厂家实现的配置函数,例如三星的配置函数s3c_gpio_cfgpin等,这样带来的问题就是各家有个家的接口函数与是实现方式,不但内核的代码复用率低而且开发者很难记住这么多的函数,如果要使用多种平台的话背函数都是很麻烦的,所以在引入设备树后对GPIO子系统进行大的改造,使用设备树来实现并提供统一的接口。通过GPIO子系统功能主要实现引脚功能的配置,如设置为GPIO,特殊功能,GPIO的方向,设置为中断等。

那么我们先来看一下怎么在设备树中pinctrl和gpio子系统描述一个gpio。

2.1 设备树使用pinctrl和gpio子系统描述一个gpio

test1:test{
    #address-cells = <1>;
    #size-cells = <1>;
    
    compatible = "test";
    reg = <0x20ac000 0x00000004>;//描述数据寄存器的地址
    
    pinctrl-names = "default";
    pintrl-0 = <&pinctrl_test>;
    test-gpio = <gpio1 3 GPIO_ACTICE_LOW>;//gpio 表示第一组,3表示第一组第三个引脚,GPIO_ACTICE_LOW表示低电平
};

2.2 常用的gpio子系统提供的api函数

这些函数的定义在include\linux\gpio.h

2.2.1 gpio_request函数

作用: gpio_request函数用于申请一个gpio管脚。

int gpio_request(unsigned gpio, const char *label)
参数:
gpio:要申请的gpio标号,使用of_get_named_gpio函数从设备树获取指定的GPIO属性信息,此函数会返回这个GPIO标号。
label:给gpio设置个名字。
返回值:0,申请成功,其他值申请失败。
2.2.2 gpio_free函数

作用:如果不使用某个GPIO了,那么就可以调用gpio_free函数进行释放。

void gpio_free(unsigned gpio);
参数:
gpio:要释放的gpio标号。
返回值:无
2.2.3 gpio_direction_input函数

作用:此函数用于设置某个GPIO为输入。

int gpio_direction_input(unsigned gpio);
参数:
gpio:要设置为输入的GPIO标号。
返回值:0,设置成功,其他值设置失败。
2.2.4gpio_direction_output函数

作用:此函数用于设置某个GPIO为输出,并且设置默认输出值。

int gpio_direction_output(unsigned gpio, int value);
参数:
gpio:要设置为输出的GPIO标号。
value:GPIO默认输出值。
返回值:0,设置成功,设置失败返回负值。
2.2.5 gpio_get_value函数

作用:此函数用于获取某个GPIO的值(0或1)

int gpio_get_value(unsigned int gpio);
gpio:要获取的gpio标号
返回值:0,成功,失败返回负值。
2.2.5 gpio_set_value函数

作用:此函数用于获取某个GPIO的值(0或1)

void gpio_set_value(unsigned int gpio, int value);
gpio:要设置的gpio标号
value:要设置的值。
返回值:无。

2.3 总结

pinctl子系统的作用就是设置引脚的复用功能和电气属性。gpio子系统就是当pinctl子系统把引脚设置成GPIO功能以后就可以使用gpio子系统来操作我们引脚了,比如说设置输入、输出或者引脚的高低电平等等。

3、pinctl和gpio子系统(三)

pinctrl子系统就是设置引脚的复用关系和电气属性,gpio子系统就是当pinctrl把引脚设置成设置为gpio以后我们使用gpio子系统来操作gpio。

3.1 引脚的宏定义是在哪里找的

在arch/arm/boot/dts/imx6ul-pinfunc.h:

每个宏定义都对应一个管脚的复用功能。一个引脚有怎么多复用功能,但是只能使能一个,所以在设备树下需要检察是否有其他复用功能被使用,有就需要在设备树文件其他使用的地方注释掉:

3.2 实验

Linux驱动学习—设备树及设备树下的platform总线-CSDN博客

实现设备树学习中的7.3未实现的部分,即在probe函数注册一个杂项设备驱动用于对蜂鸣器的操作。这里对引脚的操作不是相之前一样对地址寄存器的操作实现gpio电平值的改变,而是通过gpio子系统的api函数是实现。

3.2.1 设备树文件修改

3.2.2 实验代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h> 
#include <linux/of.h>
#include <linux/of_address.h>
​
struct device_node *test_device_node;
struct property *test_node_property;
int size;
u32 out_values[2]={0};
const char *str=NULL;
unsigned int *vir_gpio_dr;
int beep_gpio = 0;
​
static const of_device_id of_match_table_test[] = {//匹配表
    {.compatible = "test1234"},
};
​
static const platform_device_id beep_id_table ={
    .name = "beep_test",
};
​
int misc_open(struct inode *inode, struct file *file)
{
    printk("misc_open\n");
    return 0;
}
​
int misc_release(struct inode *inode, struct file *file)
{
    printk("misc_relese\n");
    return 0;
}
​
ssize_t misc_read(struct file *file,char __user *ubuf, size_t size, loff_t *loff_t)
{
    char kbuf[64] = "heheh";
    
    if(copy_to_user(ubuf, kbuf, strlen(kbuf)) != 0) {
        printk("copy_to_user error\n");
        return -1;
    }
    return 0;
}
​
ssize_t misc_wirie(struct file *file,char __user *ubuf, size_t size, loff_t *loff_t)
{
    char kbuf[64] = {0};
    
    if(copy_form_user(kbuf, ubuf, strlen(kbuf)) != 0) {
        printk("copy_form_user error\n");
        return -1;
    }
    printk("kbuf is %s\n",kbuf);
    
    if(kbuf[0] == 1)
        get_set_value(beep_gpio, 1);
    else if(kbuf[0] == 0)
        get_set_value(beep_gpio, 0);
    
    return 0;
}
​
struct file_operations misc_fops = {
    .owner      = THIS_MODULE,
    .open       = misc_open,
    .release    = misc_release,
    .write      = misc_wirie,
    .read       = misc_read
};
​
struct miscdevice misc_dev = {
    .minor = MISC_DYNAMIC_MINOR,
    .name  = hello_misc,
    .fops  = &misc_fops
};
​
/*设备树节点compatible属性与of_match_table_test的compatible相匹配就会进入该函数,pdev是匹配成功后传入的设备树节点*/
int beep_probe(struct platform_device *pdev)
{
    int ret = 0;
    printk("beep_probe\n");
    
    //查找要查找的节点
    test_device_node = of_find_node_by_path("/test");
    if (test_device_node == NULL) {
        printk("test_device_node find error\n");
        return -1;
    }
    printk("test_device_node name is %s\n",test_device_node->name);//test
    
    beep_gpio = of_get_named_gpio(test_device_node, "beep-gpio", 0);
    if (beep_gpio < 0) {
        printk("of_get_named_gpio error\n");
        return -1;
    }
    printk("beep_gpio name is %d\n",beep_gpio);
    
    ret = gpio_request(beep_gpio, "beep");
    if (ret < 0) {
        printk("gpio_request error\n");
        return -1;
    }
    
    ret = misc_register(&misc_dev);
    if (ret < 0) {
        printk("misc_register error\n");
        return -1;
    }
    
    return 0;
}
​
int beep_remove(struct platform_device *pdev)
{
    pritnk("beep_remove \n");
    return 0;
}
​
strcut platform_driver beep_device = {
    .probe = beep_probe,
    .remove = beep_remove,
    .driver = {
        .owner = THIS_MODULE,
        .name  = "123",
        .of_match_table = of_match_table_test,//匹配表 
    },
    .id_table = &beep_id_table,
};
​
static int beep_driver_init(void)
{
    int ret = -1;
    ret = platform_driver_register(&beep_device);
    if(ret < 0) {
        printk("platform_driver_register error \n");
    }
    printk("platform_driver_register ok\n");
    return 0;
}
​
static void  beep_driver_exit(void)
{
    platform_driver_unregister(&beep_device);
    printk("beep_driver_exit \n");
}
​
module_init(beep_driver_init);
module_exit(beep_driver_exit);
MODULE_LICENSE("GPL");

加载驱动,可以看到杂项设备节点生成,对这个设备节点写入1就表示引脚电平设置为高,,对这个设备节点写入0就表示引脚电平设置为低,

echo 1 > /dev/hello_misc
echo 0 > /dev/hello_misc

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/283116.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

burpsuite模块介绍之compare

导语 Burp Comparer是Burp Suite中的一个工具&#xff0c;主要提供一个可视化的差异比对功能&#xff0c;可以用于分析比较两次数据之间的区别。它的应用场景包括但不限于&#xff1a; 枚举用户名过程中&#xff0c;对比分析登陆成功和失败时&#xff0c;服务器端反馈结果的区…

python脚本实现一次提取多个文件下的图片

problem formulation 有时候下载的数据集如下&#xff0c;就很烦&#xff0c;一个里面就一张图片 code import os import shutil# 定义源目录和目标目录 source_dir ./dataset/data/Detection destination_dir ./dataset/data/img# 确保目标目录存在&#xff0c;如果不存…

初识大数据,一文掌握大数据必备知识文集(7)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

pycharm python环境安装

目录 1.Python安装 2.PyQt5介绍 3.安装pyuic 4.启动designer.exe 5.pyinstaller(打包发布程序) 6.指定源安装 7.PyQt5-tools安装失败处理 8.控件介绍 9.错误记录 1.NameError: name reload is not defined 10.开发记录 重写报文输出和文件 ​编辑 1.Python安装 点…

BFS

目录 BFS 走迷宫 BFS 算法特点 优先考虑宽度&#xff0c;换句话说就是按层推进&#xff0c;直到最后一层。 空间复杂度&#xff1a;O&#xff08;2^h&#xff09; BFS是按宽度搜索&#xff0c;所以可以找到最短路&#xff0c;适用于解决像最短路&#xff0c;最少之类的问题…

Python装饰器的专业解释

装饰器&#xff0c;其实是用到了闭包的原理来进行操作的。 单个装饰器&#xff1a; 以下是一个简单的例子&#xff1a; def outer(func):print("OUTER enter ...")def wrapper(*args, **kwargs):print("调用之前......")result func(*args, **kwargs)p…

【YOLO系列】yolo V1 ,V3,V5,V8 解释

文章目录 yolo V1 模型结构图通道数 的 物理意义是什么&#xff1f;输出 7730 怎么理解&#xff1f;YOLO v1 损失函数LOSS yolo V3yolo V5yolo V8 视频来源&#xff1a;https://www.bilibili.com/video/BV13K411t7Zs/ AI视频小助理 一、YOLO系列的目标检测算法&#xff0c;其中…

【操作系统】存储器管理

目录 4.1 存储器的层次结构 4.1.1 多级存储结构 4.1. 2 可执行存储器 4.1.3 高速缓存和磁盘缓存 4.2 程序的装入和链接 4.2.1 程序的装入 4.2.2 程序的链接 1.静态链接(Static Linking)方式 (1) 对相对地址进行修改。 (2) 变换外部调用符号。 2. 装入时动态链接(Load-t…

CodeWave赋能创新的全功能技术平台

目录 前言1 应用中心2 资产中心&#xff1a;汇聚创新能量&#xff0c;提供开发加速3 集成中心3.1 API管理3.2 报表管理 4 运维中心4.1 资源监控4.2 用户管理4.3 权限管理4.4 日志与监控 5 配置中心5.1 源码配置5.2 镜像仓库配置5.3 数据库配置5.4 报表配置5.5 资产配置5.6 品牌…

JavaFX:MVC模式学习01-使用PropertyValueFactory将模型与视图绑定

PropertyValueFactory类是“TableColumn cell value factory”,绑定创建列表中的项。示例如下&#xff1a; TableColumn<Person,String> firstNameCol new TableColumn<Person,String>("First Name");firstNameCol.setCellValueFactory(new PropertyVal…

安装torch(GPU版本)并在Pycharm中配置

零.前置环境 1.NVIDIA GPU Computing Toolkit已安装 版本为&#xff1a;11.6 已添加到环境变量 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6\bin C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6\libnvvp 在cmd中查看cuda版本 方法1&#xff1a…

详解Vue3中的鼠标事件mousemove、mouseover和mouseout

本文主要介绍Vue3中的常见鼠标事件mousemove、mouseover和mouseout。 目录 一、mousemove——鼠标移动事件二、mouseover——鼠标移入事件三、mouseout——鼠标移出事件 下面是Vue 3中常用的鼠标事件mousemove、mouseover和mouseout的详解。 一、mousemove——鼠标移动事件 鼠…

图神经网络--GNN从入门到精通

图神经网络--GNN从入门到精通 一、图的基本表示和特征工程1.1 什么是图1.2 图的基本表示1.3 图的性质--度&#xff08;degree)1.4 连通图&#xff0c;连通分量1.5有向图连通性1.6图直径1.7度中心性1.7特征中心性&#xff08; Eigenvector Centrality&#xff09;1.8中介中心性 …

年度总结 | 回味2023不平凡的一年

目录 前言1. 平台成就2. 自我提升3. Bug连连4. 个人展望 前言 每年CSDN的总结都不能落下&#xff0c;回顾去年&#xff1a;年度总结 | 回味2022不平凡的一年&#xff0c;在回忆今年&#xff0c;展望下年 1. 平台成就 平台造就我&#xff08;我也造就平台哈哈&#xff09; 每…

汇川PLC(H5U):定时器指令

一、H5U系列的定时器种类 H5U系列PLC的定时器指令都封装成指令块了&#xff0c;共4种类型&#xff1a;脉冲定时器、接通延时定时器、关断延时定时器、时间累加定时器。 H5U系列PLC的定时器时间基准是1ms&#xff0c;在IN引脚的执行指令有效的时候开始跟新计数器的值。 我们知…

门控循环单元(GRU)-多输入时序预测

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、实际运行效果&#xff1a; 三、部分代码&#xff1a; 四、完整代码数据下载&#xff1a; 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 本代码基于Matlab平台编译…

LVS那点事

LVS 原理 IPVS LVS 的 IP 负载均衡技术是通过 IPVS 模块来实现的&#xff0c;IPVS 是 LVS 集群系统的核心软件&#xff0c;它的主要作用是&#xff1a;安装在 Director Server 上&#xff0c;同时在 Director Server 上虚拟出一个 IP 地址&#xff0c;用户必须通过这个虚拟的…

Docker的一个简单例子(一)

文章目录 环境示例准备构建启动/停止容器更新应用分享应用 参考 环境 RHEL 9.3Docker Community 24.0.7 示例 准备 从github克隆 getting-started-app 项目&#xff1a; git clone https://github.com/docker/getting-started-app.git查看项目&#xff1a; ➜ getting-s…

vue-springboot基于JavaWeb的家装一体化商城平台guptn

针对用户需求开发与设计&#xff0c;该技术尤其在各行业领域发挥了巨大的作用&#xff0c;有效地促进了家装一体化的发展。然而&#xff0c;由于用户量和需求量的增加&#xff0c;信息过载等问题暴露出来&#xff0c;为改善传统线下管理中的不足&#xff0c;本文将提出一套基于…

vue写了这么久了你对slot的理解是什么?slot使用场景有哪些?

一、slot是什么 在HTML中 slot 元素 &#xff0c;作为 Web Components 技术套件的一部分&#xff0c;是Web组件内的一个占位符 该占位符可以在后期使用自己的标记语言填充 举个栗子 <template id"element-details-template"><slot name"element-na…
最新文章