Pinctrl概念:
无论是哪种芯片,都有类似图
16.1
的结构:
要想让
pinA
、
B
用于
GPIO
,需要设置
IOMUX
让它们连接到
GPIO
模块;
要想让
pinA
、
B
用于
I2C
,需要设置
IOMUX
让它们连接到
I2C
模块。
为了将人们从繁杂的寄存器设置工作中解放出来,就把引脚的复用、配置抽出来,做成
Pinctrl
子系统,给
GPIO
、
I2C 等模块使用。
从设备树开始学习
Pintrl
会比较容易。
这会涉及
2
个对象:
pin controller
、
client device
。
前者提供服务:可以用它来复用引脚、配置引脚。
后者使用服务:声明自己要使用哪些引脚的哪些功能,怎么配置它们。
pin controller:
在芯片手册里找不到
pin controller
,它是一个软件上的概念,你可以认为它对应 IOMUX
──用来复用引脚,还可以配置引脚
(
比如上下拉电阻等
)
。
注意,
pin controller
和
GPIO Controller
不是一回事,前者控制的引 脚可用于 GPIO
功能、
I2C
功能;后者只是把引脚配置为输入、输出等简单的功能。即先用 pin controller
把引脚配置为
GPIO
,再用
GPIO Controler
把引 脚配置为输入或输出。
client device:
“客户设备”,谁的客户?
Pinctrl
系统的客户,那就是使用
Pinctrl
系统 的设备,使用引脚的设备。它在设备树里会被定义为一个节点,在节点里声明要用哪些引脚。
a) pin state:
对于一个“
client device
”来说,比如对于一个
UART
设备,它有多个“状 态”:default
、
sleep
等,那对应的引脚也有这些状态。
怎么理解?
比如默认状态下,
UART
设备是工作的,那么所用的引脚就要复用为
UART
功 能。
在休眠状态下,为了省电,可以把这些引脚复用为
GPIO
功能;或者直接把 它们配置输出高电平。
b) groups 和 function:
一个设备会用到一个或多个引脚,这些引脚就可以归为一组
(group)
;
这些引脚可以复用为某个功能:
function。(
复用功能的宏定义在arch/arm/boot/dts/imx6ul-pinfunc.h中
)
当然:一个设备可以用到多组引脚,比如
A1
、
A2
两组引脚,
A1
组复用为
F1 功能,A2
组复用为
F2
功能。
c) Generic pin multiplexing node 和 Generic pin configuration node
在上图左边的
pin controller
节点中,有子节点或孙节点,它们是给 client device 使用的。
◼
可 以 用 来 描 述 复 用 信 息 : 哪 组
(group)
引 脚 复 用 为 哪 个 功 能 (function);
◼
可以用来描述配置信息:哪组
(group)
引脚配置为哪个设置功能 (setting),比如上拉、下拉等。
注意
:
pin controller
节点的格式,
没有统一的标准,
每家芯片都不一样。 甚至上面的 group
、
function
关键字也不一定有,但是概念是有的。
GPIO子系统概念:
要操作
GPIO
引脚,先把所用引脚配置为
GPIO
功能,这通过
Pinctrl
子系统来实现。
然后就可以根据设置引脚方向
(
输入还是输出
)
、读值──获得电平状态,写值──输出高低电平。
以前我们通过寄存器来操作
GPIO
引脚,即使
LED
驱动程序,对于不同的板子它的代码也完全不同。 当 BSP
工程师实现了
GPIO
子系统后,我们就可以:
⚫
在设备树里指定
GPIO
引脚
⚫
在驱动代码中:使用
GPIO
子系统的标准函数获得
GPIO
、设置
GPIO
方向、读取/
设置
GPIO
值。
这样的驱动代码,将是单板无关的。
在设备树中指定引脚:
在几乎所有
ARM
芯片中,
GPIO
都分为几组,每组中有若干个引脚。所以在 使用 GPIO
子系统之前,就要先确定:它是哪组的?组里的哪一个?
在设备树中,“
GPIO
组”就是一个
GPIO Controller
,这通常都由芯片厂家设置好。我们要做的是找到它名字,比如“gpio1”
,然后指定要用它里面的哪个 引脚,比如<&gpio1 0>
。
有代码更直观,下图是一些芯片的 GPIO 控制器节点,它们一般都是厂家定义好,在 xxx.dtsi 文件中:
我们暂时只需要关心里面的这
2
个属性:
gpio-controller;
#gpio-cells = <2>;
“
gpio-controller
”表示这个节点是一个
GPIO Controller
,它下面有很 多引脚。
“
#gpio-cells = <2>
”表示这个控制器下每一个引脚要用
2
个
32
位的数 (cell)来描述。 为什么要用 2
个数?
其实使用多个
cell
来描述一个引脚,这是
GPIO Controller 自己决定的。比如可以用其中一个
cell
来表示那是哪一个引脚,用另一个 cell
来表示它是高电平有效还是低电平有效,甚至还可以用更多的 cell 来示其他特性。 普遍的用法是,用第 1
个
cell
来表示哪一个引脚,用第
2
个
cell
来表示 有效电平:
GPIO_ACTIVE_HIGH : 高电平有效
GPIO_ACTIVE_LOW : 低电平有效
定义
GPIO Controller
是芯片厂家的事,我们怎么引用某个引脚呢?在自 己的设备节点中使用属性"[<name>-]gpios"
,示例如下:
上图中,可以使用
gpios
属性,也可以使用
name-gpios
属性。
在驱动代码中调用
GPIO
子系统 :
在设备树中指定了
GPIO
引脚,在驱动代码中如何使用? 也就是 GPIO
子系统的接口函数是什么?
GPIO
子系统有两套接口:基于描述符的
(descriptor-based)
、老的 (legacy)。前者的函数都有前缀“
gpiod_
”,它使用
gpio_desc
结构体来表示 一个引脚;后者的函数都有前缀“gpio_
”,它使用一个整数来表示一个引脚。要操作一个引脚,首先要 get
引脚,然后设置方向,读值、写值。
当pinctrl子系统配置引脚为GPIO模式后,才能用gpio子系统控制引脚。gpio 子系统是基于 pinctrl 子系统的,gpio 的 API 接口的实现很多都是基于 pinctrl 子系统的函数。
参考: https://www.bilibili.com/read/cv13931424/from=search&spm_id_from=333.337.0.0 出处:bilibili