《Pinctrl和GPIO子系统的使用》

1.参考文档

a. 内核 Documentation\devicetree\bindings\Pinctrl\ 目录下:
Pinctrl-bindings.txt

b. 内核 Documentation\gpio 目录下:
Pinctrl-bindings.txt

c. 内核 Documentation\devicetree\bindings\gpio 目录下:
gpio.txt

  

2.Pinctrl子系统概念

  linux下的pintcrl和gpio子系统就类似于ST的“BSP库”。引入“设备树”之后,使用一个外设时,对于pin引脚的初始化和管理,只需通过设备树描述即可,然后由pin子系统管理;对于gpio则由gpio子系统管理。
  因此,与CPU引脚“关联”的设备驱动,最终都会调用pincrtl和gpio子系统。二者是设备驱动的基础,这二者也是一个设备驱动。
  CPU的gpio引脚除了的方向、速度、上下拉、驱动能力等基本的电气特性外,一般会包括复用功能,即该引脚既可以作为普通gpio,还可能复位为i2c引脚、uart引脚等。如果采用直接配置寄存器的方式进行驱动开发,会非常繁琐,每更改一个功能就得重新翻阅手册配一遍寄存器,另一方面还可能存在“冲突”问题,比如该引脚已被复用为i2c在使用,但被驱动工程师忽略了,再去使用该gpio时会导致未知预期的问题。引入pintctrl子系统就可以解决诸如此类问题,结合设备树的使用,只需把pin信息在设备树描述清楚,即由pinctrl子系统介入管理。
 
  从设备树开始学习 Pintrl 会比较容易。
  主要参考文档是:内核 Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt。
  这会涉及 2 个对象:pin controller、client device。
  前者提供服务:可以用它来复用引脚、配置引脚。
  后者使用服务:声明自己要使用哪些引脚的哪些功能,怎么配置它们。
 
2.1 pin controller
  在芯片手册里你找不到 pin controller,它是一个软件上的概念,你可以认为它对应IOMUX──用来复用引脚,还可以配置引脚(比如上下拉电阻等)。
  注意,pin controller 和 GPIO Controller 不是一回事,前者控制的引脚可用于 GPIO 功能、I2C 功能;后者只是把引脚配置为输出、输出等简单的功能。
 
2.2 client device
  “客户设备”,谁的客户?Pinctrl 系统的客户,那就是使用 Pinctrl 系统的设备,使用引脚的设备。它在设备树里会被定义为一个节点,在节点里声明要用哪些引脚。
  下面这个图就可以把几个重要概念理清楚:  上图中,左边是 pincontroller 节点,右边是 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:
  一个设备会用到一个或多个引脚,这些引脚就可以归为一组(group);
  这些引脚可以复用为某个功能:function。
  当然:一个设备可以用到多能引脚,比如 A1、A2 两组引脚,A1 组复用为 F1 功能,A2组复用为 F2 功能。
 
Generic pin multiplexing node 和 Generic pin configuration node:
  在上图左边的 pin controller 节点中,有子节点或孙节点,它们是给 client device 使用的。
  可以用来描述复用信息:哪组(group)引脚复用为哪个功能(function);
  可以用来描述配置信息:哪组(group)引脚配置为哪个设置功能(setting),比如上拉、下拉等。
 
注意:pin controller 节点的格式,没有统一的标准!!!!每家芯片都不一样
 
 
3.GPIO系统
  pinctrl子系统主要是管理pin的电气属性和复用功能,而gpio子系统则是管理gpio的申请释放、控制输入输出、io中断等功能。gpio子系统屏蔽了gpio相关寄存器的配置过程,换而提供了常用的接口函数给驱动工程师使用,方便gpio相关的驱动开发。 

gpio子系统功能

  • 对于驱动层,屏蔽gpio寄存器配置细节,提供统一gpio操作接口
  • 对于BSP层,统一框架,方便不同CPU接入,只需更换pinctrl子系统的驱动
3.1 GPIO子系统常用函数
  gpio子系统对于驱动层的API位于“/kernel/include/linux/gpio.h”中。
(1)检查gpio是否可用
int gpio_is_valid(int number); 
number:	gpio序号
返回:	可用返回true,不可用返回false

  

(2)申请使用一个gpio

使用一个gpio前,必须向内核申请该gpio。
int gpio_request(unsigned gpio, const char *label)
gpio:	待申请gpio序号
label:gpio命名
返回:	成功返回0,失败返回负数

  

(3)释放已申请gpio

如果不使用该gpio,则需要释放,否则其他模块申请不到该gpio序号。
int gpio_free(unsigned gpio)
gpio:待释放gpio序号
返回:成功返回0,失败返回负数

  

(4)设置gpio输入模式

int gpio_direction_input(unsigned gpio)
gpio:待设置gpio序号
返回:成功返回0,失败返回负数

  

(5)设置gpio输出模式
void gpio_set_value(unsigned gpio, int value)
gpio:待设置gpio序号
value:默认输出状态

  

(6)读取 gpio状态

int gpio_get_value(unsigned int gpio)
gpio:待读取gpio序号
返回:成功返回gpio状态(1/0),失败返回负数

  

(7)设置 gpio状态

void gpio_set_value(unsigned int gpio, int value)
gpio:待设置gpio序号
value:待设置值

  

(8)中断号映射

int gpio_to_irq(unsigned gpio)
gpio:待设置gpio序号
返回:成功返回中断号,失败返回负数

  

如果使用该 GPIO 时,不会动态的切换输入输出,建议在开始时就设置好 GPIO 输出方向,后面拉高拉低时使用 gpio_set_value()接口,而不建议使用gpio_direction_output(), 因为 gpio_direction_output 接口里面有 mutex 锁,对中断上下文调用会有错误异常,且相比 gpio_set_value,gpio_direction_output 所做事情更多,浪费。 





 

 

 
 
 
 
 
 
 
 
 
 
 
 
 
 

 

posted @ 2020-04-22 11:14  一个不知道干嘛的小萌新  阅读(2341)  评论(0编辑  收藏  举报