/ {
interrupt-parent = <&intc>;
intc: interrupt-controller {
compatible = "my_intc";
#interrupt-cells = <1>;
interrupt-controller;
reg = <0x80000000 0x1000>;
};
my_device: my-device {
compatible = "my_device";
reg = <0x81000000 0x1000>;
interrupts = <0 2>;
};
};
在这个示例中,根节点("/")有一个属性“interrupt-parent”,它指向了一个名为“intc”的中断控制器节点。该中断控制器节点被声明为一个中断控制器("interrupt-controller")并且具有一个"compatible"属性,用于匹配驱动程序。还定义了一个寄存器范围("reg"属性),表示该中断控制器的地址范围。
另外,还有一个名为“my_device”的设备节点,也有一个"compatible"属性,并指定了该设备的寄存器范围。此外,还有一个"interrupts"属性,它描述了与该设备相关的两个中断,第一个数值0表示中断的编号,第二个数值2表示中断的触发类型(即边沿或电平触发)。
通过这种方式,操作系统可以使用中断设备树中的信息来分配和管理系统中的中断资源,并确保各个设备之间的中断不会冲突。
在设备树中配置中断通常需要以下步骤:
-
在设备节点中添加
interrupt-parent
属性,指定中断控制器(IRQ controller)所在的设备节点。 -
在设备节点中添加
interrupts
属性,描述中断信息,包括中断编号、中断触发类型等。 -
在驱动程序中解析设备树中的
interrupt-parent
和interrupts
属性,并注册中断处理函数。
下面是一个简单的例程,用于演示如何在设备树中配置和使用中断。假设我们要为一个 GPIO 设备添加中断支持。设备树中对应的节点可以写成这样:
gpio {
compatible = "my_gpio_device";
gpio-number = <10>;
interrupts = <4 IRQ_TYPE_LEVEL_HIGH>;
interrupt-parent = <&gpio_controller>;
};
其中,compatible
属性指定设备的兼容性字符串,gpio-number
属性指定 GPIO 的编号,interrupts
属性描述中断信息,interrupt-parent
属性指定中断控制器所在的设备节点。
接下来,在设备驱动程序中解析中断信息,并注册中断处理函数:
#include <linux/interrupt.h>
#include <linux/of.h>
static int my_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
int irq;
// 获取 GPIO 编号和中断信息
u32 gpio_num;
const u32 *irqs;
int num_irqs;
if (of_property_read_u32(dev->of_node, "gpio-number", &gpio_num))
return -EINVAL;
num_irqs = of_irq_count(dev->of_node);
if (num_irqs < 1)
return -EINVAL;
irqs = devm_kzalloc(dev, sizeof(u32) * num_irqs, GFP_KERNEL);
if (!irqs)
return -ENOMEM;
if (of_irq_get(dev->of_node, 0, &irq))
return -EINVAL;
// 注册中断处理函数
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res)
return -EINVAL;
irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
if (devm_request_irq(dev, irq, my_gpio_irq_handler,
IRQF_TRIGGER_HIGH, dev_name(dev), pdev))
return -EINVAL;
// 其他初始化操作
// ...
return 0;
}
这个例程中,我们首先使用 of_property_read_u32()
和 of_irq_count()
函数从设备树节点中获取 GPIO 编号和中断信息。然后,我们使用 irq_set_irq_type()
函数设置中断触发类型为高电平,并使用 devm_request_irq()
函数注册中断处理函数。
最后,在 probe()
函数中完成其他初始化操作,就可以使设备支持中断了。需要注意的是,这只是一个简单的例程,实际情况下可能会更加复杂。
中断类型
// 常用的五个触发类型
enum {
IRQ_TYPE_NONE = 0x00000000,
IRQ_TYPE_EDGE_RISING = 0x00000001,
IRQ_TYPE_EDGE_FALLING = 0x00000002,
IRQ_TYPE_EDGE_BOTH = (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING),
IRQ_TYPE_LEVEL_HIGH = 0x00000004,
IRQ_TYPE_LEVEL_LOW = 0x00000008,
...
}