news 2026/5/14 7:25:01

linux gpio获取

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
linux gpio获取

最近在工作中遇到了gpio解析失败的问题,跟踪发现设备树配置的字符串不匹配,在这里再次学习并记录下。

  • of_get_named_gpio
    以前在工作中更多使用的是of_get_named_gpio这个标准函数,用以直接获取gpio。只要指定其具体的属性名,一般就能正常获取其gpio号,而本次使用另外一个接口获取的是gpio描述符结构体。就碰到问题了
  • devm_gpiod_get
    源码物位置:kernel/driver/gpio/gpiolib-devres.c
/** * devm_gpiod_get - Resource-managed gpiod_get() * @dev: GPIO consumer * @con_id: function within the GPIO consumer * @flags: optional GPIO initialization flags * * Managed gpiod_get(). GPIO descriptors returned from this function are * automatically disposed on driver detach. See gpiod_get() for detailed * information about behavior and return values. */structgpio_desc*__must_checkdevm_gpiod_get(structdevice*dev,constchar*con_id,enumgpiod_flagsflags){returndevm_gpiod_get_index(dev,con_id,0,flags);}

此接口是linux内核标准接口,下面来解析下其具体的参数函义:

  • dev 指定此gpio的使用者,一般需要拿到此dev的of_node属性节点。然后从所有的属性中查找指定的字符串。所以此参数不能为空
  • con_id 找定查找的gpio属性名,因为可能存在多个gpio属性配置,使用多个属性名。此参数可为空,如果为空则查找系统指定的字符串
  • flags gpio初始化状态,可以为以下值的任意一个
enumgpiod_flags{GPIOD_ASIS=0,GPIOD_IN=GPIOD_FLAGS_BIT_DIR_SET,GPIOD_OUT_LOW=GPIOD_FLAGS_BIT_DIR_SET|GPIOD_FLAGS_BIT_DIR_OUT,GPIOD_OUT_HIGH=GPIOD_FLAGS_BIT_DIR_SET|GPIOD_FLAGS_BIT_DIR_OUT|GPIOD_FLAGS_BIT_DIR_VAL,GPIOD_OUT_LOW_OPEN_DRAIN=GPIOD_OUT_LOW|GPIOD_FLAGS_BIT_OPEN_DRAIN,GPIOD_OUT_HIGH_OPEN_DRAIN=GPIOD_OUT_HIGH|GPIOD_FLAGS_BIT_OPEN_DRAIN,};
  • 大体函义如下:
    • GPIOD_ASIS 不需要对gpio作任何修改
    • GPIOD_IN gpio为输入
    • GPIOD_OUT_LOW gpio为输出,并拉低
    • GPIOD_OUT_HIGH gpio为输出,并拉高
    • GPIOD_OUT_LOW_OPEN_DRAIN gpio漏极开路输出,并拉低
    • GPIOD_OUT_HIGH_OPEN_DRAIN gpio漏极开路输出,并拉高
  • 此函数的调用流程如下:

devm_gpiod_get_index

  • Non-Exclusive :此模式允许多个进程或任务同时访问同一个GPIO引脚,需要对资源访问加锁

of_find_gpio

static__maybe_unusedconstchar*constgpio_suffixes[]={"gpios","gpio"};
structgpio_desc*of_find_gpio(structdevice_node*np,constchar*con_id,unsignedintidx,unsignedlong*flags){charprop_name[32];/* 32 is max size of property name */enumof_gpio_flagsof_flags;constof_find_gpio_quirk*q;structgpio_desc*desc;unsignedinti;/* Try GPIO property "foo-gpios" and "foo-gpio" */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]);elsesnprintf(prop_name,sizeof(prop_name),"%s",gpio_suffixes[i]);desc=of_get_named_gpiod_flags(np,prop_name,idx,&of_flags);if(!gpiod_not_found(desc))break;}/* Properly named GPIO was not found, try workarounds */for(q=of_find_gpio_quirks;gpiod_not_found(desc)&&*q;q++)desc=(*q)(np,con_id,idx,&of_flags);if(IS_ERR(desc))returndesc;*flags=of_convert_gpio_flags(of_flags);returndesc;}
  • 如果有指定属性名,那么会进行字符串拼接.拼接的规则是xxx-gpios|xxx-gpio,也就是说实际查找的字符串是添加了后辍的。会轮询查找对应的字符串,比如在驱动中使用of_find_gpio(…,“power”,…),那么在DTS中就应该配置power-gpios或者power-gpio
  • 如果指定属性名为空,那么会直接查找gpios或者gpio,所以如果你不想写属性名,就直接在DTS中配置其它的一个属性就可以了
    工作中碰到的查找失败起因就是在此了。

of_get_named_gpiod_flags

  • of_parse_phandle_with_args_map是个系统函数,这里不用太关注。只需要关心其输出的结果gpiospec
    • np 其指向的gpio控制器节点
    • args_count #gpio-size配置的数据
    • args 具体的gpio配置数据
structof_phandle_args{structdevice_node*np;intargs_count;uint32_targs[MAX_PHANDLE_ARGS];};

of_find_gpiochip_by_xlate

staticstructgpio_chip*of_find_gpiochip_by_xlate(structof_phandle_args*gpiospec){returngpiochip_find(gpiospec,of_gpiochip_match_node_and_xlate);}structgpio_chip*gpiochip_find(void*data,int(*match)(structgpio_chip*gc,void*data)){structgpio_device*gdev;structgpio_chip*gc=NULL;unsignedlongflags;spin_lock_irqsave(&gpio_lock,flags);list_for_each_entry(gdev,&gpio_devices,list)if(gdev->chip&&match(gdev->chip,data)){gc=gdev->chip;break;}spin_unlock_irqrestore(&gpio_lock,flags);returngc;}

上述代码很明显,轮询所有的gpio控制器。从而找到匹配的控制器,匹配的规则也很简单就两点:

  • 设备树配置的控制器节点与其中一个控制器相等
  • 存在of_xlate回调函数且其返回值>=0
    匹配实现如下:
staticintof_gpiochip_match_node_and_xlate(structgpio_chip*chip,void*data){structof_phandle_args*gpiospec=data;returndevice_match_of_node(&chip->gpiodev->dev,gpiospec->np)&&chip->of_xlate&&chip->of_xlate(chip,gpiospec,NULL)>=0;}

of_xlate_and_get_gpiod_flags

staticstructgpio_desc*of_xlate_and_get_gpiod_flags(structgpio_chip*chip,structof_phandle_args*gpiospec,enumof_gpio_flags*flags){intret;if(chip->of_gpio_n_cells!=gpiospec->args_count)returnERR_PTR(-EINVAL);ret=chip->of_xlate(chip,gpiospec,flags);if(ret<0)returnERR_PTR(ret);returngpiochip_get_desc(chip,ret);}

这里的函数实现完全依赖控制器,代码逻辑比较简单,这里要搞懂这个实现。需要找一个gpio控制器来研究下,这里以gpio-sprd.c为例

gpio-sprd控制器

staticintsprd_gpio_probe(structplatform_device*pdev){structgpio_irq_chip*irq;structsprd_gpio*sprd_gpio;sprd_gpio=devm_kzalloc(&pdev->dev,sizeof(*sprd_gpio),GFP_KERNEL);if(!sprd_gpio)return-ENOMEM;sprd_gpio->irq=platform_get_irq(pdev,0);if(sprd_gpio->irq<0)returnsprd_gpio->irq;sprd_gpio->base=devm_platform_ioremap_resource(pdev,0);if(IS_ERR(sprd_gpio->base))returnPTR_ERR(sprd_gpio->base);spin_lock_init(&sprd_gpio->lock);sprd_gpio->chip.label=dev_name(&pdev->dev);sprd_gpio->chip.ngpio=SPRD_GPIO_NR;sprd_gpio->chip.base=-1;sprd_gpio->chip.parent=&pdev->dev;sprd_gpio->chip.request=sprd_gpio_request;sprd_gpio->chip.free=sprd_gpio_free;sprd_gpio->chip.get=sprd_gpio_get;sprd_gpio->chip.set=sprd_gpio_set;sprd_gpio->chip.direction_input=sprd_gpio_direction_input;sprd_gpio->chip.direction_output=sprd_gpio_direction_output;irq=&sprd_gpio->chip.irq;gpio_irq_chip_set_chip(irq,&sprd_gpio_irqchip);irq->handler=handle_bad_irq;irq->default_type=IRQ_TYPE_NONE;irq->parent_handler=sprd_gpio_irq_handler;irq->parent_handler_data=sprd_gpio;irq->num_parents=1;irq->parents=&sprd_gpio->irq;returndevm_gpiochip_add_data(&pdev->dev,&sprd_gpio->chip,sprd_gpio);}

这里此控制器的定义,从上可以看出此控制器并没有定义。如果控制器没有定义此回调函数,则会使用系统默认提供的回调函数of_gpio_simple_xlate

此函数是公用的回调函数,如果控制器定义了自己的xlate函数则使用控制器自身的,如果没有就会使用此函数。到这里gpio的解析流程就基本走完了,对gpio子系统认识进一步加深。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/4 6:38:32

数据结构学习篇(4)---算法的时间复杂度

由于现在计算机的储存在硬件上能得到很好的解决&#xff0c;所以时间复杂度较空间复杂度更受关注。1.1 时间复杂度的概念时间复杂度的定义&#xff1a;在计算机科学中&#xff0c;算法的时间复杂度是一个函数&#xff0c;它定量描述了该算法的运行时间。一 个算法执行所耗费的时…

作者头像 李华
网站建设 2026/5/11 15:41:25

桌面开发,在线%RIP,路由表管理%系统,基于vs2022,c#,winform,txt,无数据库

经验心得帮客户完善一下RIP路由表拓扑结构图展示。代码很多地方不严谨帮客户修改一下就行。剩下就是搞懂路由表展示原理就行。 路由展示功能介绍 做这个路由展示功能时&#xff0c;最直观的感受就是重复的活干太多了。比如A到H这8个路由按钮&#xff0c;点每个按钮的逻辑几乎一…

作者头像 李华
网站建设 2026/5/13 6:25:02

Day 39 MLP神经网络的训练

浙大疏锦行 神经网络是一种模拟人脑神经元连接结构的分层模型&#xff0c;核心通过“输入层→隐藏层→输出层”的架构实现端到端学习&#xff0c;无需手动设计特征&#xff0c;能自动提取数据中的高阶非线性关系&#xff08;如心脏病风险与年龄、血压的复杂关联&#xff09;。…

作者头像 李华
网站建设 2026/5/13 23:41:13

浏览器原理

浏览器原理 一、 宏观视角&#xff1a;Chrome 多进程架构 现在的浏览器更像是一个分布式操作系统&#xff0c;而非简单的应用程序。 1. 四大核心进程 Browser Process (主进程)&#xff1a; 职责&#xff1a;负责 UI&#xff08;地址栏、书签&#xff09;、协调子进程、管理存储…

作者头像 李华
网站建设 2026/5/7 1:12:47

XXL-TOOL v2.4.0 发布 | 布隆过滤器、Excel流式读写、高性能BeanCopy

Release Notes 1、【新增】BloomFilter&#xff08;布隆过滤器&#xff09;&#xff1a;一种基于多哈希函数和位数组的概率型数据结构&#xff0c;具有高效空间利用与快速查询特性&#xff1b;2、【新增】Trie&#xff08;前缀数&#xff09;&#xff1a;一种哈希树的变种&…

作者头像 李华
网站建设 2026/5/12 0:07:16

管理软件包

一.rpm管理软件包1.安装软件-i安装指定一个或多个软件包-v显示安装过程-h以#号显示安装进度2.查询软件-q查询软件包信息-a查询已经安装的软件包-c显示软件包的配置文件列表-d显示软件包的文本文件列表-p查询软件包文件&#xff0c;通常和其他选项组合使用-g查询所属组的软件包-…

作者头像 李华