分析:在设备树中描述GPIO引脚,在内核代码中的解析和识别

疑问

根据使用某厂商soc的dt-binding文档的说明,写好了设备树去使用gpio子系统,形如gpios = <&pio 0 7 0>,然后在驱动代码中去调用类似devm_fwnode_get_index_gpiod_from_child这样的函数去获取gpio信息(struct gpio_desc),问,内核中的GPIO子系统是如何识别并解析你在设备树中的gpio描述属性gpios = <&pio 0 7 0>

GPIO子系统用户函数原型

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)

举例

设备树
ts_led {
	gpios = <&pio 0 7 0>;
};

用户驱动代码中的调用示例

在这里插入图片描述

流程分析

  • devm_fwnode_get_index_gpiod_from_child [drivers/gpio/gpiolib-devrs.c]
    • fwnode_get_named_gpiod(后缀gpio和gpios) [drivers/gpio/gpiolib.c]
      • gpiod_get_from_of_node() [drivers/gpio/gpiolib-of.c]
        • of_get_named_gpiod_flags
          • of_parse_phandle_with_args_map(“gpio”) [drivers/of/base.c] // 获取gpios属性列表中第0个引用(phandle)中的"#gpio-cells和gpio-map"等属性信息以及对引用的传参信息info(对应设备树中的 0 7 0)
          • of_find_gpiochip_by_xlate(上述获得的属性信息) // 通过上述信息获取gpio控制器
            • gpiochip_find [drivers/gpio/gpiolib.c] // 遍历GPIO设备(gpio_devices)获取gpio控制器(gpio_chip)
          • of_xlate_and_get_gpiod_flags // 从上面gpio控制器中结合info获取gpio_desc数据
            • chip->of_xlate(chip, gpiospec, flags); // 调用gpio控制器的of_xlate设备树翻译函数,这个函数是BSP开发者在pinctrl驱动代码中注册gpio控制器时指定的!!(关键)
          • of_gpio_flags_quirks // ??可能是从上面gpio控制器里面取flag(设备树中的)
          • 返回gpio_desc数据

of_xlate实现分析

厂商BSP开发者在pinctrl驱动代码中注册gpio控制器示例

以[drivers/pinctrl/sunxi/pinctrl-sunxi.c]示例

// 给pinctrl分配gpio_chip
	pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL);
	if (!pctl->chip)
		return -ENOMEM;devm_fwnode_get_gpiod_from_child
	// 执行gpio_chip的相关处理函数
	last_pin = pctl->desc->pins[pctl->desc->npins - 1].pin.number;
	pctl->chip->owner = THIS_MODULE;
	pctl->chip->request = gpiochip_generic_request; // 请求gpio资源
	pctl->chip->free = gpiochip_generic_free; // 释放资源
	pctl->chip->set_config = gpiochip_generic_config; // 设置gpio引脚的配置
	pctl->chip->direction_input = sunxi_pinctrl_gpio_direction_input; // 输入设置
	pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output; // 输出设置
	pctl->chip->get = sunxi_pinctrl_gpio_get; // 获取gpio值
	pctl->chip->set = sunxi_pinctrl_gpio_set; // 设置gpio值
	pctl->chip->of_xlate = sunxi_pinctrl_gpio_of_xlate; // ?
	pctl->chip->to_irq = sunxi_pinctrl_gpio_to_irq; // 将GPIO引脚转换为中断号
	pctl->chip->of_gpio_n_cells = 3; // 设备树中gpio-cells
	pctl->chip->can_sleep = false; // 标记gpio操作是否可能睡眠
	pctl->chip->ngpio = round_up(last_pin, PINS_PER_BANK) -
			    pctl->desc->pin_base; // 引脚数量
	pctl->chip->label = dev_name(&pdev->dev); // 控制器名字
	pctl->chip->parent = &pdev->dev; // 父控制器
	pctl->chip->base = pctl->desc->pin_base;
	// 注册GPIO控制器
	ret = gpiochip_add_data(pctl->chip, pctl);
	if (ret)
		return ret;
关键在于sunxi_pinctrl_gpio_of_xlate的实现
static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc,
				const struct of_phandle_args *gpiospec,
				u32 *flags)
{
	int pin, base;
	// 每个控制器管理多少个pin脚 * gpio控制器的索引 = pin脚编号的base
	// 这里得出<&pin 0 7 0> 中,第一个参数0表示gpio控制器的索引,对应到实际soc中,一般就是PAx这种
	base = PINS_PER_BANK * gpiospec->args[0];
	// pin脚编号的base + pin脚在其控制器chip中的编号 = pin实际编号
	// 这里得出<&pin 0 7 0> 中,第二个参数7表示pin在其所在z控制器的编号,对应到实际soc中,一般就是PA7、PB7这种
	pin = base + gpiospec->args[1];

	if (pin > gc->ngpio)
		return -EINVAL;

	if (flags)
		*flags = gpiospec->args[2];

	return pin;
}
  • 这个函数由BSP开发者实现,根据其公司的SOC产品具体方案有所区别。
  • 总的来说就是根据传入的gpiospec(在设备树中引用的gpio控制器节点必要的#gpio-cells、gpio-map等信息, 如gpios = <&pio 0 7 0>中的&pio,还有引用列表传参, 如gpios = <&pio 0 7 0>中的0 7 0传参信息),得到pin脚在gpio控制器(gc)中的实际索引(hardware number)。
  • 这个函数的目的应该是获取引脚在给定的gpio控制器中的hardware number(索引值)。
  • of_xlate_and_get_gpiod_flags函数,通过调用此函数得到的实际索引,再调用gpiochip_get_desc最终得到pin脚的gpio_desc信息。
  • 总结:这个函数提供了BSP开发者要求的设备树中使用GPIO的格式的解析方法!
  • 24
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值