我是靠谱客的博主 失眠大门,最近开发中收集的这篇文章主要介绍Linux GPIO驱动部分函数一、设备树—API二、GPIO—API三、中断—API四、Pinctrl—API ,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、设备树—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 %un", 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

最后

以上就是失眠大门为你收集整理的Linux GPIO驱动部分函数一、设备树—API二、GPIO—API三、中断—API四、Pinctrl—API 的全部内容,希望文章能够帮你解决Linux GPIO驱动部分函数一、设备树—API二、GPIO—API三、中断—API四、Pinctrl—API 所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(54)

评论列表共有 0 条评论

立即
投稿
返回
顶部