当前位置: 首页 > article >正文

Pinctrl子系统中client端设备树相关数据结构介绍和解析

往期内容

本专栏往期内容:

  1. Pinctrl子系统和其主要结构体引入
  2. Pinctrl子系统pinctrl_desc结构体进一步介绍

input子系统专栏:

  1. 专栏地址:input子系统
  2. input角度:I2C触摸屏驱动分析和编写一个简单的I2C驱动程序
    – 末片,有往期内容观看顺序

I2C子系统专栏:

  1. 专栏地址:IIC子系统
  2. 具体芯片的IIC控制器驱动程序分析:i2c-imx.c-CSDN博客
    – 末篇,有往期内容观看顺序

总线和设备树专栏:

  1. 专栏地址:总线和设备树
  2. 设备树与 Linux 内核设备驱动模型的整合-CSDN博客
    – 末篇,有往期内容观看顺序

img

目录

  • 往期内容
  • 前言
  • 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的数据结构

img

在上文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:

img

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有两个结构体类型的成员:pinctrlpinctrl_state,pinctrl信息和状态。struct dev_pin_info *pins; 可以被用作数组类型,其中每个 dev_pin_info 结构体对应一个 pinctrl 句柄。因此,如果设备有多个 pinctrl 状态(如设备树中的 pinctrl-0pinctrl-1),则可以通过 pins 数组来管理每个状态。具体来说,struct dev_pin_info 中保存了与引脚状态相关的多个信息,如 default_statesleep_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链表中

img

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;
};
  1. struct list_head node

    • 类型: struct list_head
    • 描述: 这是一个链表节点,用于将 pinctrl 结构体加入到全局的引脚控制状态列表中。
    • 作用: 引脚控制子系统通常需要维护一个系统中所有引脚控制配置的列表,通过这个列表可以有效管理和访问与不同设备相关的所有 pinctrl 结构体。
    • 使用场景: 使用 list_addlist_add_tail 将这个 pinctrl 结构体插入到全局链表中。
  2. struct device *dev

    • 类型: 指向 struct device 的指针
    • 描述: 指向使用该引脚控制句柄的设备。
    • 作用: pinctrl 结构体中的 dev 成员用于关联该引脚控制配置到具体的设备,便于在操作引脚控制时知道该配置属于哪个设备。
  3. struct list_head states

    • 类型: struct list_head
    • 描述: 一个链表头,表示该设备的所有引脚控制状态(pinctrl_state)。
    • 作用: 一个设备可以有多个引脚控制状态,例如不同的电源状态、工作模式等。这个链表记录了该设备的所有状态,以便在需要时切换状态。
  4. struct pinctrl_state *state

    • 类型: 指向 struct pinctrl_state 的指针
    • 描述: 表示当前的引脚控制状态。
    • 作用: 设备可能在不同的工作条件下需要不同的引脚配置,而这个成员保存了当前的引脚控制状态。
  5. struct list_head dt_maps

    • 类型: struct list_head
    • 描述: 从设备树(Device Tree)中动态解析的映射表块(mapping table chunks)。
    • 作用: 如果设备树中有与引脚控制相关的映射数据,它们会被动态加载到这个链表中。该成员帮助 pinctrl 子系统从设备树中获取引脚配置数据。
  6. 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;
};
  1. struct list_head node

    • 类型: 链表节点
    • 描述: 用于将此 pinctrl_state 结构体连接到 struct pinctrlstates 字段的链表中。
    • 作用: 将多个 pinctrl_state 结构体组织在一起,形成一个链表。每个设备可能具有多个不同的状态,使用链表将这些状态链接在一起便于管理和遍历。
    • 应用场景: 当需要为设备设置或切换多个状态时,可以通过遍历链表访问所有状态。
  2. const char *name

    • 类型: 字符串指针
    • 描述: 此状态的名称。
    • 作用: 用于标识和引用该状态名称。例如,在需要将设备配置成特定状态时,可以通过名称来找到对应的 pinctrl_state
    • 应用场景: 通过状态名称切换设备的引脚配置,达到不同模式下引脚行为的定制化。
  3. struct list_head settings

    • 类型: 链表节点
    • 描述: 存储该状态下所有引脚的设置列表。有map转化而来的
    • 作用: 列出当前状态下的引脚配置选项。例如,可以包含每个引脚的模式(复用设置)和参数(例如上下拉、驱动强度等)。
    • 应用场景: 当设备进入此状态时,系统会应用 settings 中的所有设置,以确保设备的引脚行为符合当前模式的要求。

struct pinctrl_state 通过 name 字段标识状态的名称,settings 存储该状态下的所有引脚配置,而 node 将状态链表化。这种设计方式便于设备在不同工作模式之间快速切换引脚配置,满足多样化的引脚功能需求。

1.3 pinctrl_map和pinctrl_setting

img

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;
};
  1. const char *dev_name

    • 类型: 字符串指针
    • 描述: 使用该映射的设备名称。
    • 作用: 指向设备的名称,这个名称应与 struct device 中定义的设备名称一致。如果该名称与引脚控制器本身的 dev_name() 相同,那么该映射条目会在注册时由驱动程序自动接管(“hog”)。
    • 应用场景: 用于识别和定位设备,使得映射条目在正确的设备上应用。
  2. const char *name

    • 类型: 字符串指针
    • 描述: 该特定映射条目的名称。
    • 作用: 用于标识该映射条目。这个参数会传递给 pinmux_lookup_state(),从而在配置引脚控制时通过名称来查找映射。
    • 应用场景: 利用映射名称来选择特定的引脚配置状态。
  3. enum pinctrl_map_type type

    • 类型: 枚举类型 pinctrl_map_type
    • 描述: 映射表条目的类型。
    • 作用: 指定该条目所表示的映射类型。映射类型可以是引脚复用(MUX)映射、配置映射等,不同的类型指示了不同的操作,具体在 data 成员中体现。
  4. const char *ctrl_dev_name

    • 类型: 字符串指针
    • 描述: 控制此映射的设备名称。
    • 作用: 表示实际控制引脚的设备名称,该名称也应与 struct device 中的设备名称相匹配。此字段不适用于 PIN_MAP_TYPE_DUMMY_STATE 类型。
    • 应用场景: 引脚控制器在控制多个引脚时,可以根据 ctrl_dev_name 来确定哪个引脚控制器处理该映射。
  5. union data

    • 类型: 共用体,包含不同类型的数据结构

    • 描述: 根据映射类型存储特定的映射数据。

    • 作用: 该成员根据不同的 type 值存储不同的数据结构。

      • struct pinctrl_map_mux muxtype 为复用映射时,该成员包含复用配置。
      • struct pinctrl_map_configs configstype 为配置映射时,该成员包含引脚配置数据。
    • 应用场景: 根据映射类型设置不同的引脚控制参数,比如设置复用选择器或配置不同的引脚属性。

struct pinctrl_map 定义了设备与引脚控制器之间的映射关系,通过 dev_namectrl_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

img

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;
};
  1. struct list_head node

    • 类型: 链表节点
    • 描述: 链接在 pinctrl_state 中的 settings 字段中的链表节点。
    • 作用: 将多个 pinctrl_setting 链接起来形成一个链表,便于管理和访问每个特定的引脚配置。
    • 应用场景: 当设备需要切换到特定状态时,可以通过链表遍历访问每一个引脚的配置,并应用对应设置。
  2. enum pinctrl_map_type type

    • 类型: 枚举
    • 描述: 设置项的类型,用于指明该设置是复用设置(mux)还是配置(configs)。
    • 作用: 确定此 pinctrl_setting 的用途:是用来选择引脚复用功能,还是用于引脚的其他设置(如上下拉、驱动强度等)。
    • 应用场景: 在应用设置时,根据不同的 type 处理方式不同。
  3. struct pinctrl_dev *pctldev

    • 类型: 指向引脚控制设备的指针
    • 描述: 引脚控制设备的句柄,表示负责应用该设置的设备。
    • 作用: 用于定位和操作实际的引脚控制设备,使设置项能够作用于特定设备的引脚。
    • 应用场景: 需要向特定设备应用引脚控制时,利用此指针来定位具体设备并应用配置。
  4. const char *dev_name

    • 类型: 字符串指针
    • 描述: 使用此状态的设备名称。
    • 作用: 确定当前设置项属于哪个设备,便于关联设备和引脚设置。
    • 应用场景: 通过设备名称识别具体的设置目标设备,确保配置项应用在正确的设备上。
  5. 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链表

img

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;
			}		

img

📎dd.c📎pinctrl.c📎core.c📎pinmux.c


http://www.kler.cn/a/378680.html

相关文章:

  • 【点云学习笔记】——分割任务学习
  • 数学建模学习(135):使用Python基于WSM、WPM、WASPAS的多准则决策分析
  • 运维工具之docker入门
  • 读数据工程之道:设计和构建健壮的数据系统28数据服务常见关注点
  • IsADirectoryError: [Errno 21] Is a directory: ‘xxxxx/.ipynb_checkpoints‘
  • 上市公司环境信息披露质量评分数据王婉菁版(2008-2023年)噪声光污染辐射废水减排等治理
  • 【双目视觉标定】——1原理与实践
  • XSS跨站脚本攻击的实现原理及讲解
  • 第三百零八节 Log4j教程 - Log4j日志到数据库
  • 江协科技STM32学习- P35 硬件I2C读写MPU6050
  • NFTScan Site:以蓝标认证与高级项目管理功能赋能 NFT 项目
  • lua学习笔记---面向对象
  • NVR批量管理软件/平台EasyNVR多个NVR同时管理支持对接阿里云、腾讯云、天翼云、亚马逊S3云存储
  • spark-本地模式的配置和简单使用
  • 【Unity】鼠标点击获取世界坐标位置:物体移动至鼠标点击的位置
  • 设计模式讲解01-建造者模式(Builder)
  • ZDS 数字股票 布局全球视野,开启智能金融新篇章
  • 秒杀优化(异步秒杀,基于redis-stream实现消息队列)
  • node.js rc4加密/解密 不好用怎么办?
  • 中文分词模拟器
  • 双十一晚会停办,一个消费时代结束了
  • 鸿蒙网络编程系列43-仓颉版HttpRequest下载文件示例
  • 第02章 MySQL环境搭建
  • 无人机反步滑膜控制算法!
  • 谷歌浏览器报“喔唷,崩溃啦!”怎么办?
  • 五层塔灯——智能仓储的守护者