news 2026/4/16 23:41:38

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/4/16 15:45:39

抖音无水印视频下载完整教程:3分钟学会专业级视频保存技巧

想要完美保存抖音上的精彩视频却总是被水印困扰&#xff1f;douyin_downloader抖音无水印下载器正是你需要的解决方案。这款开源工具支持抖音视频无水印下载和批量保存&#xff0c;让你轻松收藏喜爱的短视频内容。无论是个人收藏还是内容创作&#xff0c;都能获得原画质的高清视…

作者头像 李华
网站建设 2026/4/16 14:36:28

线性代数(六)列空间和零空间

前篇文章给出了向量子空间的的定义&#xff0c;本篇来进一步讨论一些形式的向量子空间。取两个子空间P和L&#xff0c;P构成平面&#xff0c;L构成直线&#xff0c;讨论两种情况&#xff1a;1.P和L的并集&#xff0c;能构成子空间吗&#xff1f;显然不能&#xff0c;因为P空间内…

作者头像 李华
网站建设 2026/4/16 16:09:49

云顶之弈智能挂机助手:解放双手的自动化游戏解决方案

云顶之弈智能挂机助手&#xff1a;解放双手的自动化游戏解决方案 【免费下载链接】LOL-Yun-Ding-Zhi-Yi 英雄联盟 云顶之弈 全自动挂机刷经验程序 外挂 脚本 ,下载慢可以到https://gitee.com/stringify/LOL-Yun-Ding-Zhi-Yi 项目地址: https://gitcode.com/gh_mirrors/lo/LOL…

作者头像 李华
网站建设 2026/4/16 14:36:33

Day 39 信贷数据集神经网络训练

文章目录Day 39 信贷数据集神经网络训练一、数据预处理二、构建 DataLoader 与神经网络三、可视化Dropout 模型表现四、小结Day 39 信贷数据集神经网络训练 import pandas as pd import numpy as np import torch import torch.nn as nn import torch.optim as optim import…

作者头像 李华
网站建设 2026/4/16 14:36:25

桌面开发,在线%对联管理%系统,基于vs2022,c#,winform,sql server数据库

经验心得两个crud单子&#xff0c;没啥可聊的&#xff0c;按照不同模块实现对应的业务逻辑就行哦。毕竟只和数据库打交道&#xff0c;桌面和web开发不一样&#xff0c;web后端除了基础crud&#xff0c;咱们还得重点考虑并发问题等其他安全问题&#xff0c;比如多个请求同时执行…

作者头像 李华