核心数据结构
在
pinctrl-imx.c
中,定义了 i.MX 平台的 pinctrl 实现:引脚解析函数
在
pinctrl-imx.c
中,imx_pinctrl_parse_groups
函数负责解析设备树中的引脚组定义:引脚复用设置函数
imx_pmx_set
函数负责设置引脚的复用功能:状态图
pinctrl 子系统中引脚的状态转换:
设计理念
核心数据结构
pinctrl 子系统的核心数据结构包括:
- pinctrl_dev:表示一个 pinctrl 控制器设备
- pinctrl_desc:描述 pinctrl 控制器的特性
- pinctrl_ops:提供引脚组操作的回调函数
- pinmux_ops:提供引脚复用操作的回调函数
- pinconf_ops:提供引脚配置操作的回调函数
- pinctrl:表示一个客户端设备的 pinctrl 句柄
- pinctrl_state:表示一个 pinctrl 状态,如 "default"、"sleep" 等
- pinctrl_map:描述引脚控制映射关系
关键算法
- 引脚查找算法:通过引脚名称或 ID 快速查找对应的引脚
- 状态匹配算法:根据设备树中的状态名称匹配对应的 pinctrl 状态
- 引脚分配算法:确保同一时间一个引脚只能被一个功能使用
- 配置应用算法:将配置值正确应用到硬件寄存器
设计模式
pinctrl 子系统采用了多种设计模式:
驱动模型
工厂模式
pinctrl 子系统使用工厂模式创建不同类型的 pinctrl 控制器:
策略模式
pinctrl 子系统使用策略模式处理不同 SoC 的引脚配置:
IMX Pincontroller 功能分析
通过分析
pinctrl-imx.c
和 pinctrl-imx6ul.c
的代码,我将详细解析 IMX 平台 pincontroller 的三个核心功能实现流程。功能1:描述、获得引脚:解析设备树
初始化流程
- 驱动入口点:
- 从
imx6ul_pinctrl_init()
开始,注册平台驱动 - 调用
platform_driver_register(&imx6ul_pinctrl_driver)
- 设备匹配与探测:
- 当设备树中匹配到
fsl,imx6ul-iomuxc
或fsl,imx6ull-iomuxc-snvs
时 - 调用
imx6ul_pinctrl_probe()
函数 - 获取 SoC 特定信息
imx6ul_pinctrl_info
或imx6ull_snvs_pinctrl_info
- 调用通用探测函数
imx_pinctrl_probe()
- 设备树解析:
imx_pinctrl_probe()
中调用imx_pinctrl_probe_dt()
解析设备树- 检查设备树格式(平铺或嵌套):
imx_pinctrl_dt_is_flat_functions()
- 分配内存存储 functions 和 groups 信息
- 解析 functions:
imx_pinctrl_parse_functions()
- 解析 groups:
imx_pinctrl_parse_groups()
- 引脚组解析:
imx_pinctrl_parse_groups()
解析每个引脚组- 从设备树节点的
fsl,pins
属性获取引脚配置 - 根据 SoC 类型确定引脚配置大小(FSL_PIN_SIZE 或 SHARE_FSL_PIN_SIZE)
- 为每个引脚调用
imx_pinctrl_parse_pin_mem()
或imx_pinctrl_parse_pin_scu()
设备树到引脚映射
- 设备树到映射转换:
imx_dt_node_to_map()
将设备树节点转换为 pinctrl 子系统的映射- 查找对应的引脚组:
imx_pinctrl_find_group_by_name()
- 创建复用映射(mux map)和配置映射(config map)
- 引脚组查询:
imx_get_groups_count()
获取引脚组数量imx_get_group_name()
获取引脚组名称imx_get_group_pins()
获取引脚组中的引脚
功能2:引脚复用
复用设置流程
- 复用操作注册:
- 在
imx_pinctrl_probe()
中注册imx_pmx_ops
操作集 - 包含
get_functions_count
,get_function_name
,get_function_groups
,set_mux
等函数
- 复用设置实现:
imx_pmx_set()
设置引脚复用功能- 获取指定组的所有引脚
- 遍历每个引脚,根据 SoC 类型调用:
imx_pmx_set_one_pin_scu()
(SCU 方式)imx_pmx_set_one_pin_mem()
(内存映射方式)
- 功能查询:
imx_pmx_get_funcs_count()
获取功能数量imx_pmx_get_func_name()
获取功能名称imx_pmx_get_groups()
获取功能对应的引脚组
- GPIO 方向设置:
imx_pmx_gpio_set_direction()
设置 GPIO 方向- 根据 SoC 类型调用
imx_pmx_backend_gpio_set_direction_mem()
功能3:引脚配置
配置设置流程
- 配置操作注册:
- 在
imx_pinctrl_probe()
中注册imx_pinconf_ops
操作集 - 包含
pin_config_get
,pin_config_set
等函数
- 配置获取实现:
imx_pinconf_get()
获取引脚配置- 根据 SoC 类型调用:
imx_pinconf_backend_get_scu()
(SCU 方式)imx_pinconf_backend_get_mem()
(内存映射方式)
- 配置设置实现:
imx_pinconf_set()
设置引脚配置- 根据 SoC 类型调用:
imx_pinconf_backend_set_scu()
(SCU 方式)imx_pinconf_backend_set_mem()
(内存映射方式)
- 配置调试:
imx_pinconf_dbg_show()
显示引脚配置imx_pinconf_group_dbg_show()
显示引脚组配置
整体架构与调用关系
- 初始化流程:
- 引脚复用流程:
- 引脚配置流程:
总结
IMX pincontroller 实现了三个核心功能:
- 引脚描述与获取:通过解析设备树,建立引脚、引脚组和功能的映射关系
- 引脚复用:设置引脚的功能复用,支持内存映射和 SCU 两种方式
- 引脚配置:设置引脚的电气特性,如上拉/下拉、驱动强度等
这些功能通过统一的 pinctrl 子系统接口暴露给用户空间,使得驱动开发者可以通过设备树配置引脚,而无需直接操作硬件寄存器。
IMX Pinctrl 驱动分析
一、Pinctrl 驱动与客户端驱动的区别
Pinctrl 驱动
Pinctrl 驱动是一种底层硬件抽象驱动,负责管理 SoC 的引脚控制器硬件。从提供的代码中可以看出,
pinctrl-imx.c
和 pinctrl-imx6ul.c
就是典型的 pinctrl 驱动实现。Pinctrl 驱动主要负责:
- 引脚复用:配置引脚的功能模式(如 GPIO、UART、I2C 等)
- 引脚配置:设置引脚的电气特性(如上拉/下拉、驱动强度等)
- 引脚分组:将相关引脚组织成逻辑组,便于统一管理
客户端驱动
客户端驱动是使用 pinctrl 服务的功能驱动,如 UART、I2C、SPI 等外设驱动。
客户端驱动主要:
- 通过
pinctrl_get()
获取 pinctrl 句柄
- 通过
pinctrl_lookup_state()
查找预定义的引脚状态
- 通过
pinctrl_select_state()
应用引脚配置
二、Pinctrl 驱动与 Pinctrl 核心的关系
Pinctrl 核心
Pinctrl 核心(在
drivers/pinctrl/core.c
中实现)提供了统一的 API 和框架,是连接 pinctrl 驱动和客户端驱动的桥梁。关系模型
从代码中可以看出:
- Pinctrl 驱动通过
pinctrl_register()
向核心注册自己
- Pinctrl 驱动实现
pinctrl_ops
、pinmux_ops
和pinconf_ops
接口
- Pinctrl 核心调用这些接口来完成客户端的请求
例如,在
pinctrl-imx.c
中:三、Pinctrl 驱动开发流程
1. 准备工作
- 了解目标 SoC 的引脚控制器硬件规格
- 确定引脚编号、复用功能和配置选项
- 确定寄存器映射和位域定义
2. 定义基础数据结构
- 定义引脚枚举(如
imx6ul_pads
枚举)
- 定义引脚描述符数组(如
imx6ul_pinctrl_pads
)
- 定义 SoC 特定信息结构体(如
imx_pinctrl_soc_info
)
3. 实现 pinctrl_ops 接口
get_groups_count
:获取引脚组数量
get_group_name
:获取引脚组名称
get_group_pins
:获取引脚组中的引脚
dt_node_to_map
:将设备树节点转换为 pinctrl 映射
4. 实现 pinmux_ops 接口
get_functions_count
:获取功能数量
get_function_name
:获取功能名称
get_function_groups
:获取功能对应的引脚组
set_mux
:设置引脚复用功能
5. 实现 pinconf_ops 接口
pin_config_get
:获取引脚配置
pin_config_set
:设置引脚配置
pin_config_group_get
:获取引脚组配置
pin_config_group_set
:设置引脚组配置
6. 实现设备树解析
- 解析设备树中的引脚组和功能定义
- 将设备树配置转换为内部数据结构
7. 实现驱动探测函数
- 获取硬件资源(如寄存器映射)
- 初始化内部数据结构
- 注册 pinctrl 设备
8. 注册平台驱动
- 定义平台驱动结构体
- 实现匹配表(compatible 字符串)
- 注册驱动
四、IMX Pinctrl 驱动实现示例
从提供的代码中,我们可以看到 IMX 平台的 pinctrl 驱动实现:
1. 驱动入口点
2. 平台驱动定义
3. 设备匹配表
4. 探测函数
5. 通用探测实现
五、总结
Pinctrl 驱动是连接硬件引脚控制器和 Linux 内核 pinctrl 子系统的桥梁。开发 pinctrl 驱动需要深入了解目标 SoC 的硬件特性,并按照 Linux 内核 pinctrl 子系统的框架实现相应的接口。
IMX 平台的 pinctrl 驱动采用了分层设计:
pinctrl-imx.c
提供通用的 IMX 平台 pinctrl 实现
pinctrl-imx6ul.c
提供 IMX6UL 特定的引脚定义和驱动入口
这种设计使得不同 IMX 系列 SoC 可以共享大部分代码,只需要针对特定 SoC 实现少量差异化代码。