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);//testbeep_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.hqwc.cn/news/312279.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nginx+keepalived实现七层负载

目录 一、部署nginx01、nginx02 二、keepalived配置&#xff08;抢占模式、master- backup模式&#xff09; 三、测试 四、非抢占模式&#xff08;backup-backup模式&#xff09; nginx01 11.0.1.31nginx0211.0.1.32虚拟IP&#xff08;VIP&#xff09;11.0.1.30 一、部署ngin…

SpringBoot+MyBatis+MySQL增删改查(一)(IDEA创建SpringBoot项目)

使用IDEA创建SpringBootMyBatisMySQL进行项目搭建 1.创建项目 文件 --> 新建 --> 项目 填写项目基本信息 项目名称、存放位置、项目语言、项目类型、JDK版本、打包 Web选项选择Spring Web SQL选项中勾选JDBC API、MyBatis Framework、MySQl Driver选项 至此一个空项目…

SpringBoot用JDK1.8的依赖设置pom.xml

pom.xml的修改主要是两个地方&#xff1a; 1.修改springframework的版本为2.5.0&#xff0c;版本太高可能和其他插件搭配有冲突&#xff1b; 2.Java的版本修改成8&#xff0c;也就是对应JDK1.8。

【编程语言】协程比较

一、比较五种编程语言&#xff08;Python、C、Go、C、Java&#xff09;的协程实现和特点。 Python Python从3.5版本开始通过async 和 await 关键字提供了原生协程支持&#xff0c;主要用于简化异步I/O操作。在Python中&#xff0c;协程是由事件循环&#xff08;event loop&am…

【Spring实战】14 Web表单校验

文章目录 1. 依赖2. 实体类3. 控制器4. 页面5. 启动6. 验证1&#xff09;访问页面2&#xff09;后台校验 7. 优点8. 代码详细总结 在 Web 应用中&#xff0c;表单是用户与后端交互的主要界面之一。为了确保数据的有效性和一致性&#xff0c;我们经常需要对提交的表单数据进行验…

学生管理系统(vue + springboot)

学生管理系统&#xff08;vuespringboot&#xff09;资源-CSDN文库 项目介绍 这是一个采用前后端分离开发的项目&#xff0c;前端采用 Vue 开发、后端采用 Spring boot Mybatis 开发。 项目部署 ⭐️如果你有 docker 的话&#xff0c;直接 docker compose up 即可启动&#…

计算机基础面试题 |01.精选计算机基础面试题

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

第4课 FFmpeg读取本地mp4文件并显示

在上节课&#xff0c;我们使用FFmpeg实现了一个最简单的rtmp播放器&#xff0c;它看起来工作正常。这节课&#xff0c;我们尝试让它来播放本地的mp4文件试试。 1.压缩备份上节课工程文件夹为demo3.rar&#xff0c;并修改工程文件夹demo3为demo4&#xff0c;重要的事情再说一遍…

使用anaconda创建notebook工程

1.由于每个工程使用的环境都可能不一样&#xff0c;因此一个好的习惯就是不同的工程都创建属于自己的环境&#xff0c;在anaconda中默认的环境是base&#xff1a; //括号中名字&#xff0c;代表当前的环境 (base)dragonmachine: $ conda create --nameexample2.激活环境 // 环…

Kubernetes网络-VXLAN

一. 网络基础 1. 计算机网络的分层 如今连接方式也越来也丰富&#xff0c;网线、WiFi、蓝牙、光纤&#xff0c;甚至我们普通的电线、照明所用的灯光&#xff0c;都可以作为接入网络的介质。如此庞大的网络&#xff0c;丰富多样的设备&#xff0c;计算机网络技术能把它们统一起…

回味2023

2023年的元旦假期我是在南京度过的&#xff0c;1月2日&#xff0c;我特别前往南京博物院&#xff0c;为了看一个特展——《墨田》。 时代发展&#xff0c;有些东西变了&#xff0c;但是有些东西没有变。 比如书写的方式变了&#xff0c;我们这一代&#xff0c;不再耕耘在真的“…

ubuntu22.04安装anacoda遇到的坑

这几天把用了3年的windows10换成了ubuntu22.04 各种环境都得配置&#xff0c;本文记录下遇到的坑。 1、anacoda在ubuntu上也可以用官方也提供了安装包&#xff0c;但是没有图形界面&#xff0c;需要以命令行的方式安装和运行配置 1.1 安装&#xff1a;官网下载后&#xff0c;…