首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

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

  • 25-03-04 14:01
  • 3036
  • 13878
blog.csdn.net

往期内容

本专栏往期内容:

  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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

这个 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; // 返回成功
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111

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

3.1 单个引脚

img

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

这种控制器支持哪些引脚在代码中就已经写死了,而比如某个芯片中的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
  • 1

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; // 返回错误
	}

	//。。。。。。。。。。。。。。。。。
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

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

  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;       // 引脚数组,存储每个引脚的详细配置
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

其中imx_pin结构体,存储每个引脚的详细配置,它是数组类型。 通过 struct imx_pin,可以配置一个引脚的复用模式、电气特性等参数,适配不同的硬件平台(如基于内存映射或 SCU 管理的硬件)。imx_pin_memmap 和 imx_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 兼容的电气特性设置
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • img
  • img
  • 以该组引脚为例子,其中一个印记哦MX6UL_PAD_UART1_RTS_B_GPIO1_IO19 0X17059,最后就是会被解析成imx_pin_memmap
  1. 回到imx_pinctrl_soc_info结构体,接下来讲一下其成员struct imx_pmx_func *functions,imx_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` 数组中的元素个数
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 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;
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • imx_pinctrl_dt_is_flat_functions(np):检查函数是否以“平面”方式定义。如果 flat_funcs 为真,则表示函数定义是平面的,例如,所有引脚组在一个层级中定义,而不再划分不同的子节点。
  • nfuncs = of_get_child_count(np);:如果不是平面结构,计算 np 节点的子节点数,代表有多少个不同的功能模块(对应 imx6ul-evk 下的子节点,如 hdmigrp、hoggrp-1、enetgrp 等每个模块分别代表一个功能组)。
  • 其实就是看设备树节点中有没有"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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  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);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • info->nfunctions = nfuncs;:将功能数量保存到 imx_pinctrl_soc_info 的 nfunctions 字段。
  • 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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • info->groups:分配用于保存引脚组信息的内存。

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

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

img

4.总结

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

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

4.引脚复用和配置

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

文章知识点与官方知识档案匹配,可进一步学习相关知识
C技能树首页概览220410 人正在系统学习中
注:本文转载自blog.csdn.net的憧憬一下的文章"https://blog.csdn.net/caiji0169/article/details/143443022"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top