一.pinctrl子系统
pinctrl 子系统主要工作内容如下:
1、获取设备树中 pin 信息。
2、根据获取到的 pin 信息来设置 pin 的复用功能
3、根据获取到的 pin 信息来设置 pin 的电气特性,比如上/下拉、速度、驱动能力等。
对于我们使用者来讲,只需要在设备树里面设置好某个 pin 的相关属性即可,其他的初始化工作均由 pinctrl 子系统来完成,pinctrl 子系统源码目录为 drivers/pinctrl。
1.PIN配置信息
要使用 pinctrl 子系统,我们需要在设备树里面设置 PIN 的配置信息,毕竟 pinctrl 子系统要根据你提供的信息来配置 PIN 功能,一般会在设备树里面创建一个节点来描述 PIN 的配置信息。
compatible 属性值为“fsl,imx6ul-iomuxc”,Linux 内核会根据 compatbile 属性值来查找对应的驱动文件
2.PIN驱动程序
第 326~330 行,of_device_id 结构体数组,里面保存着这个驱动文件的兼容性值,设备树中的 compatible 属性值会和 of_device_id 中的所有兼容性字符串比较,查看是否可以使用此驱动。
第 347~355 行,platform_driver 是平台设备驱动,这platform_driver 是个结构体,有个 probe 成员变量。当设备和驱动匹配成功以后 platform_driver 的 probe 成员变量所代表的函数就会执行,在 353 行设置 probe 成员变量为 imx6ul_pinctrl_probe 函数,因此在本实验中 imx6ul_pinctrl_probe 这个函数就会执行,可以认为 imx6ul_pinctrl_probe 函数就是 I.MX6ULL 这个 SOC 的 PIN 配置入口函数。以此为入口,如图 所示的函数调用路径:
imx_pinctrl_parse_groups函数如下
接下来看一下函数 pinctrl_register,此函数用于向 Linux 内核注册一个 PIN 控制器,此函数原型如下:
参数 pctldesc 非常重要,因为此参数就是要注册的 PIN 控制器,PIN 控制器用于配置 SOC的 PIN 复用功能和电气特性。参数 pctldesc 是 pinctrl_desc 结构体类型指针,pinctrl_desc 结构体如下所示:
第 132~124 行,这三个“_ops”结构体指针非常重要!!!因为这三个结构体就是 PIN 控制器的“工具”,这三个结构体里面包含了很多操作函数,通过这些操作函数就可以完成对某一个PIN 的配置。pinctrl_desc 结构体需要由用户提供,结构体里面的成员变量也是用户提供的。但是这个用户并不是我们这些使用芯片的程序员,而是半导体厂商,半导体厂商发布的 Linux 内核源码中已经把这些工作做完了。比如在 imx_pinctrl_probe 函数中可以找到如下所示代码:
第 655 行,定义结构体指针变量 imx_pinctrl_desc。
第 664 行,向指针变量 imx_pinctrl_desc 分配内存。
第 706~712 行,初始化 imx_pinctrl_desc 结构体指针变量,重点是 pctlops、 pmxops 和 confops这三个成员变量,分别对应 imx_pctrl_ops、imx_pmx_ops 和 imx_pinconf_ops 这三个结构体。
第 723 行,调用函数 pinctrl_register 向 Linux 内核注册 imx_pinctrl_desc,注册以后 Linux 内核就有了对 I.MX6ULL 的 PIN 进行配置的工具。
imx_pctrl_ops、imx_pmx_ops 和 imx_pinconf_ops 这三个结构体定义如下:
二.GPIO子系统
gpio 子系统顾名思义,就是用于初始化 GPIO 并且提供相应的 API 函数,比如设置 GPIO为输入输出,读取 GPIO 的值等。gpio 子系统的主要目的就是方便驱动开发者使用 gpio,驱动开发者在设备树中添加 gpio 相关信息,然后就可以在驱动程序中使用 gpio 子系统提供的 API函数来操作 GPIO,Linux 内核向驱动开发者屏蔽掉了 GPIO 的设置过程,极大的方便了驱动开发者使用 GPIO。
1.设备树中表示方法
GPIO相关API函数