驱动设备数-of函数-获取中断资源

提示: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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

野火少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值