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

news2024/11/23 8:25:54

往期内容

本专栏往期内容:

  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的驱动程序来去调用相关函数实现的。

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

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

相关文章

地理信息科学专业想搞GIS开发:学前端还是后端?

地理信息科学专业的同学是学前端开发比较好呢还是学后端开发比较好呢&#xff1f; 部分网友&#xff1a;学前端更好 主修前端更好&#xff0c;因为地信学后端&#xff0c;是卷不赢学计算机的 本科卷前端&#xff0c;硕士阶段可以卷后端 甚至有网友直呼&#xff0c;地信根本没有…

批处理之for语句从入门到精通--呕血整理

文章目录 一、前言二、for语句的基本用法三、文本解析显神威&#xff1a;for /f 用法详解四、翻箱倒柜遍历文件夹&#xff1a;for /r五、仅仅为了匹配第一层目录而存在&#xff1a;for /d六、计数循环&#xff1a;for /l后记 for语句从入门到精通 一、前言 在批处理中&#…

第8章利用CSS制作导航菜单(第八次作业)

效果图如下&#xff1a; Html代码如下&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8"><title>山水之间</title><style type"text/css">import url("../css/work1.css");</style…

Ubuntu22.04 安装图形界面以及XRDP教程

一、准备环境 1.一台服务器安装系统ubuntu&#xff08;这里大部分ubuntu系统可以同用&#xff09; 2.安装的ubuntu系统未安装图形界面 二、操作步骤 1.远程ssh或者直接登录服务器命令行界面 ssh -p 远程端口 rootIP 2.更新系统软件包 sudo apt update # 更新本地的软件包…

深度学习基础知识-编解码结构理论超详细讲解

编解码结构&#xff08;Encoder-Decoder&#xff09;是一种应用广泛且高效的神经网络架构&#xff0c;最早用于序列到序列&#xff08;Seq2Seq&#xff09;任务&#xff0c;如机器翻译、图像生成、文本生成等。随着深度学习的发展&#xff0c;编解码结构不断演变出多种模型变体…

扫描电镜的超低温冷冻制样及传输技术(Cryo-SEM)

扫描电镜的超低温冷冻制样及传输技术(Cryo-SEM) 扫描电镜&#xff08;Scanning Electron Microscope&#xff0c;简称SEM&#xff09;是一种利用聚焦电子束扫描样品表面&#xff0c;通过检测二次电子或反射电子等信号来获取样品表面形貌信息的显微观察技术&#xff1b;然而&…

JS手写:从0开始认识【柯里化】【支持占位符的柯里化】

柯里化 功能介绍 柯里化是拆分函数的一种手段&#xff0c;允许我们以偏函数的方式调用这个函数。 比如说&#xff0c;原来的函数A必须传入三个参数才能运行。经过柯里化处理之后的函数KA传入三个参数&#xff0c;能成功运行&#xff1b;传入两个参数也能&#xff0c;但是会返…

WebSocket 连接频繁断开的问题及解决方案

文章目录 WebSocket 连接频繁断开的问题及解决方案1. 引言2. 什么是 WebSocket&#xff1f;2.1 WebSocket 的优势2.2 WebSocket 的工作原理 3. WebSocket 连接频繁断开的常见原因3.1 服务器端问题3.1.1 服务器负载过高3.1.2 服务器配置不当3.1.3 超时设置 3.2 网络问题3.2.1 网…

openGauss开源数据库实战十二

文章目录 任务十二 openGauss逻辑结构:表管理任务目标实施步骤一、准备工作二、创建表1.新建表默认保存在public模式中2.在一个数据库的不同模式下创建表3.创建表的时候定义约束4.创建表时使用自增数据类型5.使用现有的表创建新表 三、查看表的信息1.在gsql中查看表的定义2.查看…

ADI仿真连接有效性检查方法

1、确认仿真器引脚接插OK. A、检查电脑正常连接 B、确认仿真器引脚定义匹配与上电正确连接 2、打开CCES&#xff0c;打开Debug Configurations 3、连接芯片类型选择 4、点击Configuratior… 5、选择Test…,在点Start&#xff0c;确认状态都OK&#xff0c;即可开始仿真调…

docker部署nginx+nacos+redis+java镜像和容器

nginx镜像制作 Dockerfile内容&#xff1a; # 基础镜像 FROM nginx # author MAINTAINER ruoyi# 挂载目录 VOLUME /home/ruoyi/projects/ruoyi-ui # 创建目录 RUN mkdir -p /home/ruoyi/projects/ruoyi-ui # 指定路径 WORKDIR /home/ruoyi/projects/ruoyi-ui # 复制conf文件到路…

SAP RFC 用户安全授权

一、SAP 通讯用户 对于RFC接口的用户&#xff0c;使用五种用户类型之一的“通讯”类型&#xff0c;这种类型的用户没有登陆SAPGUI的权限。 二、对调用的RFC授权 在通讯用户内部&#xff0c;权限对象&#xff1a;S_RFC中&#xff0c;限制进一步可以调用的RFC函数授权&#xff…

Uniapp的H5以及App不支持后端传FormData类型参数的解决方案

在uniapp中不支持FormData的传参&#xff0c;这就很恶心&#xff1b;如果强行传的话会提示&#xff0c;请求失败的报错信息。 因为后端必须要FormData类型的传参&#xff0c;所以在查阅一系列方案后&#xff0c;有一种解决办法可以完美解决。 代码&#xff1a; init() {const…

PyTorch 训练集、验证集、测试集、模型存档、正则化项

为什么要将数据集划分为三个部分&#xff1f;三个部分的作用&#xff1f;三个部分数据集的比例应如何设定&#xff1f; 另外一种常见的数据集划分方法是将数据集划分为两个部分&#xff08;训练集和测试集&#xff09;&#xff0c;这种划分方法存在的问题在于&#xff0c;模型…

Flask轻松上手:从零开始搭建属于你的Web应用

目录 一、准备工作 二、安装Flask 三、创建你的第一个Flask应用 创建一个新的Python文件 编写Flask应用代码 运行Flask应用 四、创建一个简单的博客系统 定义路由和文章列表 创建模板文件 运行并测试博客系统 五、使用数据库存储用户信息 安装Flask-SQLAlchemy 修…

游戏启动失败:8种修复xinput1_3.dll错误的几种方法教程,轻松解决xinput1_3.dll错误

当你准备好在一天的工作后放松一下&#xff0c;启动你最爱的游戏&#xff0c;却突然收到一个“xinput1_3.dll 丢失”的错误消息&#xff0c;这无疑是令人沮丧的。幸运的是&#xff0c;xinput1_3.dll丢失问题通常可以通过几个简单的步骤来解决。本文将详细介绍这些步骤&#xff…

Halcon-模板匹配(WPF)

halcon的代码 dev_open_window (0, 0, 512, 512, black, WindowHandle) read_image (Image, C:/Users/CF/Desktop/image.jpg) dev_display (Image)draw_rectangle1 (WindowHandle, Row1, Column1, Row2, Column2) gen_rectangle1 (Rectangle, Row1, Column1, Row2, Column2) r…

《AI从0到0.5》之提示工程

参考资料&#xff1a;《AI提示工程&#xff1a;基础 应用 实例》万欣 主要内容&#xff1a; 该文章是对《AI提示工程&#xff1a;基础 应用 实例》这本书的浓缩整理&#xff0c;旨在让读者快速的了解AI提示工程的概念和设计原则、策略和技巧、部分应用案例。并结合笔者自…

@FISCO BCOS的朋友们,年度生态大会邀您查收成果集结令

七载春秋&#xff0c;繁星相映。站在开源七周年的重要节点上&#xff0c;FISCO BCOS年度生态大会再次面向全社区发出产业数字化成果集结令&#xff0c;邀请FISCO BCOS的朋友们于今年12月份共探区块链产业的发展现状与未来。 作为深圳国际金融科技节的重要组成部分和特色活动&a…

Linux文件清空的五种方法总结分享

简介&#xff1a; 每种方法各有优势&#xff0c;选择最合适的一种或几种&#xff0c;可以极大提高您的工作效率。更多有关Linux系统管理的技巧与资源&#xff0c;欢迎访问&#xff0c;持续提升您的运维技能。 在Linux操作系统环境下&#xff0c;清空文件内容是日常维护和管理中…