From f7d6acc1baf0cd6436ad65629c28b9a4e36fb03e Mon Sep 17 00:00:00 2001 From: "rick.chan" Date: Fri, 7 Aug 2020 12:01:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20Pinctrl=20=E5=92=8C=20sh-p?= =?UTF-8?q?fc=20=E5=AD=90=E7=B3=BB=E7=BB=9F.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: rick.chan --- .../Pinctrl/Pinctrl_和_sh-pfc_子系统.md | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 Software/Development/OperatingSystem/Linux/Kernel/Modules/Pinctrl/Pinctrl_和_sh-pfc_子系统.md diff --git a/Software/Development/OperatingSystem/Linux/Kernel/Modules/Pinctrl/Pinctrl_和_sh-pfc_子系统.md b/Software/Development/OperatingSystem/Linux/Kernel/Modules/Pinctrl/Pinctrl_和_sh-pfc_子系统.md new file mode 100644 index 0000000..341ac11 --- /dev/null +++ b/Software/Development/OperatingSystem/Linux/Kernel/Modules/Pinctrl/Pinctrl_和_sh-pfc_子系统.md @@ -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 进行了进一步的封装,使其更容易使用。