提示:of 函数获取中断信息
文章目录
前言
- 前面了解了of 函数获取设备节点、设备属性 相关内容,这里通过 of 函数获取中断相关信息
一、参考资料
Linux-驱动-设备树实案例分析-中断
Linux驱动-设备树-获取节点属性of函数分析
RK3568平台(中断篇)of操作函数获取中断资源
of操作函数——获取中断资源
二、of 相关API 获取中断资源
配置中断设备树节点
路径:kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-linux.dts
中,新增中断设备数描述,如下:
新增如下设备数,配置中断节点:
。。。。。
/{
topeet{
#address-cells = <1>;
#size-cells = <1>;
ranges;
compatible = "simple-bus";
myLed{
compatible = "my devicetree";
reg = <0xFDD60000 0x00000004>;
};
myirq {
compatible = "my_devicetree_irq";
interrupt-parent = <&gpio3>;
interrupts = <RK_PA5 IRQ_TYPE_LEVEL_LOW>;
};
};
};
。。。。。。。。。。
问题:
上面配置为什么这么配置,设备树中中断配置就是这么配置的,前面我们了解过。 这里我们参考的文件是:/kernel/arch/arm64/boot/dts/rockchip/topeet_rk3568_lcds.dtsi
编译Room后,查看开发板是否生成了中断设备,如下:路径:/sys/bus/platform/devices
[root@topeet:/sys/bus/platform/devices]# ls topeet
driver_override fdd60000.myLed modalias of_node power subsystem topeet:myirq uevent
看到了 topeet:myirq ,说明设备树生成设备成功。
irq_of_parse_and_map
irq_of_parse_and_map 是 Linux 设备树(DTS)操作中用于解析和映射中断请求(IRQ)的重要函数。它在设备驱动初始化过程中经常被使用,用于从设备树节点获取中断信息并将其映射到Linux内核的IRQ编号。
函数原型
unsigned int irq_of_parse_and_map(struct device_node *dev, int index);
参数说明
- dev: 指向设备树节点的指针,表示要从中获取中断信息的设备节点
- index: 中断的索引号,表示要获取该设备的第几个中断描述
返回值
成功返回Linux IRQ号,失败返回0
示例驱动代码如下:
#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_of_parse_and_map 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("wfc");
其中核心代码:
// 解析和映射中断
irq = irq_of_parse_and_map(mydevice_node, 0);
printk("irq_of_parse_and_map irq is %d\n", irq);
内部实现细节
- 首先查找设备节点的interrupts属性
- 获取或推断interrupt-parent(中断控制器)
- 使用中断控制器的xlate函数将设备树中断说明符转换为硬件IRQ号
- 调用irq_create_mapping将硬件IRQ号映射为Linux IRQ号
irq_get_trigger_type
irq_get_trigger_type 是 Linux 内核中用于获取中断触发类型的函数,它属于内核中断子系统的一部分。
函数原型
int irq_get_trigger_type(unsigned int irq);
参数说明:
- irq: 要查询的中断号(IRQ number)
返回值 返回该中断的触发类型,可能的取值包括:
- IRQ_TYPE_NONE - 未指定触发类型
- IRQ_TYPE_EDGE_RISING - 上升沿触发
- IRQ_TYPE_EDGE_FALLING - 下降沿触发
- IRQ_TYPE_EDGE_BOTH - 双边沿触发
- IRQ_TYPE_LEVEL_HIGH - 高电平触发
- IRQ_TYPE_LEVEL_LOW - 低电平触发
- 如果中断号无效,可能返回错误码
函数功能
该函数用于查询指定中断号的当前触发类型配置。触发类型决定了中断控制器在什么条件下会触发中断。
是咧编写:
irqq = platform_get_irq(pdev, 0);
printk("platform_get_irq 111 irqq is %d\n", irqq);
trigger_type = irq_get_trigger_type(irq);
printk("irq_get_trigger_type 222 trigger_type is %d\n", trigger_type);
结果如下:
哈哈,结果triger 类型是8 ,我们看看8 到底是什么值:Linux-驱动-设备树实案例分析-中断
那就和我们配置的低电平触发类型对上了,如下;
myirq {
compatible = "my_devicetree_irq";
interrupt-parent = <&gpio3>;
interrupts = <RK_PA5 IRQ_TYPE_LEVEL_LOW>;
};
irq_get_irq_data
irq_get_irq_data 是 Linux 内核中断子系统中的一个重要函数,用于获取与特定中断号关联的 irq_data 数据结构。这个函数提供了访问中断底层信息的接口。
函数原型
struct irq_data *irq_get_irq_data(unsigned int irq);
参数说明
irq: 要查询的中断号(IRQ number)
返回值
- 成功时返回指向 struct irq_data 的指针
- 如果中断号无效,返回 NULL
struct irq_data 关键成员
struct irq_data {
unsigned int irq; // 中断号
struct irq_chip *chip; // 关联的中断控制器芯片操作
struct irq_domain *domain; // 所属的irq domain
void *handler_data; // 控制器特定的handler数据
void *chip_data; // 控制器特定的芯片数据
unsigned long hwirq; // 硬件中断号
unsigned int state_use_accessors; // 中断状态标志
// ... 其他成员
};
gpio_to_irq
gpio_to_irq 是 Linux 内核中用于将 GPIO 编号转换为对应中断号(IRQ)的函数,属于 GPIO 子系统与中断子系统的桥梁函数。
函数原型
int gpio_to_irq(unsigned int gpio);
参数说明
- gpio: 要转换的 GPIO 编号(由 of_get_named_gpio() 或 gpiod_to_desc() 等函数获得)
返回值
- 成功时返回与 GPIO 关联的 Linux IRQ 编号
- 失败时返回负数错误码(常见如 -ENXIO 表示该 GPIO 不支持中断)
此函数完成以下工作:
- 通过 GPIO 编号查找对应的 GPIO 描述符
- 检查该 GPIO 是否配置为中断功能
- 返回映射到该 GPIO 的中断号
我们看看实际demo 和 结果:
// 将GPIO转换为中断号
irq = gpio_to_irq(101);
printk("irq is %d\n", irq);
of_irq_get
of_irq_get() 是 Linux 设备树(DTS)操作中用于解析和获取中断请求(IRQ)的核心函数,相比 irq_of_parse_and_map 提供了更完善的错误处理机制。
函数原型
int of_irq_get(struct device_node *dev, int index);
参数说明
- dev: 指向设备树节点的指针
- index: 中断的索引号(设备可能有多个中断)
返回值
- 成功: 返回映射后的 Linux IRQ 编号(正数)
- 失败: 返回负数错误码:
- -EINVAL: 参数无效
- -ENODEV: 设备不支持中断
- -ENXIO: 中断不存在或映射失败
- -EPROBE_DEFER: 依赖的资源未就绪(需要重试)
核心功能
- 解析设备树中的 interrupts 属性
- 查找 interrupt-parent 指定的中断控制器
- 将设备树中断说明符映射为 Linux IRQ 编号
- 提供详细的错误码而非简单的 0 返回值
测试代码及结果
// 从设备节点获取中断号
irq = of_irq_get(mydevice_node, 0);
printk("irq 3333 is %d\n", irq);
platform_get_irq
这个函数,上面也用过 ,这里不做详细解释,上面irq_get_trigger_type 函数 验证时候。
拓展-都是获取irq - irq_of_parse_and_map-of_irq_get-platform_get_irq 对比
函数 | 错误处理 | 推荐场景 | 内核版本 |
---|---|---|---|
irq_of_parse_and_map() | 返回0表示失败 | 旧代码兼容 | 早期版本 |
of_irq_get() | 详细错误码 | 新开发代码 ≥ 3.14 | |
platform_get_irq() | 封装更友好 | platform设备 | 通用 |
选择建议
-
首选platform_get_irq:
大多数平台设备驱动应该使用这个函数
提供最好的兼容性和最简单的接口 -
考虑of_irq_get的情况:
当需要处理非平台设备但使用设备树的情况
需要更精细控制中断获取过程 -
避免irq_of_parse_and_map:
除非有特殊需求且了解其局限性
新代码不建议使用
总结
- 这里还是通过设备树,了解设备树获取中断资源方案
- 进一步了解中断-设备树吧
- 基础知识务必掌握,后面才能熟练运用
- 核心方法platform_get_irq、irq_get_irq_data、gpio_to_irq