Pinctrl子系统中Pincontroller构造过程驱动分析:imx_pinctrl_soc_info结构体

往期内容

本专栏往期内容:

  1. Pinctrl子系统和其主要结构体引入
  2. Pinctrl子系统pinctrl_desc结构体进一步介绍
  3. Pinctrl子系统中client端设备树相关数据结构介绍和解析

input子系统专栏:

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

I2C子系统专栏:

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

总线和设备树专栏:

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

img

前言

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

主要讲解pincontroller中设备树是如何去定义的,以及其驱动程序是如何去对设备树中节点的相关引脚去进行解析、获取相关信息并存储进imx_pinctrl_soc_info结构体当中。

1.设备树

img

对应的驱动程序:drivers\pinctrl\freescale\pinctrl-imx6ul.c📎pinctrl-imx6ul.c,这要是涉及具体的单板,内部还是会调用到pinctrl-imx.c中提供的通用的函数,具体往下面看。

img

2.驱动代码执行流程

img

主要函数是pinrctrl-imx6ull.c中的imx6ul_pinctrl_probe

drivers\pinctrl\freescale\pinctrl-imx6ul.c:
static int imx6ul_pinctrl_probe(struct platform_device *pdev)
{
    const struct of_device_id *match;
    struct imx_pinctrl_soc_info *pinctrl_info;

    // 1. 使用设备树匹配表(imx6ul_pinctrl_of_match)查找是否有匹配的设备节点
    //通过 of_match_device 函数,将设备树中定义的设备节点与 pdev->dev 设备的 compatible 属性进行匹配。
    match = of_match_device(imx6ul_pinctrl_of_match, &pdev->dev);

    // 2. 如果没有找到匹配项,返回 -ENODEV,表示没有此设备
    if (!match)
        return -ENODEV;

    // 3. 取出匹配的设备信息数据(即 pinctrl 的配置信息),并将它转换成合适的数据结构类型
    //match->data 存储了当前 SoC 的 pinctrl 信息,如引脚映射表等内容。通过类型转换将其解析为 struct imx_pinctrl_soc_info 类型,便于后续操作。
    pinctrl_info = (struct imx_pinctrl_soc_info *) match->data;

    // 4. 调用 imx_pinctrl_probe 函数,初始化 pinctrl,并将其注册到系统中
    //将平台设备 pdev 和其 pinctrl 信息 pinctrl_info 传入 imx_pinctrl_probe,完成引脚控制器的初始化。
    return imx_pinctrl_probe(pdev, pinctrl_info);
}

这个 imx6ul_pinctrl_probe 函数是 IMX6UL(NXP i.MX 6UL系列处理器)的引脚控制器(pinctrl)驱动程序中的探测函数,用于在内核加载时初始化该设备的引脚控制功能。此函数通过匹配设备树中的节点,将设备的 pinctrl 配置信息初始化并注册到系统中。

其中imx_pinctrl_probe,这个函数才是主要的。

drivers\pinctrl\freescale\pinctrl-imx.c:

int imx_pinctrl_probe(struct platform_device *pdev,
		      struct imx_pinctrl_soc_info *info)
{
	struct regmap_config config = { .name = "gpr" }; // 注册映射配置,名称为 "gpr"
	struct device_node *dev_np = pdev->dev.of_node; // 获取设备树节点
	struct pinctrl_desc *imx_pinctrl_desc; // 用于描述 pinctrl 的结构体
	struct device_node *np; // 临时设备节点指针
	struct imx_pinctrl *ipctl; // IMX pinctrl 控制器实例
	struct resource *res; // 存储资源信息
	struct regmap *gpr; // 注册映射指针
	int ret, i; // 返回值和循环计数器

	// 检查传入的 pinctrl 信息是否有效
	if (!info || !info->pins || !info->npins) {
		dev_err(&pdev->dev, "wrong pinctrl info\n"); // 打印错误信息
		return -EINVAL; // 返回无效参数错误
	}
	info->dev = &pdev->dev; // 将设备指针保存到信息结构中

	// 如果存在 GPR 兼容性,则获取 GPR 的注册映射
	if (info->gpr_compatible) {
		gpr = syscon_regmap_lookup_by_compatible(info->gpr_compatible);
		if (!IS_ERR(gpr))
			regmap_attach_dev(&pdev->dev, gpr, &config); // 附加设备到注册映射
	}

	// 为驱动创建状态持有者等结构体
	ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL); // 分配内存
	if (!ipctl)
		return -ENOMEM; // 如果内存分配失败,返回错误

	// 检查是否使用 SCU(系统控制单元)
	if (!(info->flags & IMX8_USE_SCU)) {
		// 为每个引脚分配寄存器数组内存
		info->pin_regs = devm_kmalloc(&pdev->dev, sizeof(*info->pin_regs) *
					      info->npins, GFP_KERNEL);
		if (!info->pin_regs)
			return -ENOMEM; // 内存分配失败,返回错误

		// 初始化引脚寄存器结构体
		for (i = 0; i < info->npins; i++) {
			info->pin_regs[i].mux_reg = -1; // 初始化复用寄存器
			info->pin_regs[i].conf_reg = -1; // 初始化配置寄存器
		}

		// 获取设备的内存资源
		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
		ipctl->base = devm_ioremap_resource(&pdev->dev, res); // 映射资源到内存
		if (IS_ERR(ipctl->base))
			return PTR_ERR(ipctl->base); // 映射失败,返回错误

		// 检查设备树中是否存在 "fsl,input-sel" 属性
		if (of_property_read_bool(dev_np, "fsl,input-sel")) {
			np = of_parse_phandle(dev_np, "fsl,input-sel", 0); // 解析设备树句柄
			if (!np) {
				dev_err(&pdev->dev, "iomuxc fsl,input-sel property not found\n"); // 错误信息
				return -EINVAL; // 返回无效参数错误
			}

			ipctl->input_sel_base = of_iomap(np, 0); // 映射输入选择寄存器
			of_node_put(np); // 释放设备节点
			if (!ipctl->input_sel_base) {
				dev_err(&pdev->dev,
					"iomuxc input select base address not found\n"); // 错误信息
				return -ENOMEM; // 内存不足错误
			}
		}
	}

	// 为 pinctrl 描述结构体分配内存
	imx_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*imx_pinctrl_desc),
					GFP_KERNEL);
	if (!imx_pinctrl_desc)
		return -ENOMEM; // 内存分配失败,返回错误

	// 初始化 pinctrl 描述结构体
	imx_pinctrl_desc->name = dev_name(&pdev->dev); // 设置设备名称
	imx_pinctrl_desc->pins = info->pins; // 设置引脚信息
	imx_pinctrl_desc->npins = info->npins; // 设置引脚数量
	imx_pinctrl_desc->pctlops = &imx_pctrl_ops; // 设置 pinctrl 操作
	imx_pinctrl_desc->pmxops = &imx_pmx_ops; // 设置 pinmux 操作
	imx_pinctrl_desc->confops = &imx_pinconf_ops; // 设置 pin 配置操作
	imx_pinctrl_desc->owner = THIS_MODULE; // 设置模块所有者

	// 通过设备树初始化 pinctrl 相关属性
	ret = imx_pinctrl_probe_dt(pdev, info);
	if (ret) {
		dev_err(&pdev->dev, "fail to probe dt properties\n"); // 错误信息
		return ret; // 返回错误
	}

	// 保存信息到 pinctrl 实例中
	ipctl->info = info; // 保存 pinctrl 信息
	ipctl->dev = info->dev; // 保存设备指针
	platform_set_drvdata(pdev, ipctl); // 设置平台驱动数据

	// 注册 pinctrl 驱动
	ipctl->pctl = devm_pinctrl_register(&pdev->dev,
					    imx_pinctrl_desc, ipctl);
	if (IS_ERR(ipctl->pctl)) {
		dev_err(&pdev->dev, "could not register IMX pinctrl driver\n"); // 错误信息
		return PTR_ERR(ipctl->pctl); // 返回错误
	}

	// 初始化成功信息
	dev_info(&pdev->dev, "initialized IMX pinctrl driver\n");

	return 0; // 返回成功
}

3.描述、获得引脚(解析设备树)

3.1 单个引脚

img

/sys/kernel/debug/pinctrl/20e0000.iomuxc]# cat pins

这种控制器支持哪些引脚在代码中就已经写死了,而比如某个芯片中的I2C模块既支持第A组中的引脚,也支持第B组中的引脚(又或者是A组引脚既支持I2C又支持GPIO模块),这些组的引脚则通过pinctrl_ops来描述,具体看下面一点

3.2 某组引脚

在imx6ull中,组引脚的信息是在设备树中进行构造的,而在stm157中则是在代码中构造写死的

比较长,可以看下面图就,建议放大观看。

img

某组引脚中,有哪些引脚?这要分析设备树:imx_pinctrl_probe_dt。

[root@100ask:/sys/kernel/debug/pinctrl/20e0000.iomuxc]# cat pingroups

img

下面是详细的解析代码:

drivers\pinctrl\freescale\pinctrl-imx6ul.c:

int imx_pinctrl_probe(struct platform_device *pdev,
		      struct imx_pinctrl_soc_info *info)
{
	struct regmap_config config = { .name = "gpr" }; // 注册映射配置,名称为 "gpr"
	struct device_node *dev_np = pdev->dev.of_node; // 获取设备树节点
	struct pinctrl_desc *imx_pinctrl_desc; // 用于描述 pinctrl 的结构体
	
    // 。。。。。。。。。。。。。。
	// 为 pinctrl 描述结构体分配内存
	imx_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*imx_pinctrl_desc),
					GFP_KERNEL);
	if (!imx_pinctrl_desc)
		return -ENOMEM; // 内存分配失败,返回错误

	// 初始化 pinctrl 描述结构体
	imx_pinctrl_desc->name = dev_name(&pdev->dev); // 设置设备名称
	imx_pinctrl_desc->pins = info->pins; // 设置引脚信息
	imx_pinctrl_desc->npins = info->npins; // 设置引脚数量
	imx_pinctrl_desc->pctlops = &imx_pctrl_ops; // 设置 pinctrl 操作
	imx_pinctrl_desc->pmxops = &imx_pmx_ops; // 设置 pinmux 操作
	imx_pinctrl_desc->confops = &imx_pinconf_ops; // 设置 pin 配置操作
	imx_pinctrl_desc->owner = THIS_MODULE; // 设置模块所有者

	// 通过设备树初始化 pinctrl 相关属性
	ret = imx_pinctrl_probe_dt(pdev, info);
	if (ret) {
		dev_err(&pdev->dev, "fail to probe dt properties\n"); // 错误信息
		return ret; // 返回错误
	}

	//。。。。。。。。。。。。。。。。。
}

ret = imx_pinctrl_probe_dt(pdev, info);,设备树中组引脚的解析和信息提取主要是在该函数中。其中参2为info,为struct imx_pinctrl_soc_info *类型的,解析该函数钱需要讲解一下该结构体

3.2.1 imx_pinctrl_soc_info结构体

解析后的引脚的组信息会存放在info中

\Linux-4.9.88\drivers\pinctrl\freescale\pinctrl-imx.h:
// 用于描述 IMX 平台的 Pin 控制器的结构体
struct imx_pinctrl_soc_info {
	struct device *dev;               // 设备指针,指向使用该 pinctrl 的设备
	const struct pinctrl_pin_desc *pins; // 指向描述每个 pin 的数组,包含每个引脚的详细信息
	unsigned int npins;               // 引脚数量,表示 pins 数组中的元素数

	struct imx_pin_reg *pin_regs;     // 指向该 SoC 使用的寄存器地址映射结构
	struct imx_pin_group *groups;     // 描述各个引脚组的数组指针,每个组包含一组引脚配置
	unsigned int ngroups;             // 引脚组数量,即 groups 数组的元素数量
	unsigned int group_index;         // 引脚组的索引,用于指示当前配置的组

	struct imx_pmx_func *functions;   // 指向支持的引脚复用功能的数组指针
	unsigned int nfunctions;          // 支持的复用功能数量,即 functions 数组的元素数量
	unsigned int flags;               // 标志位,用于存储当前 pin 控制器的特殊设置或配置

	const char *gpr_compatible;       // 指向字符串,用于设备树兼容性匹配 (GPR) 的信息

	/* 当存在共享 MUX 和 CONF 寄存器的情况时,下面的字段用于控制 */
	unsigned int mux_mask;            // MUX_MODE 的掩码值,用于提取和设置特定位
	u8 mux_shift;                     // MUX_MODE 的位移值,用于确定 mux_mask 应应用的位位置
	u32 ibe_bit;                      // 用于配置输入缓冲区使能 (Input Buffer Enable) 的位掩码
	u32 obe_bit;                      // 用于配置输出缓冲区使能 (Output Buffer Enable) 的位掩码
};

下面是其相关成员的介绍:

  1. struct imx_pin_group *groups: 在 i.MX 平台中定义一个引脚组的集合,该集合中的引脚通常是具有特定功能需求或用途相关的。例如,某些引脚组用于 UART 功能,而另一些用于 SPI、I2C 等功能。通过这种分组,便于对相关引脚的统一配置和管理,同时可以通过 pinctrl 框架将一组引脚配置为同一功能,方便驱动和上层应用进行访问和配置。 这是一个数据指针类型的,也就是说引脚有多少组就该结构体有多少个
/**
 * struct imx_pin_group - 描述一个 i.MX 平台的引脚组(pin group)
 * @name: 引脚组名称
 *        用于标识该引脚组的名称(字符指针),通常用于调试或配置时参考。
 * 
 * @npins: 引脚组中的引脚数量
 *         表示引脚组中的引脚数,即 .pins 数组中的元素数量。
 *         可以根据该值循环遍历 pins 数组中的元素。
 * 
 * @pin_ids: 引脚组中每个引脚的 ID 数组
 *           一个存储每个引脚 ID 的数组(unsigned int* 类型),
 *           是 `pinctrl` 子系统所要求维护的,用于将每个引脚与其特定 ID 进行关联。
 *           引脚 ID 可以帮助查找和操作每个引脚的具体配置。
 * 
 * @pins: 引脚数组
 *        一个 `struct imx_pin` 类型的数组,存储该引脚组中每个引脚的具体信息。
 *        该数组的每个元素对应引脚组中的一个引脚,其结构中可能包括引脚的复用、
 *        功能、驱动强度等详细配置。
 */
struct imx_pin_group {
	const char *name;           // 引脚组的名称,用于标识该组
	unsigned npins;             // 引脚组中包含的引脚数量
	unsigned int *pin_ids;      // 引脚 ID 数组,用于引用每个引脚的唯一标识
	struct imx_pin *pins;       // 引脚数组,存储每个引脚的详细配置
};

其中imx_pin结构体,存储每个引脚的详细配置,它是数组类型。 通过 struct imx_pin,可以配置一个引脚的复用模式、电气特性等参数,适配不同的硬件平台(如基于内存映射或 SCU 管理的硬件)。imx_pin_memmapimx_pin_scu 为不同硬件平台提供了所需的配置结构体,确保在驱动开发中可以灵活地配置引脚功能和特性:

/**
 * struct imx_pin - 描述单个 i.MX 平台的引脚配置
 * @pin: 引脚的编号或 ID
 *       表示该引脚在整个引脚控制器(pinctrl)系统中的唯一标识符,
 *       用于在设置时引用特定的引脚。
 *
 * @pin_conf: 引脚的配置信息,具体使用哪种结构视硬件平台而定
 *            使用共用体(union)来存储引脚配置,有两种配置结构体可选:
 *            1. `imx_pin_memmap` - 内存映射的配置(适用于较旧的 i.MX 硬件)
 *            2. `imx_pin_scu` - SCU 配置(适用于较新的 SCU 管理的 i.MX 硬件)
 */
struct imx_pin {
	unsigned int pin;                // 引脚编号或 ID
	union {
		struct imx_pin_memmap pin_memmap;  // 内存映射的引脚配置
		struct imx_pin_scu pin_scu;        // SCU 管理的引脚配置
	} pin_conf;                       // 选择合适的引脚配置结构
};

/**
 * struct imx_pin_memmap - 描述基于内存映射的引脚配置(较旧的硬件平台)
 * @mux_mode: 复用模式
 *            设置引脚的功能复用模式,例如将该引脚配置为 UART、SPI、GPIO 等。
 *            不同的值对应不同的功能或信号通道。
 *
 * @input_reg: 输入控制寄存器
 *             引脚的输入控制寄存器(16 位),用于配置引脚的输入特性,
 *             比如输入延迟或电平触发控制。
 *
 * @input_val: 输入寄存器的值
 *             具体的输入控制值,决定输入配置的具体参数。设置引脚的输入配置时参考此值。
 *
 * @config: 引脚的通用配置寄存器
 *          该寄存器的值用于设置引脚的电气特性和行为,如驱动强度、上拉/下拉电阻等。
 */
struct imx_pin_memmap {
	unsigned int mux_mode;       // 引脚复用模式
	u16 input_reg;               // 输入控制寄存器
	unsigned int input_val;      // 输入寄存器值
	unsigned long config;        // 通用配置寄存器,用于电气特性设置
};

/**
 * struct imx_pin_scu - 描述基于 SCU 管理的引脚配置(较新硬件平台)
 * @mux: 复用模式寄存器
 *       类似于 mux_mode,但用于 SCU 管理的硬件上。不同值代表不同功能复用。
 *
 * @config: 通用配置寄存器
 *          用于设置引脚的电气特性和配置选项,包括驱动强度、上拉/下拉等。
 *          与 SCU 兼容的配置选项通常通过该寄存器控制。
 */
struct imx_pin_scu {
	unsigned long mux;           // 复用模式寄存器,SCU 管理的硬件专用
	unsigned long config;        // 通用配置寄存器,SCU 兼容的电气特性设置
};
  • img
  • img
  • 以该组引脚为例子,其中一个印记哦MX6UL_PAD_UART1_RTS_B_GPIO1_IO19 0X17059,最后就是会被解析成imx_pin_memmap
  1. 回到imx_pinctrl_soc_info结构体,接下来讲一下其成员struct imx_pmx_func *functionsimx_pmx_func 结构体用于定义 i.MX 平台的 pinmux 功能(pin multiplexing function)。在嵌入式系统中,一个引脚通常具有多种复用功能(如 GPIO、I2C、SPI 等),通过定义 imx_pmx_func,驱动程序可以描述每个特定功能所需要的引脚组,从而在硬件和软件层面实现该功能。
/**
 * struct imx_pmx_func - 描述 i.MX 平台的 pinmux 功能
 * @name: 该功能的名称
 *        此字段用于标识特定的引脚复用(pinmux)功能。例如,可以命名为
 *        `i2c_func`、`spi_func` 等,以表示与不同外设关联的功能名称。
 *
 * @groups: 关联的引脚组
 *          指向引脚组名称的字符串数组,表示执行该功能所需的引脚组。每个引脚组
 *          可以包含多个引脚,用于实现该功能的完整硬件连接。
 *
 * @num_groups: 引脚组的数量
 *              该字段指定 `groups` 数组中的引脚组数量,用于迭代处理数组中的每个引脚组。
 */
struct imx_pmx_func {
	const char *name;         // 功能的名称,标识具体的 pinmux 功能
	const char **groups;      // 对应的引脚组,指向该功能相关的引脚组名称数组
	unsigned num_groups;      // 引脚组的数量,指定 `groups` 数组中的元素个数
};

3.2.2 结构体关联图

img

3.2.3 回到函数解析

用到的设备树示例:

  • img

\Linux-4.9.88\drivers\pinctrl\freescale\pinctrl-imx.c

回到上文提到的imx_pinctrl_probe函数中,其中调用了imx_pinctrl_probe_dt函数,下面对该函数拆开来讲解:该设备树解析函数 imx_pinctrl_probe_dt 是用于解析 i.MX 平台的设备树节点(Device Tree Node),并从中获取引脚控制的配置信息,存储在 imx_pinctrl_soc_info 结构体中。下面逐步解析这段代码如何对应到您设备树的内容。

static int imx_pinctrl_probe_dt(struct platform_device *pdev,
                struct imx_pinctrl_soc_info *info)
{
    struct device_node *np = pdev->dev.of_node; // 获取设备树节点
    struct device_node *child;
    u32 nfuncs = 0;
    u32 i = 0;
    bool flat_funcs;

    if (!np)
        return -ENODEV;
  • np = pdev->dev.of_node;:获取当前设备(即 pdev)在设备树中的节点(对应您设备树中的 imx6ul-evk 节点)。
  1. 判断函数结构
    flat_funcs = imx_pinctrl_dt_is_flat_functions(np); // 检查函数结构
    if (flat_funcs) {
        nfuncs = 1;
    } else {
        nfuncs = of_get_child_count(np);
        if (nfuncs <= 0) {
            dev_err(&pdev->dev, "no functions defined\n");
            return -EINVAL;
        }
    }
  • imx_pinctrl_dt_is_flat_functions(np):检查函数是否以“平面”方式定义。如果 flat_funcs 为真,则表示函数定义是平面的,例如,所有引脚组在一个层级中定义,而不再划分不同的子节点。
  • nfuncs = of_get_child_count(np);:如果不是平面结构,计算 np 节点的子节点数,代表有多少个不同的功能模块(对应 imx6ul-evk 下的子节点,如 hdmigrphoggrp-1enetgrp 等每个模块分别代表一个功能组)。
  • 其实就是看设备树节点中有没有"fsl,pin",以上面的设备树为例子是有的,因此是非平面结构体,其解析方式的函数如下:
static bool imx_pinctrl_dt_is_flat_functions(struct device_node *np)
{
	struct device_node *function_np; // 用于存储 np 节点的子节点
	struct device_node *pinctrl_np;  // 用于存储 function_np 节点的子节点

	for_each_child_of_node(np, function_np) { // 遍历 np 的每个直接子节点
		if (of_property_read_bool(function_np, "fsl,pins"))
			return true; // 如果直接子节点包含 "fsl,pins" 属性,返回 true

		// 遍历 function_np 的每个子节点
		for_each_child_of_node(function_np, pinctrl_np) {
			if (of_property_read_bool(pinctrl_np, "fsl,pins"))
				return false; // 如果找到 "fsl,pins" 在 function_np 的子节点中,返回 false
		}
	}

	return true; // 如果遍历完没有发现嵌套结构,返回 true
}
  1. 分配内存空间
    info->nfunctions = nfuncs;
    info->functions = devm_kzalloc(&pdev->dev, nfuncs * sizeof(struct imx_pmx_func),
                    GFP_KERNEL);
    if (!info->functions)
        return -ENOMEM;

    info->group_index = 0;
    if (flat_funcs) {
        info->ngroups = of_get_child_count(np);
    } else {
        info->ngroups = 0;
        for_each_child_of_node(np, child)
            info->ngroups += of_get_child_count(child);
    }
  • info->nfunctions = nfuncs;:将功能数量保存到 imx_pinctrl_soc_infonfunctions 字段。
  • info->functions 分配内存用于保存各功能的信息。
  • info->ngroups:若为平面结构,则直接获取节点 np 的子节点数;若非平面结构,遍历每个子节点,统计所有子节点的引脚组数量。

3.解析函数与引脚组

img

    info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct imx_pin_group),
                    GFP_KERNEL);
    if (!info->groups)
        return -ENOMEM;

    if (flat_funcs) {
        imx_pinctrl_parse_functions(np, info, 0);
    } else {
        for_each_child_of_node(np, child)
            imx_pinctrl_parse_functions(child, info, i++);
    }

    return 0;
}
  • info->groups:分配用于保存引脚组信息的内存。

  • imx_pinctrl_parse_functions:根据是否为平面结构,选择性地解析功能:

    • 如果是平面结构,则直接解析 np 下的所有引脚组。
    • 如果非平面结构,则遍历 np 的每个子节点(即 imx6ul-evk 下的各功能组节点),分别解析。

img

4.总结

该函数imx_pinctrl_probe_dt主要是根据 imx6ul-evk 下的节点结构来设置功能和引脚组信息,并将这些信息填充到 imx_pinctrl_soc_info 结构体中,便于后续引脚复用的配置。

图中 hoggrp-1hdmigrp 等子节点被解析为各个功能组,fsl,pins 属性用于指定每个功能组内具体的引脚配置。

4.引脚复用和配置

引脚复用和引脚配置在 client端使用pinctrl过程的情景分析 中讲解,也就是下一章节,一般是由client的驱动程序来去调用相关函数实现的。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于YOLO11/v10/v8/v5深度学习的维修工具检测识别系统设计与实现【python源码+Pyqt5界面+数据集+训练代码】

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

jenkins搭建及流水线配置

1.安装docker curl https://mirrors.aliyun.com/repo/Centos-7.repo >> CentOS-Base-Aliyun.repomv CentOS-Base-Aliyun.repo /etc/yum.repos.d/yum -y install yum-utils device-mapper-persistent-data lvm2yum-config-manager --add-repo http://mirrors.aliyun.com/…

vue项目安装组件失败解决方法

1.vue项目 npm install 失败 删除node_modules文件夹、package-lock.json 关掉安装对话框 重新打开对话框 npm install

WPF中如何解决DataGrid的Header没有多余的一行

将最后一行设置DataGridTemplateColumn Width"*" 使其自适应

ros与mqtt相互转换

vda5050 VDA5050协议介绍 和 详细翻译-CSDN博客 ros与mqtt相互转换 如何转换的&#xff0c;通过某个中转包&#xff0c;获取ros的消息然后以需要的格式转换为mqtt 需要的参数 ros相关 parameters[ (ros_subscriber_type, vda5050_msgs/NodeState), (ros_subscriber_queue…

一些硬件知识【2024/11/2】

当需要提供功率型的输出信号的时候&#xff0c;可以在信号发生器外接功率放大器&#xff0c;这样可以提高输出功率 信号的调幅&#xff08;AM&#xff09;、调频&#xff08;FM&#xff09;与调相&#xff08;PM&#xff09;&#xff1a; 调制信号&#xff1a;控制高频振荡的低…

YOLO即插即用---PKIBlock

Poly Kernel Inception Network for Remote Sensing Detection 论文地址 1. 解决的问题 2. 解决方案 3. 解决问题的具体方法 4. 模块的应用 5. 在目标检测任务中的添加位置 6.即插即用代码 论文地址 2403.06258https://arxiv.org/pdf/2403.06258 1. 解决的问题 遥感图…

丝杆支撑座的更换与细节注意事项

丝杆支撑座是支撑连接丝杆和电机的轴承支撑座&#xff0c;分固定侧和支撑侧&#xff0c;它们都有用预压调整的JIS5级的交界处球轴承。在自动化设备中是常用的传动装置&#xff0c;作为核心部件&#xff0c;对设备精度、稳定性和生产效率产生直接影响。在长时间运行中&#xff0…

3D Gaussian Splatting代码详解(一):模型训练、数据加载

1 模型训练 这段代码实现了一个 3D 高斯模型的训练循环&#xff0c;旨在通过逐步优化模型参数&#xff0c;使其能够精确地渲染特定场景。以下是代码的详细解析&#xff1a; def training(dataset, opt, pipe, testing_iterations, saving_iterations, checkpoint_iterations,…

Docker-微服务项目部署

环境准备 1.微服务项目 参考&#xff1a;通过网盘分享的文件&#xff1a;wolf2w_cloud.zip 链接: https://pan.baidu.com/s/1Lr4k6LPIJ59gVNA_DgKM_Q?pwdkjxt 提取码: kjxt 前端项目&#xff1a;trip-mgrsite-ui&#xff0c;trip-website-ui&#xff0c;trip-wenda-ui 服务项…

设计模式讲解01-建造者模式(Builder)

1. 概述 建造者模式也称为&#xff1a;生成器模式 定义&#xff1a;建造者模式是一种创建型设计模式&#xff0c;它允许你将创建复杂对象的步骤与表示方式相分离。 解释&#xff1a;建造者模式就是将复杂对象的创建过程拆分成多个简单对象的创建过程&#xff0c;并将这些简单…

HTML 基础标签——文本内容标签 <ul>、<ol>、<blockquote> 、<code> 等标签的用法详解

文章目录 1. 标题标签2. 段落标签3. 文本格式化标签4. 列表标签4.1 无序列表 `<ul>`4.2 有序列表 `<ol>`5. 引用标签5.1 块引用 `<blockquote>`5.2 行内引用 `<q>`5.3 作品引用 `<cite>`6. 代码和预格式文本标签6.1 代码标签 `<code>`6.2 …

(51)MATLAB迫零均衡器系统建模与性能仿真

文章目录 前言一、迫零均衡器性能仿真说明二、迫零均衡器系统建模与性能仿真代码1.仿真代码2.代码说明3.迫零均衡器zf_equalizer的MATLAB源码 三、仿真结果1.信道的冲击响应2.频率响应3.迫零均衡器的输入和输出 前言 使用MATLAB对迫零均衡器系统进行建模仿真&#xff0c;完整的…

前端请求后端接口报错(blocked:mixed-content),以及解决办法

报错原因&#xff1a;被浏览器拦截了&#xff0c;因为接口地址不是https的。 什么是混合内容&#xff08;Mixed Content&#xff09; 混合内容是指在同一页面中同时包含安全&#xff08;HTTPS&#xff09;和非安全&#xff08;HTTP&#xff09;资源的情况。当浏览器试图加载非…

python 包和模块

一、模块 一个.py 文件就是一个模块&#xff0c;模块是含有一系列数据&#xff0c;函数&#xff0c;类等的程序。 1、模块导入 1.1、impotrt 模块名称 [ as 别名] import nunpy as np 1.2、form 模块名 import 模块内属性名 [ as 别名] from datetime import datetime as d…

Git下载-连接码云-保姆级教学(连接Gitee失败的解决)

Git介绍 码云连接 一、Git介绍 二、Git的工作机制 下载链接&#xff1a;Git - 下载软件包 三、使用步骤 创建一个wss的文件夹&#xff0c;作为‘工作空间’ 四、连接码云账号 五、连接Gitee失败的解决方法 一、Git介绍 Git是一个免费的、开源的分布式版本控制…

https和http的区别,及HTTPS的工作流程

HTTP&#xff08;HyperText Transfer Protocol&#xff09;和HTTPS&#xff08;HyperText Transfer Protocol Secure&#xff09;都是超文本传输协议&#xff0c;但它们之间的关键区别在于安全性。 安全性&#xff1a; HTTP&#xff1a;数据以明文传输&#xff0c;没有加密&…

【Python · Pytorch】人工神经网络 ANN(上)

【Python Pytorch】人工神经网络 ANN&#xff08;上&#xff09; 0. 生物神经网络1. 人工神经网络定义2. 人工神经网络结构2.1 感知机2.2 多层感知机2.3 全连接神经网络2.4 深度神经网络 2. 训练流程※ 数据预处理 (Data Preprocessing) 3. 常见激活函数3.1 Sigmoid / Logisti…

基本查询【MySQL】

文章目录 基本查询插入时是否更新替换查询指定列查询查询字段为表达式为查询结果指定别名结果去重where条件NULL 的查询 结果排序筛选分页结果UpdateDelete截断表聚合函数分组(group by)having && where 基本查询 建表 mysql> create table Student (-> id int…

pandas——数据结构

一、series &#xff08;一&#xff09;创建series import pandas as pd#1.使用列表或数组创建Series # 使用列表创建Series&#xff0c;索引默认从0开始 s1 pd.Series([1, 2, 3]) print(s1) # 使用列表和自定义索引创建Series s2 pd.Series([1, 2, 3], index[a, b, c]) pr…