GPIO 应该是每个嵌入式设备都避免不了的。最近在做项目的时候,也遇到这方面的问题,所以简单总结一下

现在内核里面多了gpiod的来控制gpio口,相对于原来的形式,使用gpiod的好处是我们申请后不进行free也没有什么问题。但是你要是使用原来的方式后,一定要记得释放。不释放的话可能会有问题。

#旧的GPIO使用实例

DTS文件

det-gpios = <&gpio3 RK_PA6 IRQ_TYPE_EDGE_BOTH>;

驱动文件调用

    gc5025->det_pin = of_get_named_gpio_flags(node, "det-gpios", 0, &det_flags);camera_det_irq = gpio_to_irq(gc5025->det_pin);gc5025->det_value = gpio_get_value(gc5025->det_pin);/*判断注册终端*/if(camera_det_irq){if (gpio_request(gc5025->det_pin, "camera-irq-gpio")) {printk("gpio %d request failed!\n", gc5025->det_pin);gpio_free(gc5025->det_pin);return IRQ_NONE;}ret = request_irq(camera_det_irq, camera_det_irq_handler, IRQ_TYPE_EDGE_BOTH, "det-gpio", NULL);if (ret != 0) {free_irq(camera_det_irq, NULL);dev_err(dev, "Failed to request IRQ: %d\n", ret);return ret;}}

# 新的GPIOD文档

Linux 内核文档

https://www.kernel.org/doc/Documentation/gpio/consumer.txt

#头文件

我们需要包含头文件

#include <linux/gpio/consumer.h>

看头文件里面包含的函数列表

desc_to_gpio
devm_get_gpiod_from_chi
devm_gpiod_get
devm_gpiod_get_array
devm_gpiod_get_array_op
devm_gpiod_get_index
devm_gpiod_get_index_op
devm_gpiod_get_optional
devm_gpiod_put
devm_gpiod_put_array
fwnode_get_named_gpiod
gpio_to_desc
gpiod_cansleep
gpiod_count
gpiod_direction_input
gpiod_direction_output
gpiod_direction_output_
gpiod_export
gpiod_export_link
gpiod_get
gpiod_get_array
gpiod_get_array_optiona
gpiod_get_direction
gpiod_get_index
gpiod_get_index_optiona
gpiod_get_optional
gpiod_get_raw_value
gpiod_get_raw_value_can
gpiod_get_value
gpiod_get_value_canslee
gpiod_is_active_low
gpiod_put
gpiod_put_array
gpiod_set_array_value
gpiod_set_array_value_c
gpiod_set_debounce
gpiod_set_raw_array_val
gpiod_set_raw_array_val
gpiod_set_raw_value
gpiod_set_raw_value_can
gpiod_set_value
gpiod_set_value_canslee
gpiod_to_irq
gpiod_unexport

#获取gpio描述符和释放

使用一下两个函数获取GPIO设备,多个设备时需要附带index参数。函数返回一个GPIO描述符,或一个错误编码,可以使用IS_ERR()进行检查:

struct gpio_desc *gpiod_get(struct device *dev, const char *con_id,enum gpiod_flags flags)struct gpio_desc *gpiod_get_index(struct device *dev,const char *con_id, unsigned int idx,enum gpiod_flags flags)

或者也可以使用如下两个函数获取可用设备:

struct gpio_desc *gpiod_get_optional(struct device *dev,const char *con_id,enum gpiod_flags flags)struct gpio_desc *gpiod_get_index_optional(struct device *dev,const char *con_id,unsigned int index,enum gpiod_flags flags)

使用如下函数同时获取多个设备:

struct gpio_descs *gpiod_get_array(struct device *dev,const char *con_id,enum gpiod_flags flags)

该函数返回一个GPIO描述结构体:

struct gpio_descs {unsigned int ndescs;struct gpio_desc *desc[];
}

一个GPIO描述符可以使用如下函数释放:

void gpiod_put(struct gpio_desc *desc)
void gpiod_put_array(struct gpio_descs *descs)

需要注意GPIO描述符被释放后不可再使用,而且不允许使用第一个函数来释放通过序列获取得到GPIO描述符。

#举个例子

#dts文件

gc5025: gc5025@37 {status = "okay";compatible = "galaxycore,gc5025";reg = <0x37>;clock-frequency = <400000>;pinctrl-names = "default";pinctrl-0 = <&cif_clkout_m0>;clocks = <&cru SCLK_CIF_OUT>;clock-names = "xvclk";avdd-supply = <&vcc2v8_dvp>;dovdd-supply = <&vcc1v8_dvp>;dvdd-supply = <&vdd1v2_dvp>;reset-gpios = <&gpio3 RK_PA3 GPIO_ACTIVE_LOW>;pwdn-gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>;det-gpios = <&gpio3 RK_PA6 IRQ_TYPE_EDGE_BOTH>;rockchip,camera-module-index = <0>;rockchip,camera-module-facing = "front";rockchip,camera-module-name = "CMK-CW4191-FG1";rockchip,camera-module-lens-name = "CK5502";port {ucam_out: endpoint {remote-endpoint = <&mipi_in_ucam>;data-lanes = <1 2>;};};};

驱动文件调用:

    gc5025->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);if (IS_ERR(gc5025->reset_gpio))dev_warn(dev, "Failed to get reset-gpios\n");gc5025->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW);if (IS_ERR(gc5025->pwdn_gpio))dev_warn(dev, "Failed to get pwdn-gpios\n");/*新的GPIO子系统方式,这种方式不需要手动释放资源*/gc5025->det_gpio = devm_gpiod_get(dev, "det", GPIOD_OUT_LOW);if (IS_ERR(gc5025->det_gpio))

#GPIO使用

#设置GPIO口方向

int gpiod_direction_input(struct gpio_desc *desc)
int gpiod_direction_output(struct gpio_desc *desc, int value)

#检查GPIO口是方向

int gpiod_get_direction(const struct gpio_desc *desc)

函数返回GPIOF_DIR_IN或者GPIOF_DIR_OUT

#读取GPIO口电平

访问分为两种,一种是通过储存器读写实现的,这种操作属于原子操作,不需要等待,所以可以在中断处理程序中使用:

int gpiod_get_value(const struct gpio_desc *desc);
void gpiod_set_value(struct gpio_desc *desc, int value);

还有一种访问必须通过消息总线比如I2C或者SPI,这种访问需要在总线访问队列中等待,所以可能进入睡眠,此类访问不能出现在IRQ handler。可以使用如下函数分辨这些设备:

int gpiod_cansleep(const struct gpio_desc *desc)

使用如下函数读写:

int gpiod_get_value_cansleep(const struct gpio_desc *desc)
void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)

#active-low和raw-value

active-low & raw value有些设备采用低电平有效的方式输出逻辑信号。此时低电平输出1,高电平输出0。此时可以通过访问raw_value的方式来访问实际电路上的值,与逻辑处理无关:假设我们在DTS里面这样设置

reset-gpios = <&gpio3 RK_PA3 GPIO_ACTIVE_LOW>;

然后我们这样调用

gpiod_set_value_cansleep(gc5025->reset_gpio, 1);

因为DTS里面的active 状态是 GPIO_ACTIVE_LOW,所以这个代码输出的是 低电平

gpiod_set_value_cansleep(gc5025->reset_gpio, 0);

输出的是高电平

这几个函数如下:

int gpiod_get_raw_value(const struct gpio_desc *desc)
void gpiod_set_raw_value(struct gpio_desc *desc, int value)
int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value)
int gpiod_direction_output_raw(struct gpio_desc *desc, int value)

raw-value 的意思就是不在乎DTS里面的ACTIVE,我set 高电平,就是高电平。逻辑关系汇总如下:

Function (example) active-low property physical line
gpiod_set_raw_value(desc, 0); don’t care low
gpiod_set_raw_value(desc, 1); don’t care high
gpiod_set_value(desc, 0); default (active-high) low
gpiod_set_value(desc, 1); default (active-high) high
gpiod_set_value(desc, 0); active-low high
gpiod_set_value(desc, 1); active-low low

可以使用如下函数判断一个设备是否是低电平有效的设备。

int gpiod_is_active_low(const struct gpio_desc *desc)

#设置多个输出

这个没使用过 使用如下函数设置一组设备的输出值

void gpiod_set_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)

#兼容旧版本

旧的GPIO系统使用基于标号的结构而不是基于描述符。可以使用如下两个函数进行相互转换:

int desc_to_gpio(const struct gpio_desc *desc)
struct gpio_desc *gpio_to_desc(unsigned gpio)

注意不能使用一套API的方法释放另一套API获取的设备

#和中断IRQ相关

使用如下函数获取一个GPIO设备对应的IRQ中断号

int gpiod_to_irq(const struct gpio_desc *desc)

返回值时一个IRQ number,或者一个负数的错误代码。得到的中断号可以传递给函数request_irq(),free_irq().

#举例子

    /*新的GPIO子系统方式,这种方式不需要手动释放资源*/gc5025->det_gpio = devm_gpiod_get(dev, "det", GPIOD_OUT_LOW);if (IS_ERR(gc5025->det_gpio))dev_warn(dev, "Failed to get det-gpios\n");camera_det_irq = gpiod_to_irq(gc5025->det_gpio);/*新gpio子系统转成旧gpio子系统*/gc5025->det_pin = desc_to_gpio(gc5025->det_gpio);/*读取上电gpio电平*/gc5025->det_value = gpio_get_value(gc5025->det_pin);/*判断注册终端*/if(camera_det_irq){ret = request_irq(camera_det_irq, camera_det_irq_handler, IRQ_TYPE_EDGE_BOTH, "det-gpio", NULL);if (ret != 0) {free_irq(camera_det_irq, NULL);dev_err(dev, "Failed to request IRQ: %d\n", ret);return ret;}}

#调试

移植驱动阶段或者调试阶段的工程中,难免想知道当前gpio的电平状态。当然很easy。万用表戳上去不就行了。是啊!硬件工程师的思维。作为软件工程师自然是要软件的方法。下面介绍两个api接口。自己摸索使用吧。点到为止。

static inline int gpio_export(unsigned gpio, bool direction_may_change);
static inline int gpio_export_link(struct device *dev, const char *name, unsigned gpio);

在你的driver中调用以上api后,编译下载。去/sys/class/gpio目录看看有什么发现。

回复「 篮球的大肚子」进入技术群聊

回复「1024」获取1000G学习资料

Linux下的gpio,gpiod相关推荐

  1. linux下使用gpio控制代码,zynq linux 下控制gpio的c代码

    在linux下控制gpio可以先用简单的命令行去控制下看看, 1. devmem 0x41200000 32 0x00000005 2.devicetree的结构如下 dip0: gpio_dip_s ...

  2. Linux下使用GPIO模拟I2C IIC驱动(PCF8563)

    此代码实现LINUX下,创建/dev/algortc设备,但是没有实现rtc标准的读写接口,仅仅实现了IIC时序模拟,编译出.ko文件之后,使用insmod命令挂载,代码里面的线程就会循环读写PCF8 ...

  3. 在ARM Linux下使用GPIO模拟SPI时序详解

    Author:杨正  Data:2016.1.1  Mail:yz2012ww@gmail.com 一.       概述 SPI是英文SerialPeripheral Interface的缩写,顾名 ...

  4. linux网卡点灯命令,LINUX下SHELL GPIO点灯

    我使用的lichee Pi 芯片是全志的v3s.摸索一下linux的点灯. 我的代码 #!/bin/sh echo "led run!" echo 36 > /sys/cla ...

  5. linux下的gpio转串口驱动,X-026-KERNEL-Linux gpio driver的移植之gpio range

    X-026-KERNEL-Linux gpio driver的移植之gpio range 作者:wowo 发布于:2017-9-27 22:27 分类:X Project 1. 前言 我们在[1][2 ...

  6. Linux下创建GPIO(/sys/class/gpio)

       通过sysfs方式控制GPIO,先访问/sys/class/gpio目录,向export文件写入GPIO编号,使得该GPIO的操作接口从内核空间暴露到用户空间,GPIO的操作接口包括direct ...

  7. linux下IO口模拟I2C的一些总结

    2019独角兽企业重金招聘Python工程师标准>>> 以前一直在用I2C接口,因为总是有线程的例子就一直没有去深入的了解,今天分析了一下在linux下通用GPIO模拟I2C的程序. ...

  8. 61-20210407华为海思Hi3516DV300的linux系统下控制GPIO口(标准linux模式点亮LED灯)

    61-20210407华为海思Hi3516DV300的linux系统下控制GPIO口(标准linux模式点亮LED灯) 2021/4/7 15:13 https://xueqiu.com/797071 ...

  9. Linux下LED设备驱动开发(LED灯实现闪烁)

    文章目录 一.配置连接说明 二.更新设备树 (1)将led灯引脚添加到pinctrl子系统 (2)设备树中添加LDE灯的设备树节点 (3)编译更新设备树 三.驱动开发与测试 (1)编写设备驱动代码 ( ...

最新文章

  1. 批量导出AD组内的成员
  2. c# point偏移_.NET 在图片上写文字出现偏移的解决
  3. 【牛客 - 331J】炫酷数学(打表猜结论,按位枚举证明)
  4. 八年级信息技术认识计算机网络,初二信息技术课名称:认识计算机网络.doc
  5. python处理文本文件实现生成指定格式文件的方法
  6. 如何用TC群控系统同时控制上百台手机
  7. 【向生活低头】如何在Gold Wave软件中为声音添加背景音乐
  8. Excel取整函数汇总
  9. win10系统连接不上服务器,win10系统电驴连接不上服务器的解决方法
  10. 微信小程序Token登录验证
  11. ng-alain之G2图表
  12. AutoCAD二次开发——CAD数据库层次关系(笔记22.11.29)
  13. c语言检测网络连接,C++ 网络连通性检测的实现方法
  14. PPT制作(文字排版)
  15. Android Animator(Android动画)
  16. C# GDAL 数字图像处理Part10 自动配准/半自动配准
  17. OpenAI击败Dota 2世界冠军后记:如何训练你的AI
  18. Android实现电量控制降低耗电
  19. 企业微信营销软件「群积分」功能,助力商家搭建高效私域营销体系
  20. delmia机器人模型调入

热门文章

  1. 2013年11月份我国网络不良与垃圾短信息分析报告
  2. XP访问Linux共享错误提示
  3. 如何在asp.net中实现listbox item值上下移动?(转)
  4. [Diary]6.10
  5. 场景应用题目常见面试真题详解
  6. Centos7安装Docker教程
  7. pyecharts对于经纬度_一文带你掌握Pyecharts地理数据可视化的方法
  8. axureux中后台管理信息系统通用原型方案 v2_前端公共图表数据大盘方案
  9. 哈希表思路图解和代码实现
  10. 【R】语言第四课----读取文件