瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网网关、NVR 存储、工控平板、工业检测、工控盒、卡拉 OK、云终端、车载中控等行业。
【公众号】迅为电子
【粉丝群】824412014(加群获取驱动文档+例程)
【视频观看】嵌入式学习之Linux驱动(第七期_设备树_全新升级)_基于RK3568
【购买链接】迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板
第69章 of操作函数实验:获取中断资源
69.1 of操作:获取中断资源
69.1.1 irq_of_parse_and_map函数
该函数的主要功能是解析设备节点的"interrupts"属性,并将对应的中断号映射到系统的中断号。"interrupts"属性通常以一种特定的格式表示,可以包含一个或多个中断号。通过提供索引号,可以获取对应的中断号。
函数原型:
unsigned int irq_of_parse_and_map(struct device_node *dev, int index);
头文件:
#include <linux/of_irq.h>
函数作用:
从设备节点的"interrupts"属性中解析和映射对应的中断号
参数说明:
dev:设备节点,表示要解析的设备节点。
index:索引号,表示从"interrupts"属性中获取第几个中断号。
返回值:
是一个无符号整数,表示成功解析和映射的中断号。
69.1.2 irq_get_trigger_type函数
该函数的主要功能是从给定的中断数据结构中提取中断触发类型。中断触发类型描述了中断信号的触发条件,例如边沿触发(edge-triggered)或电平触发(level-triggered)等。
函数原型:
u32 irqd_get_trigger_type(struct irq_data *d);
头文件:
#include <linux/irq.h>
函数作用:
从中断数据结构(irq_data)中获取对应的中断触发类型。
参数说明:
d:中断数据结构(irq_data),表示要获取中断触发类型的中断。
返回值:
是一个无符号32位整数,表示成功获取的中断触发类型。
69.1.3 irq_get_irq_data函数
函数irq_get_irq_data的作用是根据中断号获取对应的中断数据结构(irq_data)。
函数原型:
struct irq_data *irq_get_irq_data(unsigned int irq);
头文件:
#include <linux/irq.h>
函数作用:
根据中断号获取对应的中断数据结构。
参数说明:
irq:中断号,表示要获取中断数据结构的中断号。
返回值:
指向irq_data结构体的指针,表示成功获取的中断数据结构。
69.1.4 gpio_to_irq函数
该函数的主要功能是将给定的GPIO编号转换为对应的中断号。在某些系统中,GPIO可以配置为中断引脚,当特定事件发生时触发中断。通过该函数,可以根据GPIO编号获取与之关联的中断号,以便进行中断处理等操作。
函数原型:
int gpio_to_irq(unsigned int gpio);
头文件:
#include <linux/gpio.h>
函数作用:
根据GPIO编号获取对应的中断号。
参数说明:
gpio:GPIO编号,表示要获取中断号的GPIO。
返回值:
是一个整数,表示成功获取的中断号。
69.1.5 of_irq_get函数
该函数的主要功能是从给定的设备节点的"interrupts"属性中解析并获取对应的中断号。"interrupts"属性通常以一种特定的格式表示,可以包含一个或多个中断号。通过提供索引号,可以获取对应的中断号
函数原型:
int of_irq_get(struct device_node *dev, int index);
头文件 :
#include <linux/of_irq.h>
函数作用:
是从设备节点的"interrupts"属性中获取对应的中断号。
参数说明:
dev:设备节点,表示要获取中断号的设备节点。
index:索引号,表示从"interrupts"属性中获取第几个中断号。
返回值:
是一个整数,表示成功获取的中断号。
69.1.6 irq_of_parse_and_map函数
irq_of_parse_and_map函数的主要功能是根据给定的平台设备和索引号获取对应的中断号。平台设备是指与特定硬件平台相关的设备。在某些情况下,平台设备可能具有多个中断号,通过提供索引号,可以获取对应的中断号。
函数原型:
int platform_get_irq(struct platform_device *dev, unsigned int num);
函数作用:
根据平台设备和索引号获取对应的中断号。
头文件:
linux/platform_device.h
参数说明:
dev:平台设备,表示要获取中断号的平台设备。
num:索引号,表示从中获取第几个中断号。
返回值:
是一个整数,表示成功获取的中断号。
69.2 实验程序编写
69.2.1 设备树的修改
本实验修改完成的设备树和编译完成的boot.img对应的网盘路径为:iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\57_of_03\dts。
由于本章节要获取的是中断相关的资源,所以需要在设备树中添加有关中断的设备节点,在第57章节的学习中,我们已经对中断实例进行了讲解,所以这里直接对rk3568-evb1-ddr4-v10-linux.dts设备树进行中断节点的添加,添加的内容如下所示:
cpp
myirq {
compatible = "my_devicetree_irq";
interrupt-parent = <&gpio3>;
interrupts = <RK_PA5 IRQ_TYPE_LEVEL_LOW>;
};
添加完成如下图(图69-1)所示:
图249-1
保存退出之后,重新编译内核源码,得到boot.img内核镜像之后烧写到开发板即可。
69.2.2 实验程序的编写
本实验驱动对应的网盘路径为:iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\57_of_03。
本小节驱动程序是由65章驱动程序修改而来,由于本章节获取中断属性的函数需要在查找到设备树节点的前提下使用,所以在下面的程序中,先在probe函数中查找设备树节点,然后添加了本章节学习的of操作相关代码和其他一些相关的函数,用来获取设备树节点中断资源。
编写完成的platform_driver.c代码如下所示:
cpp
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/gpio.h>
int num;
int irq;
struct irq_data *my_irq_data;
struct device_node *mydevice_node;
u32 trigger_type;
// 平台设备的初始化函数
static int my_platform_probe(struct platform_device *pdev)
{
printk(KERN_INFO "my_platform_probe: Probing platform device\n");
// 查找设备节点
mydevice_node = of_find_node_by_name(NULL, "myirq");
// 解析和映射中断
irq = irq_of_parse_and_map(mydevice_node, 0);
printk("irq is %d\n", irq);
// 获取中断数据结构
my_irq_data = irq_get_irq_data(irq);
// 获取中断触发类型
trigger_type = irqd_get_trigger_type(my_irq_data);
printk("trigger type is 0x%x\n", trigger_type);
// 将GPIO转换为中断号
irq = gpio_to_irq(101);
printk("irq is %d\n", irq);
// 从设备节点获取中断号
irq = of_irq_get(mydevice_node, 0);
printk("irq is %d\n", irq);
// 获取平台设备的中断号
irq = platform_get_irq(pdev, 0);
printk("irq is %d\n", irq);
return 0;
}
// 平台设备的移除函数
static int my_platform_remove(struct platform_device *pdev)
{
printk(KERN_INFO "my_platform_remove: Removing platform device\n");
// 清理设备特定的操作
// ...
return 0;
}
const struct of_device_id of_match_table_id[] = {
{.compatible="my_devicetree_irq"},
};
// 定义平台驱动结构体
static struct platform_driver my_platform_driver = {
.probe = my_platform_probe,
.remove = my_platform_remove,
.driver = {
.name = "my_platform_device",
.owner = THIS_MODULE,
.of_match_table = of_match_table_id,
},
};
// 模块初始化函数
static int __init my_platform_driver_init(void)
{
int ret;
// 注册平台驱动
ret = platform_driver_register(&my_platform_driver);
if (ret) {
printk(KERN_ERR "Failed to register platform driver\n");
return ret;
}
printk(KERN_INFO "my_platform_driver: Platform driver initialized\n");
return 0;
}
// 模块退出函数
static void __exit my_platform_driver_exit(void)
{
// 注销平台驱动
platform_driver_unregister(&my_platform_driver);
printk(KERN_INFO "my_platform_driver: Platform driver exited\n");
}
module_init(my_platform_driver_init);
module_exit(my_platform_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("topeet");
69.3 运行测试
69.3.1 编译驱动程序
cpp
export ARCH=arm64#设置平台架构
export CROSS_COMPILE=aarch64-linux-gnu-#交叉编译器前缀
obj-m += platform_driver.o #此处要和你的驱动源文件同名
KDIR :=/home/topeet/Linux/linux_sdk/kernel #这里是你的内核目录
PWD ?= $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules #make操作
clean:
make -C $(KDIR) M=$(PWD) clean #make clean操作
对于Makefile的内容注释已在上图添加,保存退出之后,来到存放platform_driver.c和Makefile文件目录下,如下图(图69-2)所示:
图 69-2
然后使用命令"make"进行驱动的编译,编译完成如下图(图69-3)所示:
图 69-3
编译完生成platform_driver.ko目标文件,如下图(图69-4)所示:
图 69-4
至此驱动模块就编译成功了。
69.3.2 运行测试
在进行实验之前,首先要确保开发板烧写的是我们在69.2.1小节中编译出来的boot.img,开发板启动之后,使用以下命令进行驱动模块的加载,如下图(图69-5)所示:
insmod platform_driver.ko
图 69-5
可以看到总共有5个打印,第1、3、4、5个打印都是获取的中断号为113,第2个打印的是中断的类型,即IRQ_TYPE_LEVEL_LOW,该触发类型的宏定义在内核源码"include/dt-bindings/interrupt-controller/irq.h"目录下,具体内容如下所示:
cpp
#define IRQ_TYPE_NONE 0 // 无中断触发类型
#define IRQ_TYPE_EDGE_RISING 1 // 上升沿触发
#define IRQ_TYPE_EDGE_FALLING 2 // 下降沿触发
#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)// 双边沿触发
#define IRQ_TYPE_LEVEL_HIGH 4 // 高电平触发
#define IRQ_TYPE_LEVEL_LOW 8 // 低电平触发
可以看到IRQ_TYPE_LEVEL_LOW的宏定义为8,证明上面的打印正确。
然后使用以下命令进行驱动模块的卸载,如下图(图69-6)所示:
rmmod platform_driver.ko
图 69-6
至此,使用of操作函数获取中断资源实验就完成了。