news 2026/6/9 19:02:58

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/6/10 7:59:05

SQL的基础

SQL的基础语句select语句使用形式&#xff1a;SELECT column1, column2, ... FROM table_name WHERE condition;select * from student where sex’男’;其中&#xff0c;SELECT关键字用于指定要查询的列&#xff0c;可以使用*代表所有列&#xff1b;FROM关键字用于指定要查询的…

作者头像 李华
网站建设 2026/6/10 7:51:22

MATLAB基于RSM和MOGWO的440C不锈钢外圆磨削参数优化

一、 问题定义与优化目标 工件材料&#xff1a; 440C不锈钢 特性&#xff1a; 高碳马氏体不锈钢&#xff0c;高硬度&#xff08;HRC 58-60&#xff09;&#xff0c;高耐磨性&#xff0c;但导热性差&#xff0c;磨削时易产生&#xff1a; 磨削烧伤&#xff08;热损伤&#xff09…

作者头像 李华
网站建设 2026/6/10 7:51:21

SQLite Glob 子句详解

SQLite Glob 子句详解 概述 SQLite 是一款轻量级的数据库管理系统,以其简洁的设计和强大的功能深受用户喜爱。在 SQLite 中,Glob 子句是一个非常有用的特性,它允许用户使用通配符进行模糊查询。本文将详细介绍 SQLite 的 Glob 子句,包括其工作原理、语法以及应用场景。 …

作者头像 李华
网站建设 2026/6/10 7:50:59

ionic 单选框操作指南

ionic 单选框操作指南 引言 在移动应用开发中,单选框(Radio Button)是一种常见的用户界面元素,用于让用户从一组选项中选择一个选项。Ionic框架作为一款流行的移动端UI框架,提供了丰富的组件来帮助开发者构建高性能的移动应用。本文将详细介绍如何在Ionic中使用单选框,…

作者头像 李华
网站建设 2026/6/10 8:54:50

08_C 语言进阶之面向对象编程:模块化及抽象思维 —— 用过程式语言构建面向对象的世界

C 语言进阶之面向对象编程:模块化及抽象思维 —— 用过程式语言构建面向对象的世界 一、C 语言真的不能搞面向对象吗? “C 语言是过程式语言,只能写面条代码?” “项目变大后,C 代码耦合度高、维护难,难道只能转 C++?” “想实现代码复用、数据封装,C 语言有没有优…

作者头像 李华
网站建设 2026/6/10 8:58:59

我在学c语言分支和循环的见解和踩过的坑

在这篇blog中我将边讲解边说说我遇到的困难&#xff0c;我将分为12个点来论述&#xff1b;1. if语句 2. 关系操作符 3. 条件操作符 4. 逻辑操作符&#xff1a;&& , || , &#xff01; 5. switch语句 6. while循环 7. for循环 8. do-while循环 9. break和continue语句 1…

作者头像 李华