1 Pinctrl引入
参考资料
- Linux 5.x内核文档
- Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt
- Linux 4.x内核文档
- Documentation\pinctrl.txt
- Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt
1.1 Pinctrl作用
无论是哪种芯片,都有类似下图的结构

- 想要pinA、B用于GPIO,需要设置IOMUX让它们连接到GPIO模块;
- 要想pinA、B用于I2C,需要设置IOMUX让它们连接到I2C模块;
- 要想pinA、B用于UART,需要设置IOMUX让它们连接到UART模块;
需要选择哪一个功能这就是pinctrl子系统需要做的事(所以,简单理解,pinctrl其实就是IOMUX复用寄存器)。
这里GPIO、I2C是并列的关系,它们能够使用之前,需要设置复用关系IOMUX,有时还要配置引脚,比如上拉、下拉、开漏等等。现在芯片一般动辄上百或几百个引脚,在使用到GPIO、I2C等功能时,若一个引脚一个引脚去找对应的寄存器进行配置非常浪费时间和精力,所以内核引入了Pinctrl子系统,把引脚的复用和配置抽象出来,只需要芯片厂商把自家芯片的支持进去,就可以很方便的配置引脚。
1.2 什么是GPIO子系统
GPIO子系统是Linux内核的一个组成部分,用于管理通用输入/输入引脚。它提供了一种标准化且统一的接口,使用户程序和驱动程序能够与硬件上的GPIO进行交互。
它的功能包括:
①:引脚控制(输入输出,电气属性配置)
②:值的读取以及写入,读取或者输出引脚的值
③:中断支持配置引脚触发中断。
1.3 pinctrl子系统和GPIO子系统的关系
pinctrl子系统是GPIO子系统的底层基础,使用pinctrl将引脚设置为GPIO功能,再由GPIO子系统进行通用输入输出配置。
1.4 如何使用pinctrl子系统和GPIO子系统
从设备树开始学习Pinctrl会比较容易。参考内核Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt,Pinctrl子系统涉及2个对象:Pin controller devices、Pinctrl client devices。
- Pin controller devices:提供服务,可以用它来复用引脚、配置引脚,是一个软件上的概念。
注意:Pin controller和GPIO Controller不同,前者控制的引脚可用于GPIO功能、I2C功能;后者只是把引脚配置为输入、输出等简单的功能。两者的关系是先用Pin controller把引脚配置为GPIO,再用GPIO Controler把引脚配置为输入或输出。 - Pinctrl client devices:使用服务,Pinctrl系统的客户,即使用Pinctrl系统的设备。声明自己要使用哪些引脚的哪些功能,怎么配置它们。
在设备树中,上述两个对象被定义成两个节点,如下图所示。左边是Pin controller节点,右边是client device节点:

- Pin state:对于一个client device来说,比如他是一个UART设备,它有多个“状态”:default、sleep等,那对应的引脚也有这些状态。比如默认状态下,UART设备是工作的,那么所用的引脚就要复用为UART功能。在休眠状态下,为了省电,可以把这些引脚复用为GPIO功能,或者直接把它们配置输出高电平。上图中,pinctrl-names属性里定义了2种状态:default、sleep。
- 第0种状态用到的引脚在pinctrl-0中定义,它是state_0_node_a,位于Pincontroller节点中。 第1种状态用到的引脚在pinctrl-1中定义,它是state_1_node_a,位于pincontroller节点中。
- 当这个设备处于default状态时,pinctrl子系统会自动根据上述信息把所用引脚复用为uart0功能。
- 当这个设备处于sleep状态时,pinctrl子系统会自动根据上述信息把所用引脚配置为高电平
groups、function和pins:一个设备会用到一个或多个引脚pin,这些引脚就可以归为一组group,复用为某个功能function;当然:一个设备可以用到多组引脚,比如A1、A2两组引脚,A1组复用为F1功能,A2组复用为F2功能。

c. pin multiplexing node和pin configuration node:在上图Pin controller节点中,有子节点或孙节点,它们是给client device使用的。
可以用来描述复用信息:哪组(group)引脚复用为哪个功能(function);
可以用来描述配置信息:哪组(group)引脚配置为哪个设置功能(setting),比如上拉、下拉等。
注意:Pin controller节点的格式,没有统一的标准!!!!每家芯片都不一样,甚至上面的group、function关键字也不一定有,但是概念是有的。而client device节点的格式是统一的。
2. Pinctrl子系统主要数据结构
参考资料
- pin_controller数据结构
- drivers\pinctrl\core.h
- include\linux\pinctrl\pinctrl.h
- include\linux\pinctrl\pinmux.h
- include\linux\pinctrl\pinconf.h
- client数据结构
- drivers\pinctrl\core.h
- include\linux\pinctrl\devinfo.h
- include\linux\device.h
- include\linux\pinctrl\machine.h
2.1 设备树模型

2.1 应用示例
实例:(NXP官方提供了一个能够根据选项自动生成设备树文件的软件)
打开nxp芯片设备树配置软件

这里需要点灯选择GPIO5_3将它路由至下面功能,标红的表示不能使用该功能。

将代码复制下来

然后去设备树中寻找这个节点(&iomux_snv),将复制的内容添加进去。


然后在设备树中加入自己的led节点,首先设置compatible属性方便与驱动匹配之后配置默认状态default之后去服务端找这个节点,看到是设置成GPIO5_3了,然后设备对应的GPIO,有效电平为低电平

三.代码
应用程序:ledtest.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
//ledtest /dev/myled on
//ledtest /dev/myled off
int main(int argc, char * argv[])
{
int fd;
char status = 0;
if(argc != 3)
{
printf("Usag:%s <dev> <on|off>\n", argv[0]);
printf("eg:%s <dev> <on|off>\n", argv[0]);
printf("eg:%s <dev> <on|off>\n", argv[0]);
}
//open
fd = open(argv[1], O_RDWR);
if(fd < 0)
{
printf("can not open %s\n", argv[0]);
}
//write
if(strcmp(argv[2], "on") == 0)
{
status = 1;
}
write(fd, &status, 1);
return 0;
}
驱动程序:led_drv.c
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
//1.确定主设备号
static int major;
static struct class *led_class;
static struct gpio_desc *led_gpio;
/*3.实现open/write函数,填入file_operations结构体*/
/*
struct file *file:表示打开设备文件后返回的文件指针。
const char __user *buf:表示用户空间缓冲区的起始地址,数据从这里传递到内核空间。
size_t size

本文围绕Linux内核的Pinctrl和GPIO子系统展开。介绍了Pinctrl子系统的作用,即抽象引脚复用和配置;阐述了GPIO子系统用于管理通用输入输出引脚。说明了二者关系,Pinctrl是GPIO的底层基础。还讲解了如何在设备树中使用这两个子系统,并给出应用示例和相关代码。
2977

被折叠的 条评论
为什么被折叠?



