增加 Pinctrl 和 sh-pfc 子系统.
Signed-off-by: rick.chan <chenyang@autoai.com>
This commit is contained in:
parent
7002fe3ac7
commit
f7d6acc1ba
|
@ -0,0 +1,55 @@
|
|||
# Pinctrl 和 sh-pfc 子系统
|
||||
|
||||
## 1.基本概念
|
||||
|
||||
### 1.1.Pin 与 GPIO 的差别
|
||||
|
||||
SOC 与其他外部设备通过 Pin 进行相互连接,某些 Pin 是 GPIO 功能,某些 Pin 是 SPI 功能,更多的 Pin 则复用了 GPIO 和其他功能,另外某些 Pin 属于 Power Supply 或 Clock Input。总之,Pin 泛指 SOC 的各个硬件管脚,而 GPIO 是功能概念,专指那些具备 GPIO 功能的 Pin,因此 GPIO 是 Pin 的一个子集。
|
||||
|
||||
### 1.2.Pinctrl 的实际需求
|
||||
|
||||
早期的 Linux 系统中没有 Pinctrl 的概念,每个驱动自己设置自己的管脚(Pin)。这似乎是一个非常简单的好办法,但问题是 Linux 要适应不同的平台。即便使用统一款 SOC,相似的外围器件,实际的硬件电路也可能不同。在一个项目里使用了 SPI1 去访问 SPI-Flash,在另一个项目里可能用的却是 SP3。这个时候驱动工程师就要深入到各个驱动里去逐个修改,Linux 有众多的驱动,一旦修改的地方不只一两处,开发人员就会深陷泥沼。有的时候驱动不正常,可能只是因为忘记了修改某个 Pin 的功能。
|
||||
|
||||
因此开发人员最好将 Pin 进行统一管理,一个 Pin 是用作 GPIO 还是 SPI,或者其他第二功能,应该由一个统一的系统来管理。将 Pin 作为统一的资源进行管理,也避免了使用上产生冲突的可能性,一旦某个 Pin 用作 I2C 了,那用户就不能再申请作为 GPIO 使用,除非前者释放了该资源。
|
||||
|
||||
因此诞生了 Pinctrl 子系统。Pinctrl 与 DeviceTree 配合工作,在 DeviceTree 中指定 Pin 所使用的功能,Pinctrl 解析设备树,对管脚进行配置,这样以来,当硬件发生变化后,就不再需要修改代码,只要修改 DeviceTree 就可以了。这样,不同的硬件都可以使用同一个内核,只要启动时传入正确的 DeviceTree 就可以了。
|
||||
|
||||
对于 Pin 的第二功能,往往不是独立工作的,对于 SPI,至少要有三个 Pin 配合工作(CLK、MISO 和 MOSI),这三个 Pin 应该一起被配置,所以,Pinctrl 提出了 Group 的概念,将具有同一功能的 Pin 组织到一起,统一配置和使用。
|
||||
|
||||
当今的 SOC 中,一个 Pin 往往不只具备两个功能,甚至可以附加第三个、第四个功能。Pin 的不同功能,由 Function 来指定。另外 Pin 可以有不同的 State,例如系统空闲、休眠时会将 Pin 设置为不同的状态。
|
||||
|
||||
### 1.3.Pinctrl 是如何解决现实问题的
|
||||
|
||||
由于大部分驱动模块都依赖于 Pinctrl,因此,Pinctrl 要先于其他驱动运行。Pinctrl 要对各个 Pin 进行配置,那么,何时才是配置 Pin 功能的最佳时机呢?在 Pinctrl 运行时就按照 DeviceTree 将所有 Pin 都配置一遍?
|
||||
|
||||
其实这是没必要的,如果 DeviceTree 中没有某个设备,也不必非得将对应的 Pin 设置为第二功能。Pinctrl 会在系统真正探测到某个设备时,触发将对应的 Pin 设置为正确的状态和功能。具体而言是在 really_probe 函数中调用的 pinctrl_bind_pins 方法。
|
||||
|
||||
```cpp
|
||||
static int really_probe(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
...
|
||||
...
|
||||
/* If using pinctrl, bind pins now before probing */
|
||||
ret = pinctrl_bind_pins(dev);
|
||||
if (ret)
|
||||
goto pinctrl_bind_failed;
|
||||
...
|
||||
if (dev->bus->probe) {
|
||||
ret = dev->bus->probe(dev);
|
||||
if (ret)
|
||||
goto probe_failed;
|
||||
} else if (drv->probe) {
|
||||
ret = drv->probe(dev);
|
||||
if (ret)
|
||||
goto probe_failed;
|
||||
}
|
||||
...
|
||||
pinctrl_init_done(dev);
|
||||
...
|
||||
return ret;
|
||||
}
|
||||
```
|
||||
|
||||
## 2.sh-pfc
|
||||
|
||||
sh-pfc 是 Pinctrl 的一个子集,Pinctrl 提供了许多回调函数,如果对应的是 sh-pfc 设备,则继续回调 sh-pfc 驱动的相关回调函数继续执行。sh-pfc 对 Pinctrl 进行了进一步的封装,使其更容易使用。
|
Loading…
Reference in New Issue