pinctrl子系统

news2025/1/24 17:27:33

目录

一、PinCtrl子系统的定义

二、明确PinCtrl子系统和我们编写驱动的关系

三、pinctrl_desc结构体引入

四、PinCtrl子系统驱动实现分析

1.芯片厂家是如何实现PinCtrl子系统的

2.linux在什么位置设置的引脚复用和电气属性

2.1 really_probe的主要功能

2.2 really_probe函数

2.2.1.  检查设备是否已经重用过设备树节点

2.2.2.  分配引脚容器(pins)

2.2.3.  获取引脚控制器句柄

2.2.4.  查找默认引脚状态

2.2.5.  查找初始化引脚状态(可选)

2.2.6.  激活初始引脚状态

2.2.7.  可选的电源管理状态(sleep 和 idle)

2.2.8.  清理和错误处理

2.2.9.  返回值

2.3 总结


阅读引言:

        pinctrl子系统顾名思义就是引脚控制的意思, 如下图一个Soc芯片有很多的引脚, 那大家有没有想过,我们在写驱动的时候, 是直接调用的一些接口比如设置gpio的电气属性,使用i2c总线就行数据的发送和接收等,这个时候,其实有些引脚是有复用关系的。那么linux是什么时候将我们需要使用的引脚设置为gpio功能, i2c功能的呢? 这个问题就是本文需要解决的疑问。

一、PinCtrl子系统的定义

        PinCtrl子系统(Pin Controller子系统)是Linux内核中的一个重要组件,用于管理和配置芯片引脚的功能和电气特性。其主要功能和作用包括以下几个方面。

  1. 引脚枚举与命名:在系统初始化时,PinCtrl子系统会枚举所有可以控制的引脚,并为每个引脚分配一个唯一的编号。

  2. 引脚复用管理:PinCtrl子系统允许将引脚配置为不同的功能,例如GPIO、I2C、SPI、UART等。一个引脚可以根据需要在不同功能之间切换。

  3. 电气特性配置:PinCtrl子系统可以配置引脚的电气特性,例如上拉/下拉电阻、驱动能力、开漏等。

  4. 引脚状态管理:PinCtrl子系统通过“引脚状态”(Pin State)的概念,管理设备在不同工作状态下的引脚配置。例如,设备在默认状态、睡眠状态或空闲状态下可以有不同的引脚配置。

  5. 设备树支持:PinCtrl子系统通过设备树(Device Tree)获取引脚配置信息,从而实现硬件与软件的解耦。设备驱动可以通过设备树声明所需的引脚配置,PinCtrl子系统负责解析并应用这些配置。

  6. 与GPIO子系统的协同:PinCtrl子系统与GPIO子系统紧密协作,负责引脚的功能复用和电气配置,而GPIO子系统则专注于GPIO的输入输出控制。

PinCtrl子系统的设计目标是提供一个统一的框架,让不同SoC平台的引脚管理更加灵活和高效,同时减少硬件平台之间的差异。

二、明确PinCtrl子系统和我们编写驱动的关系

        PinCtrl子系统实现了Soc芯片引脚的管理、命名、编号, 以及各种配置的实现,配置引脚的复用功能, 设置引脚的电气属性等。这些内容都是芯片厂家的BSP驱动工程师实现好的,我们作为二级驱动开发人员, 只需要知道如何在设备树中指定和配置我们需要的功能。

pinctrl-0 
pinctrl-names

设置这些节点主要使用和设备树中的这两个属性。比如这里的这个键盘的写法

        在这个键盘的设备树节点中就指定了使用的状态, 和具体的哪一个配置。以上便是这个子系统的使用, 使用非常的简单, 我们只需要在设备树中添加子节点, 加上我们需要的引脚配置信息就能使用起来, 接下来我们将具体的分析PinCtrl子系统是如何设置引脚的具体功能的。

三、pinctrl_desc结构体引入

linux源码路径include\linux\pinctrl\pinctrl.h

其实, 各家厂商实现PInCtrl子系统就是在实现这个结构体, 然后注册, 后面我们会在分析,现在先说一说这个结构体的成员, 以及含义。

name: 引脚控制器的名字

pins: 具体某一个引脚的描述结构体指针, 到最后这儿其实指向一个描述整个芯片引脚的数组

pctlops: 操作引脚组的方法结构体指针

pmxops: 设置引脚复用功能的结构体指针

confops: 配置引脚电气属性的结构体指针

owner: 模块归属

struct pinctrl_pin_desc const *pins, 这个成员的原型如下:

const struct pinctrl_ops *pctlops成员的原型如下:

const struct pinmux_ops *pmxops成员的原型如下: 

const struct pinconf_ops *confops成员结构体原型:

        芯片厂家的BSP工程师其实在适配PinCtrl子系统的时候, 其实就是在实现这个结构体中的方法,以及结合自家的设备树的写法, 需要自己的编写从设备树中获得配置信息, 以便在驱动中使用。这个结构体就先介绍到这里, 大家对这个都系先有个印象。

四、PinCtrl子系统驱动实现分析

1.芯片厂家是如何实现PinCtrl子系统的

这里我们以瑞芯微3588为例,来大致看一下设置引脚复用的驱动是如何实现的。这是文件路径:linux-6.6.55\drivers\pinctrl\pinctrl-rockchip.c

这个模块并不是用最基础的module_init宏去将这个函数放入初始化段的, 而是使用的另外一个宏, 这个其实是控制这个模块先加载, 放入的将这个模块放入初始化段中比较靠前的位置,因为这个模块容易被别的模块依赖。

设备树中的这个节点会生成一个平台设备

这个函数中注册了一个平台驱动, 设备树中会生成平台设备,调用注册函数, 会在设备和驱动就行匹配,匹配上之后, 回去调用驱动中的probe函数。

在平台驱动probe函数中会执行一系列的操作, 准备注册一个pinctrl_desc对象

        这部分实现主要是实现各种方法, 以及解析设备树中的信息,将设备树中的信息存储起来给驱动使用。

2.linux在什么位置设置的引脚复用和电气属性

这个小节, 将解决这个问题。

在解决上面这个疑问之前, 需要先了解一下really_probe函数的一些知识, 这是关于平台总线的知识。在Linux内核中,really_probe 函数是设备驱动匹配和绑定过程中的一个关键函数,用于完成设备和驱动的最终绑定操作。它会在以下情况下被调用:

  1. 设备和驱动匹配成功后:当设备(struct device)和驱动(struct device_driver)通过总线的匹配函数(bus->match)确认可以绑定时,会调用 driver_probe_device 函数。随后,driver_probe_device 会进一步调用 really_probe 函数。

  2. 设备添加到系统中时:当设备通过 device_add 函数被添加到系统中时,会触发一系列操作,最终调用 bus_probe_device 函数。bus_probe_device 会尝试将设备与已注册的驱动进行匹配,如果匹配成功,则调用 really_probe

  3. 驱动注册到总线时:当驱动通过 driver_register 函数被注册到系统中时,内核会尝试将该驱动与已存在的设备进行匹配。如果找到匹配的设备,同样会调用 really_probe

2.1 really_probe的主要功能


  • 引脚控制初始化:在调用驱动的 probe 函数之前,really_probe 会调用 pinctrl_bind_pins 来初始化引脚控制。

  • 调用驱动的 probe 函数:如果总线定义了自己的 probe 函数,则先调用总线的 probe 函数;否则调用驱动的 probe 函数。

  • 系统资源管理:完成设备与驱动的绑定,并在失败时进行资源清理。

总结来说,really_probe 是设备与驱动匹配成功后,完成绑定和初始化的关键函数,它在设备添加或驱动注册时被调用。

所以, 接下来我们就知道分析哪里了, 没错就是really_probe函数。

2.2 really_probe函数


在这个函数中回去判断是否使用了pinctrl子系统。

/**
 * pinctrl_bind_pins() - called by the device core before probe
 * @dev: the device that is just about to probe
 */
int pinctrl_bind_pins(struct device *dev)
{
	int ret;

	if (dev->of_node_reused)
		return 0;

	dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);
	if (!dev->pins)
		return -ENOMEM;

	dev->pins->p = devm_pinctrl_get(dev);
	if (IS_ERR(dev->pins->p)) {
		dev_dbg(dev, "no pinctrl handle\n");
		ret = PTR_ERR(dev->pins->p);
		goto cleanup_alloc;
	}

	dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,
					PINCTRL_STATE_DEFAULT);
	if (IS_ERR(dev->pins->default_state)) {
		dev_dbg(dev, "no default pinctrl state\n");
		ret = 0;
		goto cleanup_get;
	}

	dev->pins->init_state = pinctrl_lookup_state(dev->pins->p,
					PINCTRL_STATE_INIT);
	if (IS_ERR(dev->pins->init_state)) {
		/* Not supplying this state is perfectly legal */
		dev_dbg(dev, "no init pinctrl state\n");

		ret = pinctrl_select_state(dev->pins->p,
					   dev->pins->default_state);
	} else {
		ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);
	}

	if (ret) {
		dev_dbg(dev, "failed to activate initial pinctrl state\n");
		goto cleanup_get;
	}

#ifdef CONFIG_PM
	/*
	 * If power management is enabled, we also look for the optional
	 * sleep and idle pin states, with semantics as defined in
	 * <linux/pinctrl/pinctrl-state.h>
	 */
	dev->pins->sleep_state = pinctrl_lookup_state(dev->pins->p,
					PINCTRL_STATE_SLEEP);
	if (IS_ERR(dev->pins->sleep_state))
		/* Not supplying this state is perfectly legal */
		dev_dbg(dev, "no sleep pinctrl state\n");

	dev->pins->idle_state = pinctrl_lookup_state(dev->pins->p,
					PINCTRL_STATE_IDLE);
	if (IS_ERR(dev->pins->idle_state))
		/* Not supplying this state is perfectly legal */
		dev_dbg(dev, "no idle pinctrl state\n");
#endif

	return 0;

	/*
	 * If no pinctrl handle or default state was found for this device,
	 * let's explicitly free the pin container in the device, there is
	 * no point in keeping it around.
	 */
cleanup_get:
	devm_pinctrl_put(dev->pins->p);
cleanup_alloc:
	devm_kfree(dev, dev->pins);
	dev->pins = NULL;

	/* Return deferrals */
	if (ret == -EPROBE_DEFER)
		return ret;
	/* Return serious errors */
	if (ret == -EINVAL)
		return ret;
	/* We ignore errors like -ENOENT meaning no pinctrl state */

	return 0;
}

pinctrl_bind_pins 函数是 Linux 内核中 PinCtrl 子系统的一个重要函数,它的主要作用是为设备初始化引脚控制器(Pin Controller)的状态,并确保设备的引脚配置正确。以下是该函数的主要功能和步骤:


2.2.1.  检查设备是否已经重用过设备树节点
if (dev->of_node_reused)
	return 0;
  • 如果设备的设备树节点已经被重用(of_node_reusedtrue),则直接返回 0,表示无需重新绑定引脚。

  • 这种情况通常出现在设备树中定义了多个设备实例,但它们共享同一个设备树节点时。


2.2.2.  分配引脚容器(pins
dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);
if (!dev->pins)
	return -ENOMEM;
  • 为设备分配一个 struct pinctrl_devinfo 结构体(存储在 dev->pins 中),用于保存引脚控制器相关的信息。

  • 如果分配失败,返回 -ENOMEM


2.2.3.  获取引脚控制器句柄
dev->pins->p = devm_pinctrl_get(dev);
if (IS_ERR(dev->pins->p)) {
	dev_dbg(dev, "no pinctrl handle\n");
	ret = PTR_ERR(dev->pins->p);
	goto cleanup_alloc;
}
  • 通过 devm_pinctrl_get 函数获取设备的引脚控制器句柄(pinctrl_handle)。

  • 如果获取失败(返回错误指针),记录调试信息并清理分配的内存,返回错误码。


2.2.4.  查找默认引脚状态
dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,
					PINCTRL_STATE_DEFAULT);
if (IS_ERR(dev->pins->default_state)) {
	dev_dbg(dev, "no default pinctrl state\n");
	ret = 0;
	goto cleanup_get;
}
  • 使用 pinctrl_lookup_state 查找设备的默认引脚状态(PINCTRL_STATE_DEFAULT)。

  • 如果找不到默认状态,记录调试信息并清理资源,返回错误码。


2.2.5.  查找初始化引脚状态(可选)
dev->pins->init_state = pinctrl_lookup_state(dev->pins->p,
					PINCTRL_STATE_INIT);
if (IS_ERR(dev->pins->init_state)) {
	/* Not supplying this state is perfectly legal */
	dev_dbg(dev, "no init pinctrl state\n");
}
  • 尝试查找初始化引脚状态(PINCTRL_STATE_INIT),如果不存在,记录调试信息但不会报错。


2.2.6.  激活初始引脚状态
if (IS_ERR(dev->pins->init_state)) {
	ret = pinctrl_select_state(dev->pins->p,
				   dev->pins->default_state);
} else {
	ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);
}
  • 如果存在初始化状态,则激活该状态;否则激活默认状态。

  • 如果激活失败,记录调试信息并清理资源,返回错误码。

在这个函数中就会调用到bsp实现好的引脚电气设置、复用功能设置的驱动。


2.2.7.  可选的电源管理状态(sleepidle
#ifdef CONFIG_PM
dev->pins->sleep_state = pinctrl_lookup_state(dev->pins->p,
					PINCTRL_STATE_SLEEP);
if (IS_ERR(dev->pins->sleep_state))
	dev_dbg(dev, "no sleep pinctrl state\n");

dev->pins->idle_state = pinctrl_lookup_state(dev->pins->p,
					PINCTRL_STATE_IDLE);
if (IS_ERR(dev->pins->idle_state))
	dev_dbg(dev, "no idle pinctrl state\n");
#endif
  • 如果启用了电源管理(CONFIG_PM),还会查找设备的睡眠(sleep)和空闲(idle)引脚状态。

  • 如果这些状态不存在,记录调试信息但不会报错。


2.2.8.  清理和错误处理

如果在上述过程中遇到错误,函数会执行清理操作:

cleanup_get:
	devm_pinctrl_put(dev->pins->p);
cleanup_alloc:
	devm_kfree(dev, dev->pins);
	dev->pins = NULL;
  • 释放引脚控制器句柄。

  • 释放分配的 pins 结构体。

  • 清空 dev->pins


2.2.9.  返回值
  • 如果一切正常,返回 0。

  • 如果遇到严重错误(如 -EINVAL),直接返回错误码。

  • 如果是可忽略的错误(如 -ENOENT),也返回 0。


2.3 总结

pinctrl_bind_pins 函数的主要作用是:

  1. 为设备分配和初始化引脚控制器的容器。

  2. 获取引脚控制器句柄。

  3. 查找并激活设备的默认或初始化引脚状态。

  4. 如果启用了电源管理,还会查找睡眠和空闲状态。

  5. 如果过程中遇到错误,会进行清理操作。

这个函数是设备驱动初始化过程中的一部分,确保设备的引脚配置正确,为设备的正常工作提供基础支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2281543.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

行政纠错——pycorrector学习

pycorrector是一个开源中文文本纠错工具&#xff0c;它支持对中文文本进行音似、形似和语法错误的纠正。此工具是使用Python3进行开发的&#xff0c;并整合了Kenlm、ConvSeq2Seq、BERT、MacBERT、ELECTRA、ERNIE、Transformer等多种模型来实现文本纠错功能。pycorrector官方仓库…

深入MapReduce——计算模型设计

引入 通过引入篇&#xff0c;我们可以总结&#xff0c;MapReduce针对海量数据计算核心痛点的解法如下&#xff1a; 统一编程模型&#xff0c;降低用户使用门槛分而治之&#xff0c;利用了并行处理提高计算效率移动计算&#xff0c;减少硬件瓶颈的限制 优秀的设计&#xff0c…

React+Cesium基础教程(001):创建基于React的Cesium项目及对Cesium进行基本配置

文章目录 01-基于react的cesium项目创建基于React的Cesium项目Cesium基本配置设置默认启动视角完整项目下载地址01-基于react的cesium项目 创建基于React的Cesium项目 创建react项目: create-react-app react-cesium-basic安装[cesium1.93.0]版本: npm install cesium@1.…

Vue2:使用sortablejs实现el-table中行拖拽调整顺序

如图,实现拖拽表格中的行来调整行顺序,但是其中的编号仍然是1、2、3、4的顺序,不跟着变化。 实现如下: 一、导入sortablejs import Sortable from "sortablejs";export default { components: {Sortable},data() {return {//数据中的id很重要,拖拽行重新排序…

Kingbase数据库体系结构和日常运维监控

1. 数据库架构 1.1. 内存 1.1.1. Share Memory 共享内存是服务器服务器为数据库缓存和事务日志缓存预留的内存缓存空间&#xff0c;其中最重要的组成部分是Shared Buffer和WAL Buffer&#xff1a; 1. Shared Buffer&#xff1a; 减少磁盘IO 2. WAL Buffer&#xff1a; 用…

【Prometheus】Prometheus如何监控Haproxy

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

【0x0012】HCI_Delete_Stored_Link_Key命令详解

目录 一、命令参数 二、命令格式及参数 2.1. HCI_Delete_Stored_Link_Key 命令格式 2.2. BD_ADDR 2.3. Delete_All 三、生成事件及参数 3.1. HCI_Command_Complete事件 3.2. Status 3.3. Num_Keys_Deleted 四、命令执行流程 4.1. 命令发送阶段 4.2. 控制器处理阶段…

github汉化

本文主要讲述了github如何汉化的方法。 目录 问题描述汉化步骤1.打开github&#xff0c;搜索github-chinese2.打开项目&#xff0c;打开README.md3.下载安装脚本管理器3.1 在README.md中往下滑动&#xff0c;找到浏览器与脚本管理器3.2 选择浏览器对应的脚本管理器3.2.1 点击去…

机器学习-K近邻算法

文章目录 一. 数据集介绍Iris plants dataset 二. 代码三. k值的选择 一. 数据集介绍 鸢尾花数据集 鸢尾花Iris Dataset数据集是机器学习领域经典数据集&#xff0c;鸢尾花数据集包含了150条鸢尾花信息&#xff0c;每50条取自三个鸢尾花中之一&#xff1a;Versicolour、Setosa…

C++函数——fill

在C中&#xff0c;std::fill 是标准库提供的一个算法适用于几乎所有类型的容器&#xff0c;只要这些容器支持迭代器操作。具体来说&#xff0c;std::fill 的适用性取决于容器是否提供了满足其要求的迭代器类型&#xff0c;用于将指定范围内的所有元素设置为某个特定值。它是一个…

如何打造高效同城O2O平台?外卖跑腿系统源码选型与开发指南

打造一个高效的同城O2O平台&#xff0c;选择合适的外卖跑腿系统源码并制定科学的开发方案至关重要。本篇文章&#xff0c;笔者将从源码选型、核心功能、开发架构及运营策略等方面&#xff0c;全面解析O2O平台的搭建思路。 一、外卖跑腿系统源码的选型要点 在搭建O2O平台时&…

Flutter_学习记录_基本组件的使用记录

1.TextWidge的常用属性 1.1TextAlign: 文本对齐属性 常用的样式有&#xff1a; TextAlign.center 居中TextAlign.left 左对齐TextAlign.right 有对齐 使用案例&#xff1a; body: Center(child: Text(开启 TextWidget 的旅程吧&#xff0c;珠珠, 开启 TextWidget 的旅程吧&a…

Qt实践:一个简单的丝滑侧滑栏实现

Qt实践&#xff1a;一个简单的丝滑侧滑栏实现 笔者前段时间突然看到了侧滑栏&#xff0c;觉得这个抽屉式的侧滑栏非常的有趣&#xff0c;打算这里首先尝试实现一个简单的丝滑侧滑栏。 首先是上效果图 &#xff08;C&#xff0c;GIF帧率砍到毛都不剩了&#xff09; QProperty…

10. SpringCloud Alibaba Sentinel 规则持久化部署详细剖析

10. SpringCloud Alibaba Sentinel 规则持久化部署详细剖析 文章目录 10. SpringCloud Alibaba Sentinel 规则持久化部署详细剖析1. 规则持久化1.1 Nacos Server 配置中心-规则持久化实例 2. 最后&#xff1a; 1. 规则持久化 规则没有持久化的问题 如果 sentinel 流控规则没有…

SpringCloud微服务Gateway网关简单集成Sentinel

Sentinel是阿里巴巴开源的一款面向分布式服务架构的轻量级流量控制、熔断降级组件。Sentinel以流量为切入点&#xff0c;从流量控制、熔断降级、系统负载保护等多个维度来帮助保护服务的稳定性。 官方文档&#xff1a;https://sentinelguard.io/zh-cn/docs/introduction.html …

正则表达式以及Qt中的使用

目录 一、正则表达式 1、基本匹配&#xff1a; 2、元字符&#xff1a; 2.1 .运算符&#xff1a; 2.2 字符集&#xff1a; 2.3 重复次数&#xff1a; 2.4 量词{} 2.5 特征标群() 2.6 或运算符 2.7 \反斜线转码特殊字符 2.8 锚点 3、简写字符 4、零宽度断言 4.1 正…

【STM32HAL-----GPIO】

1. 什么是GPIO&#xff1f;&#xff08;了解&#xff09; 2. STM32 GPIO简介 2.1. GPIO特点 2.2. GPIO电气特性 2.3. GPIO引脚分布图 IO引脚分布特点&#xff1a;按组存在、组数视芯片而定、每组最多16个IO引脚。 3. IO端口基本结构介绍 4. GPIO八种工作模式 4.1. 输入浮空 特…

亲测有效!解决PyCharm下PyEMD安装报错 ModuleNotFoundError: No module named ‘PyEMD‘

解决PyCharm下PyEMD安装报错 PyEMD安装报错解决方案 PyEMD安装报错 PyCharm下通过右键自动安装PyEMD后运行报错ModuleNotFoundError: No module named ‘PyEMD’ 解决方案 通过PyCharm IDE python package搜索EMD-signal&#xff0c;选择版本后点击“install”执行安装

低代码系统-产品架构案例介绍、简道云(七)

今天分析另外一个零代码、低代码产品-简道云&#xff0c;跟所有低代码产品的架构图一样&#xff0c;高、大、炫、美。 依然是从下至上&#xff0c;从左到右的顺序。 开发层 搭建中心 表单、流程、报表、用户中心&#xff0c;还是这些内容&#xff0c;自定义打印很多平台都有&am…

Chrome 132 版本新特性

Chrome 132 版本新特性 一、Chrome 132 版本浏览器更新 1. 在 iOS 上使用 Google Lens 搜索 在 Chrome 132 版本中&#xff0c;开始在所有平台上推出这一功能。 1.1. 更新版本&#xff1a; Chrome 126 在 ChromeOS、Linux、Mac、Windows 上&#xff1a;在 1% 的稳定版用户…