首页 最新 热门 推荐

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

Pinctrl子系统pinctrl_desc结构体进一步介绍

  • 25-03-04 14:01
  • 4554
  • 11190
blog.csdn.net

往期内容

本专栏往期内容:

  1. Pinctrl子系统和其主要结构体引入

input子系统专栏:

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

I2C子系统专栏:

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

总线和设备树专栏:

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

img

前言

在上一篇文章中对Pincontroller进行了简单的介绍(Pinctrl子系统和其主要结构体引入),以及对设备树也进行了示范,对Pincontroller的结构体进行的引入,也就是起了个开头,知道了是用pinctrl_dev来指代一个Pincontroller,可以提到了可以通过提供一个pinctrl_desc再去调用某个函数来实现一个pinctrl_dev。那么接下来就进一步讲解。

那么接下来看看pinctrl_dev --> pinctrl_desc *desc --> pinctrl_ops、pinmux_ops、pinconf_ops:

1. 作用1:描述、获得引脚 pinctrl_ops

使用pinctrl_ops来操作引脚,主要功能有二:

  • 来取出某组的引脚:get_groups_count、get_group_pins
  • 处理设备树中pin controller中的某个节点:dt_node_to_map,把device_node转换为一系列的pinctrl_mapimg
\Linux-4.9.88\include\linux\pinctrl\pinctrl.h

struct pinctrl_ops {
	int (*get_groups_count) (struct pinctrl_dev *pctldev);
	const char *(*get_group_name) (struct pinctrl_dev *pctldev,
				       unsigned selector);
	int (*get_group_pins) (struct pinctrl_dev *pctldev,
			       unsigned selector,
			       const unsigned **pins,
			       unsigned *num_pins);
	void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s,
			  unsigned offset);
	int (*dt_node_to_map) (struct pinctrl_dev *pctldev,
			       struct device_node *np_config,
			       struct pinctrl_map **map, unsigned *num_maps);
	void (*dt_free_map) (struct pinctrl_dev *pctldev,
			     struct pinctrl_map *map, unsigned num_maps);
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

struct pinctrl_ops 结构体定义了全局引脚控制操作(pin control operations),这些操作需要由引脚控制器驱动程序实现。该结构体中的函数指针代表不同的操作接口,允许驱动程序通过这些接口与引脚控制子系统进行交互。

  • get_groups_count: 返回当前已注册的引脚组(pin group)数量。该函数用于获取系统中引脚组的总数。
  • get_group_name: 返回特定引脚组的名称。通过组选择器 selector 作为参数,驱动可以获取某个引脚组的名称。
  • get_group_pins: 返回与特定组选择器对应的引脚数组,并通过参数 pins 和 num_pins 返回该数组的指针和引脚数量。此函数用于查询引脚组包含的具体引脚。
  • pin_dbg_show: 可选的 debugfs 显示挂钩,用于在调试文件系统(debugfs)中展示每个引脚的设备相关信息。它可以在调试时提供关于某个引脚的详细信息。
  • dt_node_to_map: 解析设备树(Device Tree)中的 “pin 配置节点” 并为其创建映射表项(mapping table entries)。这些映射表项通过 map 和 num_maps 输出参数返回。该函数是可选的,适用于支持设备树的引脚控制器驱动。
  • dt_free_map: 释放通过 dt_node_to_map 创建的映射表项。顶层的 map 指针需要释放,同时还要释放映射表项中动态分配的成员。该函数是可选的,对于不支持设备树的引脚控制器驱动,可以忽略此函数。

这些操作为引脚控制子系统提供了操作引脚组、解析设备树节点、调试显示等功能接口。

2. 作用2:引脚复用 pinmux_ops

img

把某一组引脚配置成某一功能,GPIO模式??或是其它模式

\Linux-4.9.88\include\linux\pinctrl\pinmux.h
struct pinmux_ops {
	int (*request) (struct pinctrl_dev *pctldev, unsigned offset);
	int (*free) (struct pinctrl_dev *pctldev, unsigned offset);
	int (*get_functions_count) (struct pinctrl_dev *pctldev);
	const char *(*get_function_name) (struct pinctrl_dev *pctldev,
					  unsigned selector);
	int (*get_function_groups) (struct pinctrl_dev *pctldev,
				  unsigned selector,
				  const char * const **groups,
				  unsigned *num_groups);
	int (*set_mux) (struct pinctrl_dev *pctldev, unsigned func_selector,
			unsigned group_selector);
	int (*gpio_request_enable) (struct pinctrl_dev *pctldev,
				    struct pinctrl_gpio_range *range,
				    unsigned offset);
	void (*gpio_disable_free) (struct pinctrl_dev *pctldev,
				   struct pinctrl_gpio_range *range,
				   unsigned offset);
	int (*gpio_set_direction) (struct pinctrl_dev *pctldev,
				   struct pinctrl_gpio_range *range,
				   unsigned offset,
				   bool input);
	bool strict;
};
  • 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

struct pinmux_ops 结构体定义了引脚复用(pinmux)操作,主要用于实现支持引脚复用功能的引脚控制器驱动程序。该结构体提供了一系列回调函数,允许引脚控制器子系统与引脚复用功能进行交互。

  • request: 核心功能调用,用于判断特定的引脚是否可以被用于复用。在实际选择复用设置前,核心会调用该函数来请求引脚。驱动程序可以通过返回负值拒绝该请求。
  • free: 与 request() 相反,释放被请求的引脚。这是在引脚复用完成后释放引脚的回调函数。
  • get_functions_count: 返回当前引脚复用驱动中可选择的复用功能数量。
  • get_function_name: 根据复用选择器 selector 返回某个复用功能的名称。核心通过调用此函数来确定应将某个设备映射到哪个复用设置。
  • get_function_groups: 根据功能选择器 selector 返回与该复用功能相关的引脚组名称数组,并通过 groups 和 num_groups 返回受影响的组及其数量。可以与 pinctrl_ops 中的函数结合使用以获取受影响的引脚。
  • set_mux: 启用特定的复用功能与引脚组关联。该函数根据 func_selector 选择特定的复用功能,并根据 group_selector 选择一组引脚进行复用设置。驱动程序不需要检测复用冲突,系统会自动处理引脚冲突。
  • gpio_request_enable: 请求并启用某个引脚的 GPIO 模式。如果引脚控制器支持每个引脚单独复用为 GPIO 模式,则需要实现此函数。参数包括 GPIO 范围和在该范围内的引脚偏移量。
  • gpio_disable_free: 释放之前启用的 GPIO 复用设置,与 gpio_request_enable 作用相反。
  • gpio_set_direction: 对于需要引脚复用的 GPIO 控制器,当 GPIO 配置为输入或输出时可能需要不同的设置。该函数允许控制引脚方向(输入或输出)。
  • strict: 如果为真,则不允许引脚同时作为 GPIO 和复用其他功能使用。在批准引脚请求之前,会严格检查 gpio_owner 和 mux_owner 以防止冲突。

pinmux_ops 提供了驱动与引脚复用子系统之间的交互接口,用于管理引脚复用、GPIO 配置、引脚组和功能的分配。

3. 作用3:引脚配置 pinconf_ops

img

上拉?下拉?等等

\Linux-4.9.88\include\linux\pinctrl\pinconf.h
struct pinconf_ops {
#ifdef CONFIG_GENERIC_PINCONF
	bool is_generic;
#endif
	int (*pin_config_get) (struct pinctrl_dev *pctldev,
			       unsigned pin,
			       unsigned long *config);
	int (*pin_config_set) (struct pinctrl_dev *pctldev,
			       unsigned pin,
			       unsigned long *configs,
			       unsigned num_configs);
	int (*pin_config_group_get) (struct pinctrl_dev *pctldev,
				     unsigned selector,
				     unsigned long *config);
	int (*pin_config_group_set) (struct pinctrl_dev *pctldev,
				     unsigned selector,
				     unsigned long *configs,
				     unsigned num_configs);
	int (*pin_config_dbg_parse_modify) (struct pinctrl_dev *pctldev,
					   const char *arg,
					   unsigned long *config);
	void (*pin_config_dbg_show) (struct pinctrl_dev *pctldev,
				     struct seq_file *s,
				     unsigned offset);
	void (*pin_config_group_dbg_show) (struct pinctrl_dev *pctldev,
					   struct seq_file *s,
					   unsigned selector);
	void (*pin_config_config_dbg_show) (struct pinctrl_dev *pctldev,
					    struct seq_file *s,
					    unsigned long config);
};
  • 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

struct pinconf_ops 结构体定义了引脚配置操作,用于支持引脚配置功能的驱动程序实现。它包含一系列函数指针,这些函数用于获取和设置单个引脚及引脚组的配置。

  • is_generic: (可选)如果引脚控制器希望使用通用接口,设置该标志以告诉框架其为通用接口。
  • pin_config_get: 获取特定引脚的配置。如果请求的配置在该控制器上不可用,返回 -ENOTSUPP;如果可用但被禁用,返回 -EINVAL。
  • pin_config_set: 配置单个引脚的设置。该函数接受引脚的配置参数和数量,允许驱动程序在特定引脚上设置多个配置。
  • pin_config_group_get: 获取特定引脚组的配置。该函数通过选择器返回整个引脚组的配置,便于一次性读取多个引脚的设置。
  • pin_config_group_set: 配置引脚组内所有引脚的设置。与 pin_config_set 类似,但作用于整个引脚组。
  • pin_config_dbg_parse_modify: (可选)用于调试文件系统的功能,允许修改引脚配置。
  • pin_config_dbg_show: (可选)调试文件系统中的显示钩子,提供特定引脚的设备信息。
  • pin_config_group_dbg_show: (可选)调试文件系统中的显示钩子,提供特定引脚组的设备信息。
  • pin_config_config_dbg_show: (可选)调试文件系统中的显示钩子,解码并显示驱动程序的引脚配置参数。

4. 使用pinctrl_desc注册得到pinctrl_dev

分析的文件:

  • drivers\pinctrl\freescale\pinctrl-imx6ul.c?pinctrl-imx6ul.c
  • pincontroller的驱动程序文件 。pinctrl-imx.c 文件是 Linux 内核中针对 NXP(之前是 Freescale)i.MX 系列 SoC(系统芯片)的引脚控制器驱动程序实现。这驱动程序通常用于管理和配置 SoC 中的引脚,允许用户和其他系统组件以灵活的方式控制引脚的功能和行为。是一个更通用的驱动,支持多个 i.MX 系列的 SoC。提供了一些基础的、通用的功能或结构,其中关键的是imx_pinctrl_probe函数

imx_pinctrl_probe内部调用了核心层(core.c?core.c)devm_pinctrl_register(里面又调用了pinctrl_register),就可以根据pinctrl_desc构造出pinctrl_dev,并且把pinctrl_dev放入链表:

\Linux-4.9.88\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" }; // 定义寄存器映射配置结构体
	struct device_node *dev_np = pdev->dev.of_node; // 获取设备的设备树节点
	struct pinctrl_desc *imx_pinctrl_desc; // 指向 pinctrl 描述符的指针
	struct device_node *np; // 设备树节点指针
	struct imx_pinctrl *ipctl; // 指向 i.MX 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; // 将设备指针赋值给 info 结构体

	// 检查是否有与 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); // 分配内存用于 ipctl 结构
	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); // 设置 pinctrl 名称
	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; // 设置 pinconf 操作
	imx_pinctrl_desc->owner = THIS_MODULE; // 设置模块拥有者

	// 调用设备树解析函数
	ret = imx_pinctrl_probe_dt(pdev, info);
	if (ret) {
		dev_err(&pdev->dev, "fail to probe dt properties\n"); // 打印错误信息
		return ret; // 返回错误
	}

	// 设置 ipctl 结构中的信息
	ipctl->info = info;
	ipctl->dev = info->dev;
	platform_set_drvdata(pdev, ipctl); // 将 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

可以看到,在其probe函数中主要是去配置pinctrl_desc,然后调用devm_pinctrl_register去构建pinctrl_dev:

\Linux-4.9.88\drivers\pinctrl\core.c:
struct pinctrl_dev *devm_pinctrl_register(struct device *dev,
					  struct pinctrl_desc *pctldesc,
					  void *driver_data)
{
	struct pinctrl_dev **ptr, *pctldev; // 定义指向 pinctrl_dev 的指针

	// 为资源管理分配内存,大小是指针大小,使用 devm (device managed) 内存管理机制
	ptr = devres_alloc(devm_pinctrl_dev_release, sizeof(*ptr), GFP_KERNEL); 
	if (!ptr) // 检查内存分配是否成功
		return ERR_PTR(-ENOMEM); // 如果分配失败,返回内存不足错误

	// 调用 `pinctrl_register()` 注册 pinctrl 控制器
	pctldev = pinctrl_register(pctldesc, dev, driver_data);
	if (IS_ERR(pctldev)) { // 检查注册是否成功
		devres_free(ptr); // 如果注册失败,释放分配的资源
		return pctldev; // 返回错误指针
	}

	// 将注册的 pinctrl_dev 设备保存在资源管理指针中
	*ptr = pctldev;
	devres_add(dev, ptr); // 将该资源与设备关联,确保设备卸载时自动释放资源

	return pctldev; // 返回成功注册的 pinctrl_dev 设备
}
  • 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

先是分配pinctrl_dev,然后调用pinctrl_register()函数去注册pinctl控制器,来指代一个pincontroller, 核心工作是为设备分配并初始化 pinctrl_dev 结构体,并将其注册到 pin control 子系统中。它通过操作检查确保实现的功能完整,处理 pin 的注册和状态设置

/**
 * pinctrl_register() - 注册一个 pin 控制器设备
 * @pctldesc: 描述 pin 控制器的结构体
 * @dev: 父设备
 * @driver_data: 驱动程序的私有数据
 */
struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
				    struct device *dev, void *driver_data)
{
	struct pinctrl_dev *pctldev; // 定义 pin 控制器设备结构体指针
	int ret; // 用于保存函数返回值的变量

	// 检查输入参数的有效性,如果描述符为空或描述符的名字为空,返回错误指针
	if (!pctldesc)
		return ERR_PTR(-EINVAL);
	if (!pctldesc->name)
		return ERR_PTR(-EINVAL);

	// 分配内存为 pin 控制器设备结构体,并初始化为 0
	pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);
	if (pctldev == NULL) {
		dev_err(dev, "failed to alloc struct pinctrl_dev\n"); // 输出分配失败的错误消息
		return ERR_PTR(-ENOMEM); // 返回内存不足的错误
	}

	// 初始化 pin 控制器设备结构体
	pctldev->owner = pctldesc->owner; // 赋值设备的所有者
	pctldev->desc = pctldesc; // 关联描述符
	pctldev->driver_data = driver_data; // 关联驱动私有数据
	INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL); // 初始化 `pin_desc_tree` 为 radix 树,用于描述 pin
	INIT_LIST_HEAD(&pctldev->gpio_ranges); // 初始化 GPIO 范围的链表
	pctldev->dev = dev; // 关联设备结构
	mutex_init(&pctldev->mutex); // 初始化互斥锁

	// 核查核心操作接口的完整性,确保驱动实现了必要的功能
	ret = pinctrl_check_ops(pctldev);
	if (ret) {
		dev_err(dev, "pinctrl ops lacks necessary functions\n"); // 输出缺少必要操作的错误消息
		goto out_err; // 如果失败,跳转到错误处理
	}

	// 如果实现了 pinmux 操作,检查其操作的完整性
	if (pctldesc->pmxops) {
		ret = pinmux_check_ops(pctldev);
		if (ret)
			goto out_err;
	}

	// 如果实现了 pinconfig 操作,检查其操作的完整性
	if (pctldesc->confops) {
		ret = pinconf_check_ops(pctldev);
		if (ret)
			goto out_err;
	}

	// 注册所有的 pin
	dev_dbg(dev, "try to register %d pins ...\n",  pctldesc->npins);
	ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins); // 注册 pins
	if (ret) {
		dev_err(dev, "error during pin registration\n"); // 输出 pin 注册失败的错误消息
		pinctrl_free_pindescs(pctldev, pctldesc->pins, pctldesc->npins); // 如果失败,释放 pin 资源
		goto out_err; // 跳转到错误处理
	}

	// 加入到全局的 pin 控制器设备列表
	mutex_lock(&pinctrldev_list_mutex);
	list_add_tail(&pctldev->node, &pinctrldev_list); // 将设备添加到设备列表的尾部
	mutex_unlock(&pinctrldev_list_mutex);

	// 获取 pinctrl 句柄
	pctldev->p = pinctrl_get(pctldev->dev);

	// 尝试查找并选择设备的默认和睡眠状态
	if (!IS_ERR(pctldev->p)) {
		// 查找并选择默认状态
		pctldev->hog_default = pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);
		if (IS_ERR(pctldev->hog_default)) {
			dev_dbg(dev, "failed to lookup the default state\n");
		} else {
			if (pinctrl_select_state(pctldev->p, pctldev->hog_default))
				dev_err(dev, "failed to select default state\n");
		}

		// 查找睡眠状态
		pctldev->hog_sleep = pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_SLEEP);
		if (IS_ERR(pctldev->hog_sleep))
			dev_dbg(dev, "failed to lookup the sleep state\n");
	}

	// 初始化 debugfs 调试文件系统
	pinctrl_init_device_debugfs(pctldev);

	return pctldev; // 返回注册成功的 pin 控制器设备结构体指针

out_err:
	mutex_destroy(&pctldev->mutex); // 销毁互斥锁
	kfree(pctldev); // 释放设备结构体内存
	return ERR_PTR(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
  • 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
  • 在drivers\pinctrl\freescale\pinctrl-imx6ul.c?pinctrl-imx6ul.c中注册了平台驱动后,其 probe 先通过设备树匹配找到对应的 pinctrl_info,然后传递给通用的 pinctrl-imx.c 的 probe 函数。这确保了驱动能够正确识别和初始化针对特定硬件的引脚配置。 所以pinctrl-im6ull.c是通用的。
static int imx6ul_pinctrl_probe(struct platform_device *pdev)
{
	const struct of_device_id *match;
	struct imx_pinctrl_soc_info *pinctrl_info;

	match = of_match_device(imx6ul_pinctrl_of_match, &pdev->dev);

	if (!match)
		return -ENODEV;

	pinctrl_info = (struct imx_pinctrl_soc_info *) match->data;

	return imx_pinctrl_probe(pdev, pinctrl_info); //这里就是上文中pinctrl-imx.c中定义的
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
文章知识点与官方知识档案匹配,可进一步学习相关知识
C技能树结构体结构体简介220410 人正在系统学习中
注:本文转载自blog.csdn.net的憧憬一下的文章"https://blog.csdn.net/caiji0169/article/details/143376984"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

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

分类栏目

后端 (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