pinctrl的系统架构一、数据结构和关系1.1 数据结构关系图1.2 数据结构说明1. struct pinctrl2. struct pinctrl_state3. struct pinctrl_setting4. struct pinctrl_dev5. struct client_device二、使用流程分析2.1 client 节点的 pinctrl 构造过程2.1.1 设备树中的 pinctrl 定义2.1.2 构造 pinctrl 过程2.2 切换 state 情景分析2.2.1 切换 state 函数调用栈2.2.2 详细函数调用分析2.2.3 常见切换 state 场景
pinctrl的系统架构
- 采用分层设计,将硬件细节与功能驱动分离
- 包括客户端驱动、pinctrl API、pinctrl核心、pinctrl映射和pinctrl驱动几个层次
客户端与 pinctrl组件关系图如下:
这种设计将硬件细节与功能驱动分离,使得功能驱动无需关心底层引脚配置细节,只需通过简单的 API 就能完成引脚状态管理,大大提高了代码的可维护性和可移植性。
一、数据结构和关系
1.1 数据结构关系图
- 客户端与 pinctrl 的关系:
- 客户端设备通过
pinctrl
指针使用 pinctrl 服务 - 一个客户端设备对应一个
struct pinctrl
实例
- pinctrl 与状态的关系:
- 一个
struct pinctrl
包含多个struct pinctrl_state
- 这些状态通过
states
链表连接
- 状态与设置的关系:
- 一个
struct pinctrl_state
包含多个struct pinctrl_setting
- 这些设置通过
settings
链表连接
- 设置与控制器的关系:
- 每个
struct pinctrl_setting
引用一个struct pinctrl_dev
- 设置通过控制器的操作函数被应用到硬件
1.2 数据结构说明
1. struct pinctrl
功能作用:
- 代表一个客户端设备的 pinctrl 句柄
- 管理设备的所有 pinctrl 状态和映射
- 连接客户端设备与 pinctrl 子系统
主要成员:
dev
:指向客户端设备
states
:包含所有状态的链表
dt_maps
:包含从设备树解析的映射
使用场景:
- 客户端驱动通过
devm_pinctrl_get()
获取此结构
- 用于查找和选择不同的引脚状态
2. struct pinctrl_state
功能作用:
- 表示一个特定的引脚配置状态(如 "default"、"sleep")
- 包含应用此状态所需的所有设置
主要成员:
name
:状态名称(如 "default"、"sleep")
settings
:包含此状态下所有设置的链表
使用场景:
- 客户端通过
pinctrl_lookup_state()
获取
- 通过
pinctrl_select_state()
应用状态
3. struct pinctrl_setting
功能作用:
- 表示单个引脚或引脚组的具体设置
- 可以是复用设置或配置设置
主要成员:
type
:设置类型(PIN_MAP_TYPE_MUX_GROUP 或 PIN_MAP_TYPE_CONFIGS_*)
pctldev
:指向处理此设置的 pinctrl 控制器
data
:联合体,包含具体设置数据
使用场景:
- 当应用状态时,每个设置被传递给相应的 pinctrl 驱动
4. struct pinctrl_dev
功能作用:
- 表示一个 pinctrl 控制器设备
- 提供操作引脚的接口
- 由 pinctrl 驱动注册
主要成员:
desc
:控制器描述符
ops
:基本操作函数集(如获取组)
pmxops
:复用操作函数集
confops
:配置操作函数集
使用场景:
- 由 pinctrl 驱动通过
pinctrl_register()
注册
- 处理来自客户端的引脚请求
5. struct client_device
功能作用:
- 表示使用 pinctrl 服务的客户端设备
- 存储设备的 pinctrl 句柄和常用状态
主要成员:
pinctrl
:指向设备的 pinctrl 句柄
default_state
:默认状态句柄
sleep_state
:睡眠状态句柄
使用场景:
- 客户端驱动初始化时获取 pinctrl 和状态
- 在电源管理时切换状态
二、使用流程分析
客户端驱动使用 pinctrl 的过程主要包括两个阶段:
- 构造阶段:
- 在设备树中定义 pinctrl 属性
- 驱动通过
devm_pinctrl_get()
获取 pinctrl 句柄 - 通过
pinctrl_lookup_state()
查找预定义状态
- 使用阶段:
- 通过
pinctrl_select_state()
切换引脚状态 - 在不同场景(如初始化、休眠、唤醒)选择不同状态
2.1 client 节点的 pinctrl 构造过程
2.1.1 设备树中的 pinctrl 定义
客户端驱动使用 pinctrl 的第一步是在设备树中定义 pinctrl 节点。典型的客户端节点 pinctrl 定义如下:
其中:
pinctrl-names
定义了不同的状态名称
pinctrl-0
、pinctrl-1
等对应于不同状态下的引脚配置
2.1.2 构造 pinctrl 过程
时序图
函数调用栈
- 客户端获取 pinctrl 句柄
devm_pinctrl_get(dev)
- 客户端驱动调用此函数获取 pinctrl 句柄- 内部调用
pinctrl_get()
进行实际处理
- pinctrl_get() 函数处理
- 设备树解析
pinctrl_dt_to_map() // 从设备树节点创建映射
- 映射创建和转化设置
- 映射创建过程:
- 系统从设备树中读取
pinctrl-X
属性,其中 X 是一个数字,表示不同的状态(如默认状态、睡眠状态等) - 对每个
pinctrl-X
属性,调用dt_to_map_one_config()
函数处理 - dt_to_map_one_config() 函数:
- 通过
of_find_node_by_phandle()
找到对应的 pinctrl 节点 - 调用特定 pinctrl 驱动实现的
dt_node_to_map()
函数创建映射 - 不同的 SoC 有不同的实现,例如:
sirfsoc_dt_node_to_map()
- SiRF SoCimx_dt_node_to_map()
- i.MX SoCstm32_pctrl_dt_subnode_to_map()
- STM32 SoC- dt_node_to_map() 函数:
- 创建两种类型的映射:
PIN_MAP_TYPE_MUX_GROUP
:用于配置引脚复用功能PIN_MAP_TYPE_CONFIGS_PIN
:用于配置引脚电气特性(如上拉/下拉、驱动强度等)- pinconf_map_to_setting() 函数:
- 将
pinctrl_map
结构转换为pinctrl_setting
结构 - 根据映射类型设置相应的字段
- 复制配置数据,如您提到的代码片段:
- 状态查找
- 创建
pinctrl_state
结构体表示每个状态 - 将状态与映射关联起来
2.2 切换 state 情景分析
总体的状态转换图
2.2.1 切换 state 函数调用栈
2.2.2 详细函数调用分析
- 查找状态
- 客户端调用
pinctrl_lookup_state(p, "default")
查找名为 "default" 的状态 - 内部调用
find_state()
在已创建的状态列表中查找
- 选择状态
- 客户端调用
pinctrl_select_state(p, state)
应用状态配置 - 此函数会处理两种类型的设置:复用设置和配置设置
- 复用设置处理
- 配置设置处理
- IMX 平台的实现
- 对于 IMX 平台,最终会调用
imx_pmx_set()
设置引脚复用 - 调用
imx_pinconf_set()
设置引脚配置 - 根据 SoC 类型选择不同的后端实现(内存映射或 SCU)
2.2.3 常见切换 state 场景
- 驱动初始化时
- 电源管理场景