devm_fwnode_get_gpiod_from_child 函数

 Linux version: 4.14

Code link: Linux source code (v4.14) - Bootlin


1  devm_fwnode_get_gpiod_from_child 函数

static inline
struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev,
						   const char *con_id,
						   struct fwnode_handle *child,
						   enum gpiod_flags flags,
						   const char *label)
{
	return devm_fwnode_get_index_gpiod_from_child(dev, con_id, 0, child,
						      flags, label);
}

2  devm_fwnode_get_index_gpiod_from_child 函数

struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
						const char *con_id, int index,
						struct fwnode_handle *child,
						enum gpiod_flags flags,
						const char *label)
{
	char prop_name[32]; /* 32 is max size of property name */
	struct gpio_desc **dr;
	struct gpio_desc *desc;
	unsigned int i;

	dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
			  GFP_KERNEL);
	if (!dr)
		return ERR_PTR(-ENOMEM);

	for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
		if (con_id)
			snprintf(prop_name, sizeof(prop_name), "%s-%s",
					    con_id, gpio_suffixes[i]);
		else
			snprintf(prop_name, sizeof(prop_name), "%s",
					    gpio_suffixes[i]);

		desc = fwnode_get_named_gpiod(child, prop_name, index, flags,
					      label);
		if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT))
			break;
	}
	if (IS_ERR(desc)) {
		devres_free(dr);
		return desc;
	}

	*dr = desc;
	devres_add(dev, dr);

	return desc;
}
EXPORT_SYMBOL(devm_fwnode_get_index_gpiod_from_child);

可以看到 gpio 的属性名 prop_name 是由 con_id (如果有的话)和 gpio_suffixes[i] 拼接而成,然后调用 fwnode_get_named_gpiod 函数来获取 gpiod。gpio_suffixes 的定义如下,后缀用 gpio 或者 gpios 都可以。

/* gpio suffixes used for ACPI and device tree lookup-用于ACPI和设备树查找的gpio后缀 */
static const char * const gpio_suffixes[] = { "gpios", "gpio" };

3  devm_fwnode_get_index_gpiod_from_child 函数

struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
					 const char *propname, int index,
					 enum gpiod_flags dflags,
					 const char *label)
{
	struct gpio_desc *desc = ERR_PTR(-ENODEV);
	unsigned long lflags = 0;
	bool active_low = false;
	bool single_ended = false;
	bool open_drain = false;
	int ret;

	if (!fwnode)
		return ERR_PTR(-EINVAL);

	if (is_of_node(fwnode)) {
		enum of_gpio_flags flags;

		desc = of_get_named_gpiod_flags(to_of_node(fwnode), propname,
						index, &flags);
		if (!IS_ERR(desc)) {
			active_low = flags & OF_GPIO_ACTIVE_LOW;
			single_ended = flags & OF_GPIO_SINGLE_ENDED;
			open_drain = flags & OF_GPIO_OPEN_DRAIN;
		}
	} else if (is_acpi_node(fwnode)) {
		struct acpi_gpio_info info;

		desc = acpi_node_get_gpiod(fwnode, propname, index, &info);
		if (!IS_ERR(desc)) {
			active_low = info.polarity == GPIO_ACTIVE_LOW;
			ret = acpi_gpio_update_gpiod_flags(&dflags, info.flags);
			if (ret)
				pr_debug("Override GPIO initialization flags\n");
		}
	}

	if (IS_ERR(desc))
		return desc;

	ret = gpiod_request(desc, label);
	if (ret)
		return ERR_PTR(ret);

	if (active_low)
		lflags |= GPIO_ACTIVE_LOW;

	if (single_ended) {
		if (open_drain)
			lflags |= GPIO_OPEN_DRAIN;
		else
			lflags |= GPIO_OPEN_SOURCE;
	}

	ret = gpiod_configure_flags(desc, propname, lflags, dflags);
	if (ret < 0) {
		gpiod_put(desc);
		return ERR_PTR(ret);
	}

	return desc;
}
EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod);

上述代码中的 is_of_node(fwnode) 判断 fwnode 是否为设备树结点,而 is_acpi_node(fwnode) 判断 fwnode 是否为 ACPI 结点。这里我们使用了设备树,所以 is_of_node(fwnode) 函数返回为真。

补充:fwnode 指的是固件结点,通常表示设备树或 ACPI(通常是DSDT表)中的条目。设备树和 ACPI是定义设备及其属性和它们之间的互联的两种不同的方式。他们都使用树结构来编码这些信息。给定 struct_device 上的 fwnode 成员是该设备的相应固件表中的结点。ACPI 在基于 x86/UEFI 的系统中很常见,设备树在 ARM 系统中很常见。fwnode 可以与接受 fwnode 句柄的内核 API 一起使用。一些不错的引用文档:

设备树:https://www.kernel.org/doc/Documentation/devicetree/usage-model.txt

_DSDT 中的 DSD 图:https://www.kernel.org/doc/Documentation/acpi/dsd/graph.txt

4  of_get_named_gpiod_flags 函数

struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
		     const char *propname, int index, enum of_gpio_flags *flags)
{
	struct of_phandle_args gpiospec;
	struct gpio_chip *chip;
	struct gpio_desc *desc;
	int ret;

	ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index,
					 &gpiospec);
	if (ret) {
		pr_debug("%s: can't parse '%s' property of node '%pOF[%d]'\n",
			__func__, propname, np, index);
		return ERR_PTR(ret);
	}

    // 遍历 gpio_devices 链表中的每一个 gpio_device,
    // 将每一个 gpio_device->chip 与 gpiospec 进行对比,并返回匹配的 chip */
	chip = of_find_gpiochip_by_xlate(&gpiospec);
	if (!chip) {
		desc = ERR_PTR(-EPROBE_DEFER);
		goto out;
	}

    // 根据 chip 和 gpiospec 描述的信息返回对应引脚的 gpio_desc 结构体
	desc = of_xlate_and_get_gpiod_flags(chip, &gpiospec, flags);
	if (IS_ERR(desc))
		goto out;

	pr_debug("%s: parsed '%s' property of node '%pOF[%d]' - status (%d)\n",
		 __func__, propname, np, index,
		 PTR_ERR_OR_ZERO(desc));

out:
	of_node_put(gpiospec.np);

	return desc;
}

(1)函数 of_parse_phandle_with_args 参考

of_parse_phandle_with_args 函数_Vane Zhang的博客-CSDN博客

(2)函数 of_find_gpiochip_by_xlate 参考

of_find_gpiochip_by_xlate 函数_Vane Zhang的博客-CSDN博客

(3)函数 of_xlate_and_get_gpiod_flags 参考

of_xlate_and_get_gpiod_flags 函数_Vane Zhang的博客-CSDN博客

5  总结

static inline
struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev,
						   const char *con_id,
						   struct fwnode_handle *child,
						   enum gpiod_flags flags,
						   const char *label)

 函数 devm_fwnode_get_gpiod_from_child 根据传入的 device 结构体变量,con_id 字符串以及 fwnode_handle 结构体变量,返回对应引脚的描述符 gpio_desc 结构体变量。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vane Zhang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值