Pinctrl子系统_02_使用Pinctrl要掌握的重要概念

本节说明使用Pinctrl子系统时,要掌握的重要概念。

上节我们说到,我们通过Pinctrl子系统来控制设备的引脚,但实际上,大多数芯片都没有一个单独的Pinctrl。引脚的复用、配置等操作,实际上是在GPIO子系统内部实现的。

但是,我们可以把Pinctrl(pin controller)控制器抽象出来,当做一个软件概念,他主要实现两个作用:

  • 引脚复用
  • 引脚配置(上下拉电阻等等)

Pinctrl子系统_02_使用Pinctrl要掌握的重要概念_第1张图片

将配置GPIO的工作交给Pinctrl子系统。这样,需要配置GPIO时,调用Pinctrl子系统的函数即可。

怎么使用Pinctrl子系统呢?

串口模块为例:

首先,我们在设备树文件中定义一个UART节点,因为UART节点是Pinctrl子系统的用户,所以在内核文档中,它也被叫做client device,寓意为这个节点是一个用户,它会使用Pinctrl子系统。

UART节点中分别定义了两种状态state)—— 正常工作状态和休眠状态;这两种状态分别要配置哪些管脚group);管脚分别要配置成什么功能function)。

Pinctrl子系统_02_使用Pinctrl要掌握的重要概念_第2张图片

要怎么配置状态,引脚,功能呢?

复用节点

以下图为例,在client端,定义了一个用户设备device,这个用户设备有两种状态,分别是“default”和“sleep”。

这两种状态与之后的属性名称是一一对应的,其中-0表示第一种状态,-1表示第二种状态。即“default”对应pinctrl-0;“sleep”对应pinctrl-1。

而pinctrl-0和pinctrl-1分别等于一个节点,这个节点就是用来描述在这个状态下,应该配置哪些管脚,这些管脚应该配置成什么样

那么,这些节点位于哪里呢?——就在Pinctrl中。

当使用“default”状态时,就通过Pinctrl子系统,将指定group的管脚配置为“uart0”功能;当使用“sleep”状态是,则将指定管脚配置为“gpio”功能。

Pinctrl子系统_02_使用Pinctrl要掌握的重要概念_第3张图片

因为这些节点,是将相同的管脚在不同的状态下,被复用为了不同的功能,所以在内核文档中,这些节点也被叫做复用节点(Generic pin multiplexing node)

配置节点

另外,还有一个配置节点(Generic pin configuration node)。

与配置节点一样,当处于“default”状态时,配置为“uart0”功能;但是当处于“sleep”状态时,管脚被直接配置为了输出高电平,而不是某种function,这样的节点,在内核文档中就被叫做配置节点(Generic pin configuration node)。

Pinctrl子系统_02_使用Pinctrl要掌握的重要概念_第4张图片

总结

对于上面的配置,我们可以将左右分为两部分,左边是controller,右边是client

client中,配置不同的状态,给不同的状态指定不同的节点,而这些节点位于controller中,将哪些管脚配置为哪些功能或者状态。

对于client,它的格式通常都是固定的,但是对于controller,就没有统一的格式了。

虽然controller没有统一的格式,但是group,function,复用,配置,这些概念都是统一的。

Pinctrl子系统_02_使用Pinctrl要掌握的重要概念_第5张图片

举几个例子来看一下:

右边是client,它们的格式都是统一的,但是左边的controller,他们就没有什么统一的格式了。

Pinctrl子系统_02_使用Pinctrl要掌握的重要概念_第6张图片

代码中怎么引用Pinctrl?

这是透明的,我们的驱动基本不用管。当设备切换状态时,对应的pinctrl就会被调用。

比如在platform_device和platform_driver的枚举过程中,流程如下:

Pinctrl子系统_02_使用Pinctrl要掌握的重要概念_第7张图片

类似的,当系统休眠时,也会去设置该设备sleep状态对应的引脚,不需要我们自己去调用代码。

非要自己调用,也有函数(暂时不涉及,后续有需要再研究):

devm_pinctrl_get_select_default(struct device *dev);      // 使用"default"状态的引脚
pinctrl_get_select(struct device *dev, const char *name); // 根据name选择某种状态的引脚
pinctrl_put(struct pinctrl *p);   // 不再使用, 退出时调用

你可能感兴趣的:(单片机,嵌入式硬件)