迅为RK3568开发板驱动指南GPIO子系统GPIO子系统API函数的引入
瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE图形处理器。RK3568支持4K解码和1080P编码,支持SATA/PCIE/USB3.0外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568支持安卓11和linux系统,主要面向物联网网关、NVR存储、工控平板、工业检测、工控盒、卡拉OK、云终端、车载中控等行业。
迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板
第131章GPIO子系统API函数的引入
事实上,在前面中断课程中,已经简单接触到了GPIO子系统中的API函数,其中用来获取gpio中断编号的gpio_to_irq函数就属于GPIO子系统中的API函数,在本章节中将对GPIO子系统进行简单的介绍。
在目前的Linux内核主线中,GPIO(通用输入/输出)子系统存在两个版本,这里将两个版本区分为新版本和旧版本。新版本GPIO子系统接口是基于描述符(descriptor-based)来实现的,而旧版本的GPIO子系统接口是基于整数(integer-based)来实现的,在Linux内核中为了保持向下的兼容性,旧版本的接口在最新的内核版本中仍然得到支持,而随着时间的推移,新版本的GPIO子系统接口会越来越完善,最终完全取代旧版本,所以在本课程中主要讲解新版本的GPIO子系统接口。
新的GPIO子系统接口需要与与设备树(Device Tree)结合使用。使用设备树和新的GPIO接口可以更加灵活地配置和管理系统中的GPIO资源,提供了更好的可扩展性和可移植性。所以如果没有设备树,就无法使用新的GPIO接口。
那要如何对新旧GPIO子系统接口进行区分呢,一个明显的区别是新的GPIO子系统接口使用了以"gpiod_"作为前缀的函数命名约定,而旧的GPIO子系统接口使用了以"gpio_"作为前缀的函数命名约定。
一些区分新旧 GPIO子系统接口的示例如下所示:
新的 GPIO子系统接口示例如下所示:
gpiod_set_value()
gpiod_direction_input()
gpiod_direction_output()
gpiod_get_value()
gpiod_request()
AI写代码
cpp
旧的 GPIO子系统接口示例:
gpio_set_value()
gpio_direction_input()
gpio_direction_output()
gpio_get_value()
gpio_request()
AI写代码
cpp
上面也提到了新的 GPIO子系统接口是基于描述符(descriptor-based)来实现的,由struct gpio_desc结构体来表示,该结构体定义在内核源码的“drivers/gpio/gpiolib.h”目录下。具体内容如下所示:
struct gpio_desc {
struct gpio_device gdev; // GPIO设备结构体
unsigned long flags; //标志位,用于表示不同的属性
/*标志位符号对应的位号*/
#define FLAG_REQUESTED 0 // GPIO已请求
#define FLAG_IS_OUT 1 // GPIO用作输出
#define FLAG_EXPORT 2 //受sysfs_lock保护的导出标志
#define FLAG_SYSFS 3 //通过/sys/class/gpio/control导出的标志
#define FLAG_ACTIVE_LOW 6 // GPIO值为低电平时激活
#define FLAG_OPEN_DRAIN 7 // GPIO为开漏类型
#define FLAG_OPEN_SOURCE 8 // GPIO为开源类型
#define FLAG_USED_AS_IRQ 9 // GPIO连接到中断请求(IRQ)
#define FLAG_IS_HOGGED 11 // GPIO被独占占用
#define FLAG_TRANSITORY 12 // GPIO在休眠或复位时可能失去值
/*连接标签*/
const char *label; // GPIO的名称
const char *name; // GPIO的名称
};
AI写代码
cpp
(1)struct gpio_device gdev是一个struct gpio_device类型的字段,用于表示GPIO设备的相关信息。struct gpio_device结构体通常包含设备的底层硬件控制器等信息。
(2)unsigned long flags:用于表示GPIO的标志位,以表示不同的属性。通过使用位操作,每个标志位可以单独设置或清除。
(3)第5-14行用于表示不同标志位的符号常量,与flags字段中的位号相对应。例如,在flags字段中的第0位表示FLAG_REQUESTED,第1位表示FLAG_IS_OUT,以此类推
(4)const char *label:这是一个指向字符串的指针,表示GPIO的标签或名称。
(5)const char *name:这是一个指向字符串的指针,表示GPIO的名称。
上面需要重点关注的是然后struct gpio_device结构体,该结构体同样定义在内核源码的“drivers/gpio/gpiolib.h”目录下,具体内容如下所示:
struct gpio_device {
int id; // GPIO设备ID
struct device *dev; //对应的设备结构体指针
struct cdev chrdev; //字符设备结构体
struct device *mockdev; //模拟设备结构体指针
struct module *owner; //拥有该GPIO设备的内核模块指针
struct gpio_chip *chip; //对应的GPIO芯片结构体指针
struct gpio_desc *descs; // GPIO描述符数组指针
int base; // GPIO编号的起始值
u16 ngpio; // GPIO的数量
const char *label; // GPIO设备的标签
void *data; //与GPIO设备相关的数据指针
struct list_head list; //用于将GPIO设备结构体连接到链表中
#ifdef CONFIG_PINCTRL
/*
*如果启用了CONFIG_PINCTRL选项,GPIO控制器可以选择描述它们在SoC中服务的实际引脚范围。
*此信息将由pinctrl子系统用于配置相应的GPIO引脚。
*/
struct list_head pin_ranges; //描述GPIO控制器引脚范围的链表
#endif
};
AI写代码
cpp
该结构体是用来描述GPIO设备的数据结构,关于该结构体的参数介绍如下所示:
(1)int id:整型字段,表示GPIO设备的ID。每个GPIO设备可以有一个唯一的ID。
(2)struct device *dev:指向struct device的指针,表示与GPIO设备相关联的设备结构体。
(3)struct cdev chrdev:字符设备结构体,用于实现GPIO设备的字符设备接口。
(4)struct device *mockdev:指向struct device的指针,用于表示GPIO设备的模拟设备结构体。
(5)struct module *owner:指向拥有该GPIO设备的内核模块的指针。
(6)struct gpio_chip *chip:指向struct gpio_chip的指针,表示与GPIO设备关联的GPIO芯片(GPIO控制器)结构体。
(7)struct gpio_desc *descs:指向struct gpio_desc数组的指针,表示与GPIO设备关联的GPIO描述符。每个GPIO描述符用于描述GPIO的属性和状态。
(8)int base:表示GPIO编号的起始值。
(9)u16 ngpio: 16位无符号整型字段,表示GPIO的数量。
(10)const char *label:指向字符串的指针,表示GPIO设备的标签或名称。
(11)void *data:指向与GPIO设备相关的数据的指针,用于存储和访问与GPIO设备相关的自定义数据。
(12)struct list_head list:将GPIO设备结构体连接到链表中的字段,用于管理多个GPIO设备的列表。
(13)struct list_head pin_ranges (仅在启用CONFIG_PINCTRL选项时存在):用于描述GPIO控制器引脚范围的链表。如果配置了GPIO控制器的引脚范围,该链表将包含描述每个范围的元素。
在上面一系列的参数中,要重点关注的是struct gpio_chip *chip这一结构体,表示与GPIO设备关联的GPIO芯片(GPIO控制器)结构体,该结构体定义在内核源码目录下的“include/linux/gpio/driver.h”文件中,具体内容如下所示
struct gpio_chip {
const char *label; // GPIO芯片标签
struct gpio_device gpiodev; // GPIO设备
struct device *parent; //父设备指针
struct module *owner; //拥有者模块指针
int (*request)(struct gpio_chip *chip, unsigned offset);//请求GPIO
void (*free)(struct gpio_chip *chip, unsigned offset); //释放GPIO
int (*get_direction)(struct gpio_chip *chip, unsigned offset); //获取GPIO方向
int (*direction_input)(struct gpio_chip *chip, unsigned offset); //设置GPIO为输入
int (*direction_output)(struct gpio_chip *chip, unsigned offset, int value); //设置GPIO为输出
int (*get)(struct gpio_chip chip, unsigned offset); //获取GPIO值
int (*get_multiple)(struct gpio_chip chip, unsigned long *mask, unsigned long *bits); //获取多个GPIO的值
void (*set)(struct gpio_chip chip, unsigned offset, int value); //设置GPIO值
void (*set_multiple)(struct gpio_chip chip, unsigned long mask, unsigned long *bits); //设置多个GPIO的值
int (*set_config)(struct gpio_chip *chip, unsigned offset, unsigned long config); //设置GPIO配置
int (*to_irq)(struct gpio_chip chip, unsigned offset); //将GPIO转换为中断
void (*dbg_show)(struct seq_file *s, struct gpio_chip chip); //在调试信息中显示GPIO
int base; // GPIO编号的基准值
u16 ngpio; // GPIO的数量
const char *const *names; // GPIO的名称数组
..........
};
AI写代码
cpp
struct gpio_chip *chip这一结构体用于描述GPIO芯片的属性和操作函数,可以通过函数指针调用相应的函数来请求、释放、设置、获取GPIO的状态和数值等操作,从而实现对GPIO的控制和管理,需要注意的是这个结构体中的一系列函数都不需要我们来填充,这些工作都是由芯片原厂工程师来完成的,我们只需要学会新gpio子系统相应API函数的使用即可。
在接下来的章节中将对常用的新gpio子系统API函数进行讲解。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/BeiJingXunWei/article/details/135569658
查看全文
评论0条评论