Pinctrl子系统中client端设备树相关数据结构介绍和解析
往期内容
本专栏往期内容:
- Pinctrl子系统和其主要结构体引入
- Pinctrl子系统pinctrl_desc结构体进一步介绍
input子系统专栏:
- 专栏地址:input子系统
- input角度:I2C触摸屏驱动分析和编写一个简单的I2C驱动程序
– 末片,有往期内容观看顺序I2C子系统专栏:
- 专栏地址:IIC子系统
- 具体芯片的IIC控制器驱动程序分析:i2c-imx.c-CSDN博客
– 末篇,有往期内容观看顺序总线和设备树专栏:
- 专栏地址:总线和设备树
- 设备树与 Linux 内核设备驱动模型的整合-CSDN博客
– 末篇,有往期内容观看顺序
目录
- 往期内容
- 前言
- 1. client的数据结构
- 1.1 dev_pin_info
- 1.2 pinctrl和pinctrl_state
- 1.3 pinctrl_map和pinctrl_setting
- 2. 使用pinctrl_setting
前言
Linux 4.x内核文档
- Documentation\pinctrl.txt📎pinctrl.txt
- Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt📎pinctrl-bindings.txt
- arch/arm/boot/dts/imx6ull-14x14-evk.dts
- arch/arm/boot/dts/100ask_imx6ull-14x14.dts
- drivers\pinctrl\freescale\pinctrl-imx6ul.c📎pinctrl-imx6ul.c
- drivers\pinctrl\freescale\pinctrl-imx.c📎pinctrl-imx.c
本节主要讲解在pinctrl子系统中,用户在设备树中使用后,在驱动程序中是用哪些结构体来对设备树解析后的pinctrl信息进行存储起来的,以及大概的解析流程。
1. client的数据结构
在上文pincontroller的介绍中,讲述了关于pinctrl_dev中pinctrl_desc的相关知识,可是这是对pincontroller的设备树的抽象描述,那使用了pincontroller的client的设备树节点,在程序中又用什么结构体来抽象表示自己使用了哪一个pincontroller下的某一功能的组引脚
如上图右侧就是client,也就是我们去使用左侧定义好的pincontroller,pinctrl-0指向的state_1_node_a的节点,在驱动中是怎么去存储device使用到的pinctrl-0和pinctrl-1对应到左侧的pinctrl信息?? — dev_pin_info,可以先看下面的总框图
每个device结构体里都有一个dev_pin_info结构体,用来保存设备的pinctrl信息,只不过这个pinctrl信息是经过转换的,节点–>mapping–>setting:
1.1 dev_pin_info
每个device结构体里都有一个dev_pin_info结构体,用来保存设备的pinctrl信息,只不过这个pinctrl信息是经过转换的,节点–>mapping–>setting。这里还是再提一下,因为这是理解的核心。
📎devinfo.h
pincontroller给谁使用的??那肯定是设备,设备使用了哪些引脚在设备树中指定,而该设备的设备树中去引用了Pincontroller设置好的引脚,那么pinctrl的信息就肯定在device结构体中,假设是采用平台来注册设备的:
struct platform_device {
const char *name;
int id;
bool id_auto;
struct device dev; //看下面
u32 num_resources;
struct resource *resource;
const struct platform_device_id *id_entry;
char *driver_override; /* Driver name to force a match */
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
struct device {
struct device *parent;
struct device_private *p;
struct kobject kobj;
const char *init_name; /* initial name of the device */
const struct device_type *type;
struct mutex mutex; /* mutex to synchronize calls to
* its driver.
*/
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this
device */
void *platform_data; /* Platform specific data, device
core doesn't touch it */
void *driver_data; /* Driver data, set and get with
dev_set/get_drvdata */
struct dev_links_info links;
struct dev_pm_info power;
struct dev_pm_domain *pm_domain;
#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
struct irq_domain *msi_domain;
#endif
#ifdef CONFIG_PINCTRL
struct dev_pin_info *pins;
//..........
}
platform_device和device就不在讲解了,在驱动中的device和device_driver结构体-CSDN博客和platform bus平台总线详解-CSDN博客有讲解过。其中platform_device-->device-->dev_pin_info
,#ifdef CONFIG_PINCTRL
也很明确了告诉我们,就是存储client设备节点使用的pinctrl信息,dev_pin_info
结构体定义如下:
struct dev_pin_info {
struct pinctrl *p; //指针类型,一个pinctrl,比如设备树中client定义了pinctrl-0= ;那么其对应的pinctrl信息就存在这
//这是设备的引脚控制句柄,用于管理和操作设备的引脚(pins)。通过它,驱动程序可以使用 pinctrl API 来设置和切换引脚的状态。
struct pinctrl_state *default_state;
//设备的默认引脚状态。如果设备成功查找到默认状态,这里会保存该状态。在设备初始化或者运行期间,这个状态可能会被激活。
struct pinctrl_state *init_state;
//设备在驱动探测(probe)时的初始引脚状态。如果在驱动加载时找到这个状态,它将被设置为设备的初始状态。
#ifdef CONFIG_PM
struct pinctrl_state *sleep_state;
//设备进入系统休眠(suspend)时的引脚状态。在电源管理(Power Management,PM)启用的情况下,当设备进入休眠时,这个状态会被应用,以确保引脚处于低功耗或其他适当的状态。
struct pinctrl_state *idle_state;
//设备进入空闲(即运行时挂起,runtime suspend)时的引脚状态。在设备处于空闲状态时,会应用此状态。它允许设备进入空闲时节省功耗的状态。
#endif
};
其中dev_pin_info
有两个结构体类型的成员:pinctrl
和pinctrl_state
,pinctrl信息和状态。struct dev_pin_info *pins;
可以被用作数组类型,其中每个 dev_pin_info
结构体对应一个 pinctrl
句柄。因此,如果设备有多个 pinctrl
状态(如设备树中的 pinctrl-0
、pinctrl-1
),则可以通过 pins
数组来管理每个状态。具体来说,struct dev_pin_info
中保存了与引脚状态相关的多个信息,如 default_state
、sleep_state
等。每个 dev_pin_info
实例可以关联到设备树中的一个 pinctrl
状态。
1.2 pinctrl和pinctrl_state
先看pinctrl
, 是 Linux 内核中每个设备的引脚控制状态管理器。它负责管理和切换设备的引脚配置状态(state),并且可以存储从设备树(Device Tree)解析的引脚映射表。这个结构体对于设备驱动程序而言,是引脚控制系统的一部分,用于确保设备的引脚配置在系统的不同状态下能够正确应用 :
假设芯片上有多个pin controller,那么这个设备使用哪个pin controller?
这需要通过设备树来确定:
-
分析设备树,找到pin controller,就是根据client处定义的pinctrl-0/1所对应到Pincontroller的设备树节点
-
对于每个状态,比如default、init,去分析pin controller中的设备树节点
- 使用pin controller的pinctrl_ops.dt_node_to_map来处理设备树的pinctrl节点信息,得到一系列的pinctrl_map
- 这些pinctrl_map放在pinctrl.dt_maps链表中
- 每个pinctrl_map都被转换为pinctrl_setting,放在对应的pinctrl_state.settings链表中
struct pinctrl
结构体在 Linux 内核中表示某个设备的引脚控制状态。这是引脚控制子系统用于管理和跟踪设备引脚配置的结构体,可以设置不同的硬件配置和电源状态。
struct pinctrl {
struct list_head node;
struct device *dev;
struct list_head states;
struct pinctrl_state *state;
struct list_head dt_maps;
struct kref users;
};
-
struct list_head node
- 类型:
struct list_head
- 描述: 这是一个链表节点,用于将
pinctrl
结构体加入到全局的引脚控制状态列表中。 - 作用: 引脚控制子系统通常需要维护一个系统中所有引脚控制配置的列表,通过这个列表可以有效管理和访问与不同设备相关的所有
pinctrl
结构体。 - 使用场景: 使用
list_add
或list_add_tail
将这个pinctrl
结构体插入到全局链表中。
- 类型:
-
struct device *dev
- 类型: 指向
struct device
的指针 - 描述: 指向使用该引脚控制句柄的设备。
- 作用:
pinctrl
结构体中的dev
成员用于关联该引脚控制配置到具体的设备,便于在操作引脚控制时知道该配置属于哪个设备。
- 类型: 指向
-
struct list_head states
- 类型:
struct list_head
- 描述: 一个链表头,表示该设备的所有引脚控制状态(
pinctrl_state
)。 - 作用: 一个设备可以有多个引脚控制状态,例如不同的电源状态、工作模式等。这个链表记录了该设备的所有状态,以便在需要时切换状态。
- 类型:
-
struct pinctrl_state *state
- 类型: 指向
struct pinctrl_state
的指针 - 描述: 表示当前的引脚控制状态。
- 作用: 设备可能在不同的工作条件下需要不同的引脚配置,而这个成员保存了当前的引脚控制状态。
- 类型: 指向
-
struct list_head dt_maps
- 类型:
struct list_head
- 描述: 从设备树(Device Tree)中动态解析的映射表块(mapping table chunks)。
- 作用: 如果设备树中有与引脚控制相关的映射数据,它们会被动态加载到这个链表中。该成员帮助
pinctrl
子系统从设备树中获取引脚配置数据。
- 类型:
-
struct kref users
- 类型:
struct kref
- 描述: 引用计数器。
- 作用: 用于跟踪这个
pinctrl
结构体的引用数,确保在有多个用户引用时不被释放。通常用于资源管理,只有在引用计数为零时才会销毁这个结构体。
- 类型:
struct pinctrl
结构体提供了设备引脚配置的基础框架,通过它可以记录每个设备的引脚控制状态、从设备树解析的映射信息,并进行引用计数管理。
struct pinctrl_state
结构体用于定义一个设备的引脚控制状态(pinctrl state),这是引脚控制框架中的一个抽象,用于表示设备在特定状态下引脚的配置。每个设备可以有多个状态,每个状态包含一组特定的引脚设置。当设备运行在不同的模式下时,可以通过切换不同的状态来改变其引脚的功能。
struct pinctrl_state {
struct list_head node;
const char *name;
struct list_head settings;
};
-
struct list_head node
- 类型: 链表节点
- 描述: 用于将此
pinctrl_state
结构体连接到struct pinctrl
的states
字段的链表中。 - 作用: 将多个
pinctrl_state
结构体组织在一起,形成一个链表。每个设备可能具有多个不同的状态,使用链表将这些状态链接在一起便于管理和遍历。 - 应用场景: 当需要为设备设置或切换多个状态时,可以通过遍历链表访问所有状态。
-
const char *name
- 类型: 字符串指针
- 描述: 此状态的名称。
- 作用: 用于标识和引用该状态名称。例如,在需要将设备配置成特定状态时,可以通过名称来找到对应的
pinctrl_state
。 - 应用场景: 通过状态名称切换设备的引脚配置,达到不同模式下引脚行为的定制化。
-
struct list_head settings
- 类型: 链表节点
- 描述: 存储该状态下所有引脚的设置列表。有map转化而来的
- 作用: 列出当前状态下的引脚配置选项。例如,可以包含每个引脚的模式(复用设置)和参数(例如上下拉、驱动强度等)。
- 应用场景: 当设备进入此状态时,系统会应用
settings
中的所有设置,以确保设备的引脚行为符合当前模式的要求。
struct pinctrl_state
通过 name
字段标识状态的名称,settings
存储该状态下的所有引脚配置,而 node
将状态链表化。这种设计方式便于设备在不同工作模式之间快速切换引脚配置,满足多样化的引脚功能需求。
1.3 pinctrl_map和pinctrl_setting
pinctrl中提到的struct list_head dt_maps:
struct pinctrl_map
结构体在 Linux 内核中用于定义特定设备的引脚控制映射。该结构体定义了一个引脚控制映射条目,通常用于板级或机器级别的配置来实现设备的引脚映射关系。通过这个映射关系,内核可以管理设备的引脚复用(muxing)和配置(configurations),并确保在正确的引脚配置下设备正常工作。
struct pinctrl_map {
const char *dev_name;
const char *name;
enum pinctrl_map_type type;
const char *ctrl_dev_name;
union {
struct pinctrl_map_mux mux;
struct pinctrl_map_configs configs;
} data;
};
-
const char *dev_name
- 类型: 字符串指针
- 描述: 使用该映射的设备名称。
- 作用: 指向设备的名称,这个名称应与
struct device
中定义的设备名称一致。如果该名称与引脚控制器本身的dev_name()
相同,那么该映射条目会在注册时由驱动程序自动接管(“hog”)。 - 应用场景: 用于识别和定位设备,使得映射条目在正确的设备上应用。
-
const char *name
- 类型: 字符串指针
- 描述: 该特定映射条目的名称。
- 作用: 用于标识该映射条目。这个参数会传递给
pinmux_lookup_state()
,从而在配置引脚控制时通过名称来查找映射。 - 应用场景: 利用映射名称来选择特定的引脚配置状态。
-
enum pinctrl_map_type type
- 类型: 枚举类型
pinctrl_map_type
- 描述: 映射表条目的类型。
- 作用: 指定该条目所表示的映射类型。映射类型可以是引脚复用(MUX)映射、配置映射等,不同的类型指示了不同的操作,具体在
data
成员中体现。
- 类型: 枚举类型
-
const char *ctrl_dev_name
- 类型: 字符串指针
- 描述: 控制此映射的设备名称。
- 作用: 表示实际控制引脚的设备名称,该名称也应与
struct device
中的设备名称相匹配。此字段不适用于PIN_MAP_TYPE_DUMMY_STATE
类型。 - 应用场景: 引脚控制器在控制多个引脚时,可以根据
ctrl_dev_name
来确定哪个引脚控制器处理该映射。
-
union data
-
类型: 共用体,包含不同类型的数据结构
-
描述: 根据映射类型存储特定的映射数据。
-
作用: 该成员根据不同的
type
值存储不同的数据结构。struct pinctrl_map_mux mux
: 当type
为复用映射时,该成员包含复用配置。struct pinctrl_map_configs configs
: 当type
为配置映射时,该成员包含引脚配置数据。
-
应用场景: 根据映射类型设置不同的引脚控制参数,比如设置复用选择器或配置不同的引脚属性。
-
struct pinctrl_map
定义了设备与引脚控制器之间的映射关系,通过 dev_name
和 ctrl_dev_name
识别映射的设备和控制器,根据 type
字段选择使用 data
中的相应数据,完成设备的引脚复用或配置。这种结构体设计有助于抽象和模块化管理复杂设备的引脚配置,提高了设备和引脚控制器之间的灵活性。
dev_pin_info中的pinctrl_state中提到的struct list_head settings:
就是由pinctrl中提到的struct list_head dt_maps转化来的。
struct pinctrl_setting` 是 Linux 引脚控制(pinctrl)子系统中的一个结构体,表示设备的一个特定引脚设置项。每个 `pinctrl_setting` 表示一个配置或复用(mux)设置,定义了具体的引脚配置和用途。多个 `pinctrl_setting` 可以构成一个 `pinctrl_state`,每个 `pinctrl_state` 都包含一系列引脚配置,使得设备在不同模式下可以具有不同的引脚行为。pinctrl-name不是定义了default这些么,他就是状态state,其对应的pinctrl-0下到pinconctroller(左边)对应的引脚组(uart0节点中的引脚组)都是default状态,也就是其引脚转化后的setting都构成一个`pinctrl_state
struct pinctrl_setting {
struct list_head node;
enum pinctrl_map_type type;
struct pinctrl_dev *pctldev;
const char *dev_name;
union {
struct pinctrl_setting_mux mux;
struct pinctrl_setting_configs configs;
} data;
};
-
struct list_head node
- 类型: 链表节点
- 描述: 链接在
pinctrl_state
中的settings
字段中的链表节点。 - 作用: 将多个
pinctrl_setting
链接起来形成一个链表,便于管理和访问每个特定的引脚配置。 - 应用场景: 当设备需要切换到特定状态时,可以通过链表遍历访问每一个引脚的配置,并应用对应设置。
-
enum pinctrl_map_type type
- 类型: 枚举
- 描述: 设置项的类型,用于指明该设置是复用设置(mux)还是配置(configs)。
- 作用: 确定此
pinctrl_setting
的用途:是用来选择引脚复用功能,还是用于引脚的其他设置(如上下拉、驱动强度等)。 - 应用场景: 在应用设置时,根据不同的
type
处理方式不同。
-
struct pinctrl_dev *pctldev
- 类型: 指向引脚控制设备的指针
- 描述: 引脚控制设备的句柄,表示负责应用该设置的设备。
- 作用: 用于定位和操作实际的引脚控制设备,使设置项能够作用于特定设备的引脚。
- 应用场景: 需要向特定设备应用引脚控制时,利用此指针来定位具体设备并应用配置。
-
const char *dev_name
- 类型: 字符串指针
- 描述: 使用此状态的设备名称。
- 作用: 确定当前设置项属于哪个设备,便于关联设备和引脚设置。
- 应用场景: 通过设备名称识别具体的设置目标设备,确保配置项应用在正确的设备上。
-
union data
-
类型: 联合体
-
描述: 包含该设置项类型的特定数据。
-
子成员:
struct pinctrl_setting_mux mux
:用于复用设置的数据,指明引脚的多功能选择。struct pinctrl_setting_configs configs
:用于其他配置的数据,例如上下拉、驱动强度等。
-
作用: 该
data
联合体根据type
提供具体的复用或配置数据。 -
应用场景: 当
type
为复用(mux)时,选择mux
数据;当type
为配置(configs)时,选择configs
数据。
-
struct pinctrl_setting
是一个代表设备引脚配置项的结构体,可以包含复用选择或其他引脚配置。通过 type
区分配置类型,并根据具体类型使用 data
中的数据,pinctrl_setting
可以灵活地管理设备的引脚设置。在设备初始化或模式切换时,可以应用一组 pinctrl_setting
来调整设备的引脚行为。
设备引用pin controller中的某个节点时,这个节点会被转换为一些列的pinctrl_map:
-
转换为多少个pinctrl_map,完全由具体的驱动决定
-
每个pinctrl_map,又被转换为一个pinctrl_setting
-
举例,设备节点里有:
pinctrl-0 = <&state_0_node_a>
- pinctrl-0对应一个状态,会得到一个pinctrl_state
- state_0_node_a节点被解析为一系列的pinctrl_map
- 这一系列的pinctrl_map被转换为一系列的pinctrl_setting
- 这些pinctrl_setting被放入pinctrl_state的settings链表
2. 使用pinctrl_setting
really_probe //dd.c
pinctrl_bind_pins //pinctrl.c
pinctrl_select_state //core.c
/* Apply all the settings for the new state */
list_for_each_entry(setting, &state->settings, node) {
switch (setting->type) {
case PIN_MAP_TYPE_MUX_GROUP: /*使用(复用)引脚*/
ret = pinmux_enable_setting(setting); //pinmux.c // 4.2.1
ret = ops->set_mux(...);
break;
case PIN_MAP_TYPE_CONFIGS_PIN: /*配置引脚*/
case PIN_MAP_TYPE_CONFIGS_GROUP:
ret = pinconf_apply_setting(setting);
ret = ops->pin_config_group_set(...); // 4.2.1
break;
default:
ret = -EINVAL;
break;
}
📎dd.c📎pinctrl.c📎core.c📎pinmux.c