Linux GPIO驱动部分函数

一、设备树—API

①of_find_compatible_node 函数

②of_get_named_gpio 函数

③irq_of_parse_and_map 函数

二、GPIO—API

①gpio_request 函数

②gpio_free 函数

③gpio_direction_input 函数

④gpio_direction_output 函数

⑤gpio_is_valid 函数

⑥gpio_get_value 函数

⑦gpio_set_value 函数

三、中断—API

①request_irq 函数

②free_irq 函数

③enable_irq()与disable_irq()函数

四、Pinctrl—API 

①devm_pinctrl_get 函数

②devm_pinctrl_put 函数

③pinctrl_lookup_state 函数

④pinctrl_select_state函数


inux驱动开发,首先从使用驱动的API开始,先会使用API,然后才能更深入的分析,本篇所列的都是驱动开发中非常常用的API,之所以从设备树API开始,是本人觉得驱动开发的源头在设备树,并且大部分驱动都跟设备树相关。

一、设备树—API

①of_find_compatible_node 函数

of_find_compatible_node 函数根据 device_type 和 compatible 这两个属性查找指定的节点, 函数原型如下:

struct device_node *of_find_compatible_node(struct device_node,*from, const char *type,

 const char *compatible)

函数参数和返回值含义如下:

from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。

type:要查找的节点对应的 type 字符串,也就是 device_type 属性值,可以为 NULL,表示忽略掉 device_type 属性。

compatible要查找的节点所对应的 compatible 属性列表。

返回值:找到的节点,如果为 NULL 表示查找失败

②of_get_named_gpio 函数

此函数获取 GPIO 编号,因为 Linux 内核中关于 GPIO 的 API 函数都要使用 GPIO 编号,此函数会将设备树中类似<&gpio5 7 GPIO_ACTIVE_LOW>的属性信息转换为对应的 GPIO 编号,此函数在驱动中使用很频繁!函数原型如下:

int of_get_named_gpio(struct device_node *np, const char *propname, int index)

函数参数和返回值含义如下:

np:设备节点。

propname:包含要获取 GPIO 信息的属性名。

③irq_of_parse_and_map 函数

编写驱动的时候需要用到中断号,我们用到中断号,中断信息已经写到了设备树里面,因

此可以通过 irq_of_parse_and_map 函数从 interupts 属性中提取到对应的设备号,函数原型如下: unsigned int irq_of_parse_and_map(struct device_node *dev, int index)

函数参数和返回值含义如下:

dev设备节点。

index:索引号,interrupts 属性可能包含多条中断信息,通过 index 指定要获取的信息。

返回值:中断号。

示例


   
   
  1. //设备树节点
  2. &misc {
  3. compatible = "misc,test";
  4. interrupt-parent = <&pio>;
  5. interrupts = < 8 IRQ_TYPE_EDGE_FALLING>;
  6. test-gpio = <&pio 30 0>;
  7. };
  8. //API使用示例
  9. //获取指定节点,获取不到时返回NULL
  10. struct device_node *nd = of_find_compatible_node( NULL, NULL, "misc,test");
  11. //获取GPIO编号,获取不到时返回负值
  12. int test_gpio = of_get_named_gpio(nd, "test-gpio", 0);
  13. //获取中断号,获取不到时返回负值
  14. static unsigned int tp_irq = irq_of_parse_and_map(nd, 0);
  15. ...

二、GPIO—API

①gpio_request 函数

gpio_request 函数用于申请一个 GPIO 管脚,在使用一个 GPIO 之前一定要使用 gpio_request 进行申请

函数原型如下:

int gpio_request(unsigned gpio, const char *label)

函数参数和返回值含义如下:

gpio:要申请的 gpio 标号,使用 of_get_named_gpio 函数从设备树获取指定 GPIO 属性信息,此函数会返回这个 GPIO 的标号。

label:给 gpio 设置个名字。

返回值:0,申请成功;其他值,申请失败。

②gpio_free 函数

如果不使用某个 GPIO 了,那么就可以调用 gpio_free 函数进行释放。函数原型如下:

void gpio_free(unsigned gpio)

函数参数和返回值含义如下:

gpio:要释放的 gpio 标号。

返回值:无。

③gpio_direction_input 函数

此函数用于设置某个 GPIO 为输入,函数原型如下所示:

int gpio_direction_input(unsigned gpio)

函数参数和返回值含义如下:

gpio:要设置为输入的 GPIO 标号。

返回值:0,设置成功;负值,设置失败。

④gpio_direction_output 函数

此函数用于设置某个 GPIO 为输出,并且设置默认输出值,函数原型如下:

int gpio_direction_output(unsigned gpio, int value)

函数参数和返回值含义如下:

gpio:要设置为输出的 GPIO 标号。

valueGPIO 默认输出值。

返回值:0,设置成功;负值,设置失败。

⑤gpio_is_valid 函数

检测gpio端口是否合法,函数原型如下:

int gpio_is_valid(int number); 

函数参数和返回值含义如下:

numbergpio端口号

返回值:无效反为0

⑥gpio_get_value 函数

此函数用于获取某个 GPIO 的值(0 或 1),此函数是个宏,定义所示:

#define gpio_get_value __gpio_get_value

int __gpio_get_value(unsigned gpio)

函数参数和返回值含义如下:

gpio:要获取的 GPIO 标号。

返回值:非负值,得到的 GPIO 值;负值,获取失败。

⑦gpio_set_value 函数

此函数用于设置某个 GPIO 的值,此函数是个宏,定义如下

#define gpio_set_value __gpio_set_value

void __gpio_set_value(unsigned gpio, int value)

函数参数和返回值含义如下:

gpio:要设置的 GPIO 标号。

value要设置的值。

返回值:

示例


   
   
  1. //设备树节点
  2. &misc {
  3. compatible = "misc,test";
  4. interrupt-parent = <&pio>;
  5. interrupts = < 8 IRQ_TYPE_EDGE_FALLING>;
  6. test-gpio = <&pio 30 0>;
  7. };
  8. //API使用示例
  9. //获取指定节点,获取不到时返回NULL
  10. struct device_node *nd = of_find_compatible_node( NULL, NULL, "misc,test");
  11. //获取GPIO编号,获取不到时返回负值
  12. int test_gpio = of_get_named_gpio(nd, "test-gpio", 0);
  13. /
  14. /
  15. //设置gpio为输出,同时设置输出寄存器为0,即低电平
  16. int val = gpio_direction_output(test_gpio, 0);
  17. //获取gpio状态,高低电平(0或1)
  18. int status = gpio_get_value(test_gpio);
  19. //设置gpio输出寄存器为1,即高电平
  20. gpio_set_value(test_gpio, 1);
  21. //读写操作可能导致睡眠,在中断中就需要使用带cansleep的函数
  22. //gpio_get_value_cansleep(test_gpio);
  23. //gpio_set_value_cansleep(test_gpio, 1);
  24. //设置gpio为输入
  25. gpio_direction_input(test_gpio);
  26. ...

三、中断—API

①request_irq 函数

在 Linux 内核中要想使用某个中断是需要申请的,request_irq 函数用于申请中断,request_irq 函数可能会导致睡眠,因此不能在中断上下文或者其他禁止睡眠的代码段中使用 request_irq 函数。request_irq 函数会激活(使能)中断,所以不需要我们手动去使能中断

request_irq 函数原型如下:

int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name,

void *dev) 函数参数和返回值含义如下:

irq:要申请中断的中断号。

handler:中断处理函数,当中断发生以后就会执行此中断处理函数。

flags:中断标志,可以在文件 include/linux/interrupt.h 里面查看所有的中断标志

name:中断名字,设置以后可以在/proc/interrupts 文件中看到对应的中断名字。

dev如果将 flags 设置为 IRQF_SHARED 的话,dev 用来区分不同的中断,一般情况下将dev 设置为设备结构体,dev 会传递给中断处理函数 irq_handler_t 的第二个参数。

返回值:0 中断申请成功,其他负值 中断申请失败,如果返回-EBUSY 的话表示中断已经

被申请了。

②free_irq 函数

void free_irq(unsigned int irq, void *dev_id)

关于该函数参数的一些说明如下:

  • irq参数是已经申请的硬件中断号;
  • dev_id参数和request_irq()函数的dev参数对应,一般为设备的设备结构体或者 NULL。

③enable_irq()与disable_irq()函数

在Linux设备驱动中断编程中,如果想要使能或者屏蔽中断的话,可以使用enable_irq()和disable_irq()内核函数接口。

使能中断IRQ,可以使用enable_irq()函数接口,该函数的定义如下:


    
    
  1. void enable_irq(unsigned int irq)
  2. {
  3.      unsigned long flags;
  4. struct irq_desc *desc = irq_get_desc_buslock(irq, &flags,
  5. IRQ_GET_DESC_CHECK_GLOBAL);
  6.      if (!desc)
  7.          return;
  8.      if ( WARN(!desc->irq_data.chip, \
  9. KERN_ERR "enable_irq before setup/request_irq: irq %u\n", irq))
  10.          goto out;
  11.     __enable_irq(desc);
  12. out:
  13.      irq_put_desc_busunlock(desc, flags);
  14. }

屏蔽中断IRQ,可以使用disable_irq()和disable_irq_nosync()函数,这两个函数的定义如下:


    
    
  1. void disable_ir q(unsigned int irq)
  2. {
  3.      if (!__disable_irq_nosync(irq))
  4.         synchronize_ir q(irq);
  5. }
  6. void disable_irq_nosync(unsigned int irq)
  7. {
  8.     __disable_irq_nosync(irq);
  9. }

两个函数的形参都是irq,表示要屏蔽中断的硬件中断号,这两个函数的区别在于,disable_irq()函数会等待目前的中断处理完成,而disable_irq_nosync()函数则不会等待。

示例:


   
   
  1. //设备树节点
  2. &misc {
  3. compatible = "misc,test";
  4. interrupt-parent = <&pio>;
  5. interrupts = < 8 IRQ_TYPE_EDGE_FALLING>;
  6. test-gpio = <&pio 30 0>;
  7. };
  8. //API使用示例
  9. //获取指定节点,获取不到时返回NULL
  10. struct device_node *nd = of_find_compatible_node( NULL, NULL, "misc,test");
  11. //获取GPIO编号,获取不到时返回负值
  12. int test_gpio = of_get_named_gpio(nd, "test-gpio", 0);
  13. //获取中断号,获取不到时返回负值
  14. static unsigned int tp_irq = irq_of_parse_and_map(nd, 0);
  15. //申请一个 GPIO ,使用前需要向系统申请一下,别人就用不能用了
  16. gpio_request(test_gpio, "test_gpio");
  17. //申请中断,同时注册test_interrupt_handler为回调函数
  18. int ret = request_irq(tp_irq, ( irq_handler_t) test_interrupt_handler, IRQF_TRIGGER_FALLING, "test-eint", NULL);
  19. ...

四、Pinctrl—API 

①devm_pinctrl_get 函数

struct pinctrl * devm_pinctrl_get(struct device *dev); 

函数功能:根据设备获取pin操作句柄,所有的pin操作必须基于此pinctrl句柄。与pinctrl_get接口功能完全一样,只是devm_pinctrl_get会将申请的pinctrl句柄做记账,绑定到设备句柄信息中。设备驱动申请pin资源,推荐优先使用devm_pinctrl_get接口。

返回值 pinctrl句柄 

参数 dev:使用pin的设备,pinctrl子系统会通过设备名与pin配置信息匹配。 

②devm_pinctrl_put 函数

函数原型 void devm_pinctrl_put(struct pinctrl *p); 

函数功能 释放pinctrl句柄,必须与devm_pinctrl_get配对使用。

返回值 无 

参数 p:pinctrl句柄 

③pinctrl_lookup_state 函数

函数原型 struct pinctrl_state * pinctrl_lookup_state(struct pinctrl *p, const char *name);

函数功能 查找pin句柄指定状态下的状态句柄。

返回值 状态句柄

参数 p:pinctrl句柄 

name:状态名称,A33平台上只有default一种状态

④pinctrl_select_state函数

函数原型 int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s);

函数功能 设置pin句柄的状态到硬件

返回值 0表示成功,其它表示失败

参数 p:pinctrl句柄 

S:状态句柄

示例


   
   
  1. //设备树节点
  2. default: tp_test_pins_1: eint@ 8 {
  3. pins_cmd_dat {
  4. pins = <MT8163_PIN_30_EINT8__FUNC_GPIO30>;
  5. /*配置成输入下拉*/
  6. slew-rate = < 0>;
  7. bias-pull-down = < 00>;
  8. /*//配置成输入pull disable
  9. slew-rate = <0>;
  10. bias-disable;
  11. //配置成输出high
  12. slew-rate = <1>;
  13. bias-disable;
  14. output-high;
  15. //配置成输出low
  16. slew-rate = <1>;
  17. bias-disable;
  18. output-low;*/
  19. };
  20. };
  21. tp_test_pins_1: eint@ 8 {
  22. pins_cmd_dat {
  23. pins = <MT8163_PIN_30_EINT8__FUNC_GPIO30>;
  24. slew-rate = < 1>;
  25. bias-disable;
  26. output-high;
  27. };
  28. };
  29. &misc {
  30. compatible = "misc,test";
  31. interrupt-parent = <&pio>;
  32. interrupts = < 8 IRQ_TYPE_EDGE_FALLING>;
  33. eint-debounce = < 256>;
  34. pinctrl-names = "default", "tp_test_1";
  35. pinctrl -0 = <& default>;
  36. pinctrl -1 = <&tp_test_pins_1>;
  37. test1-gpio = <&pio 30 0>;
  38. test2-gpio = <&pio 31 0>;
  39. status = "okay";
  40. };
  41. //获得设备对应的pin control state holder
  42. static struct pinctrl *pinctrl_test = devm_pinctrl_get(&dev);
  43. //查找pin control state
  44. struct pinctrl_state *tp_test_1 = pinctrl_lookup_state(pinctrl_test, "default");
  45. struct pinctrl_state *tp_test_2 = pinctrl_lookup_state(pinctrl_test, "tp_test_1");
  46. //设置gpio功能
  47. pinctrl_select_state(pinctrl_test, tp_test_1 );
  48. pinctrl_select_state(pinctrl_test, tp_test_2 );

注:Pinctrl模块兼容GPIO的功能,如果pin是作为GPIO input/output,仍然可以使用gpiolib中的标准接口,但是如果要使用GPIO的复用功能,则需要使用pinctrl接口。

在驱动代码中我们经常会见到一些以devm开头的函数,这一类的函数都是和设备资源管理(Managed Device Resource)相关的,驱动中提供这些函数主要是为了方便对于申请的资源进行释放,比如:irq、regulator、gpio等等。在驱动进行初始化的时候如果失败,那么通常会goto到某个地方释放资源,这样的标签多了之后会让代码看起来不简洁,devm就是为来处理这种情况。

转载至博客 https://blog.csdn.net/maodewen11/article/details/120651677
  • 4
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: GPIO是英文General Purpose Input/Output的缩写,翻译过来就是通用输入输出。Linux内核提供了GPIO驱动框架,可以通过该框架来控制硬件上的GPIO,实现对外设的控制。 在Linux内核中,GPIO驱动可以分为两类:基于平台的GPIO驱动和基于设备的GPIO驱动。基于平台的GPIO驱动是针对整个平台的GPIO控制,而基于设备的GPIO驱动则是针对单个设备的GPIO控制。 在使用GPIO驱动时,需要先找到所使用的GPIO引脚的编号,并将其映射到内存中的地址。然后通过读写内存中的寄存器来控制GPIO的状态。 对于GPIO的操作可以通过Linux内核提供的sysfs接口来实现。在sysfs中,每个GPIO都被表示为一个文件,可以通过读写文件来进行GPIO的操作。 需要注意的是,在使用GPIO驱动时,需要谨慎操作,避免对硬件造成损坏。同时,还需要了解所使用的硬件设备的特性和限制,以确保GPIO驱动的正确使用。补充说明: 在Linux内核中,GPIO驱动主要由GPIO子系统和GPIO控制器驱动部分组成。GPIO子系统提供了一个通用的接口,用于操作GPIO控制器驱动,而GPIO控制器驱动则是实际控制硬件的部分GPIO子系统可以分为两个部分GPIO框架和GPIO API。GPIO框架是一个通用的框架,用于管理GPIO控制器和GPIO设备,它定义了一些数据结构和函数接口,用于注册和管理GPIO控制器和GPIO设备。GPIO API是一个用户空间的API,提供了一些函数接口,用于操作GPIOGPIO控制器驱动是针对特定的GPIO控制器的驱动程序,它负责实际控制GPIO的硬件操作。在Linux内核中,每种GPIO控制器都有一个对应的GPIO控制器驱动程序。当使用GPIO时,首先需要通过GPIO子系统将GPIO控制器驱动注册到系统中,然后才能使用GPIO API对GPIO进行操作。 需要注意的是,在使用GPIO驱动时,需要注意GPIO的电气特性,避免对硬件造成损坏。同时,在进行GPIO操作时,还需要注意GPIO的并发访问和竞争问题,以确保系统的正确性和稳定性。 ### 回答2: Linux GPI驱动指的是Linux系统中通过General Purpose Input/OutputGPIO)接口与硬件设备进行交互的驱动程序。GPIO接口是一组通用的、可编程的多功能引脚,可用于连接各种外部设备,例如开关、LED、传感器、驱动器等。 Linux GPIO驱动可以实现对GPIO引脚的读写操作、中断处理等功能。它不仅可以与单片机等嵌入式设备进行通信,还可与各种外接硬件设备进行连接和通信。 在Linux系统中,用户可以通过/sys/class/gpio文件系统来访问GPIO引脚。在使用GPIO驱动时,用户需要首先加载相应的内核模块,然后使用GPIO API来对引脚进行读写操作或开启中断。 GPIO驱动程序需要实现以下功能: 1. 查询GPIO可用性及分配资源。通常,由于GPIO是多路的,因此设备需要分配资源共享GPIO。 2. 初始化GPIO引脚,包括定义方向及设置上下拉电阻等。 3. 实现GPIO引脚的读写操作。 4. 解除分配资源并释放相关资源。 正常情况下,GPIO驱动程序会提供一个设备文件,用户可以通过读写该文件实现GPIO引脚的操作。 总之,Linux GPIO驱动具有良好的可移植性和稳定性,可以方便地与其他硬件设备进行交互,因此被广泛应用于各种嵌入式设备和嵌入式系统中。 ### 回答3: Linux GPIO驱动是一种在嵌入式系统中实现通用输入输出(GPIO,General Purpose Input/Output)功能的软件驱动GPIO是一种非常有用的硬件资源,它可以连接到外部设备,例如LED灯、按键和触摸屏等。 Linux内核支持GPIO操作,当你的嵌入式系统上有GPIO设备时,你可以利用GPIO来读取或设置其状态。驱动程序能够将GPIO标记为输入或输出,并且它们可以在运行时进行配置。 在Linux中,一般有两种方式将GPIO驱动程序添加到内核中:一种是将其编译到内核中,另一种是将其作为模块加载。 GPIO驱动程序等价于操作系统提供的设备文件,例如/dev/gpiochip0,它允许用户空间应用程序访问GPIO。这些设备文件可用于读取或写入GPIO状态。例如,要控制一个LED,需要将GPIO设置为输出模式,然后将其电平设置为高或低即可。 除此之外,GPIO驱动程序也可以实现中断(interrupt)机制,GPIO的状态变化时可以产生中断事件,这常用于处理GPIO键盘或GPIO中断信号的应用场景。 总结来说,Linux内核支持GPIO驱动需要有以下几个步骤:配置GPIO硬件;添加驱动程序;编写用户空间应用程序,按需要读取或设置GPIO状态来和外设交互。GPIO驱动程序是嵌入式系统中非常必要的组成部分,它们能够随时提供接口以方便对外部设备的读写访问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值