- 了解DTS Interrupt 设置方式。
1.DTS 中 interrupt 描述
-
interrupt-controller - 一个空的属性定义, 该节点作为一个接收中断信号的设备。
-
#interrupt-cells - 这是一个中断控制器节点的属性。它声明了该中断控制器的中断指示符中 cell 的个数(类似于 #address-cells 和 #size-cells)。
-
interrupt-parent - 这是一个设备节点的属性,包含一个指向该设备连接的中断控制器的 phandle。那些没有 interrupt-parent 的节点则从它们的父节点中继承该属性。
-
interrupts - 一个设备节点属性,包含一个中断指示符的列表,对应于该设备上的每个中断输出信号。
2.中断控制器interrupt-controller
一个中断控制器节点必须含有 interrupt-controller 属性,该属性是一个 bool 属性, 其值必须为空。也就是说,只要节点中含有 interrupt-controller 属性,那么这个节点 就是中断控制器。中断控制器节点必须含有 #interrupt-cells 属性,该属性定义节点中中断标识的 cell 数量。以下是三种 cell 中断表示的例子:
2.1.One cell
中断控制器中,#interrupt-cells 属性设置为 1,此时节点中的中断标识只含有一个 cell,该 cell 用于指明中断在中断控制器内的偏移。
Example:vic: interrupt@10140000 {compatible = "arm,versatile-vic";interrupt-controller; //此设备是一个中断控制器#interrupt-cells = <1>;reg = <0x10140000 0x1000>;};sic: intc@10003000 {compatible = "arm,versatile-sic";interrupt-controller; //此设备是一个中断控制器#interrupt-cells = <1>;reg = <0x10003000 0x1000>;interrupt-parent = <&vic>;interrupts = <31>; /* Cascaded to vic */};
本例中 vic,sic 都是中断控制器的节点,其中 vic 控制器定义了 cell 数为 1,那么 所有以它为父节点的节点,中断标识只含有一个 cell。如上 sic 也是一个中断控制器, 其以 vic 为父节点,所有 sic 的 interrupts 属性就只能含有一个 cell,sic 使用的 中断在 vic 中的偏移是 31。
2.2.Two Cell
中断控制器中,#interrupt-cell 属性设置为 2,此时节点中的中断标识含有两个 cell:
- 第一个 cell 用于指明在中断控制器内的偏移;
- 第二个 cell 用于指明触发方式和级别;
bits[3:0] 触发类型和级别标志:1 = low-to-high edge triggered2 = high-to-low edge triggered4 = active high level-sensitive8 = active low level-sensitiveExample:i2c@7000c000 {gpioext: gpio-adnp@41 {compatible = "ad,gpio-adnp";reg = <0x41>;intrrupt-parent = <&gpio>;interrupts = <160 1>;gpio-controller;#gpio-cells = <1>;interrupt-controller;#interrupt-cells = <2>;nr-gpios = <64>;};sx8634@2b {compatible = "smtc,sx8634";reg = <0x2b>;interrupt-parent = <&gpioext>;interrupts = <3 0x8>;#address-cells = <1>;#size-cells = <0>;threshold = <0x40>;sensitivity = <7>;};};
2.3.Three Cell
GIC中断控制器:
Example:gic: interrupt-controller@d000 {compatible = "arm,cortex-a9-gic";interrupt-controller;#interrupt-cells = <3>;#size-cells = <0>;reg = <0xd000 0x1000>, <0xc100 0x1000>;};
#interrupt-cells 属性由于指明中断源中 cell 的数量,GIC 中 interrupt-cells 的值为 3。每个 cell 的含义如下:
- 第一个 cell 代表中断类型。
- GIC_SPI:0;
- GIC_PPI:1 ;
- 第二个 cell 代表不同类型中断的中断号。
- SPI 中断号的范围从 0 到 987;
- PPI 中断号 从 0 到 15。
- 第三个 cell 代表中断标识。
各标识含义如下:
bits[3:0] 代表触发类型1 = 上升沿 IRQ_TYPE_EDGE_RISING2 = 下降沿 IRQ_TYPE_EDGE_FALLING4 = 高电平有效 IRQ_TYPE_LEVEL_HGIH8 = 低电平有效 IRQ_TYPE_LEVEL_LOWbits[15:8] PPI 中断 CPU 掩码
3.操作interrupt APIs
include/linux/of_irq.h:45 extern int of_irq_count(struct device_node *dev);46 extern int of_irq_get(struct device_node *dev, int index); 47 extern int of_irq_get_byname(struct device_node *dev, const char *name);48 extern int of_irq_to_resource_table(struct device_node *dev,49 struct resource *res, int nr_irqs);50 extern struct device_node *of_irq_find_parent(struct device_node *child);51 extern struct irq_domain *of_msi_get_domain(struct device *dev,52 struct device_node *np,53 enum irq_domain_bus_token token);54 extern struct irq_domain *of_msi_map_get_device_domain(struct device *dev,55 u32 rid);56 extern void of_msi_configure(struct device *dev, struct device_node *np);57 u32 of_msi_map_rid(struct device *dev, struct device_node *msi_np, u32 rid_in);
4.中断调试方法
- /sys/kernel/debug/irq
- /sys/kernel/debugirq_domain_mapping
4.1.查看系统信息
开机后,从/proc/interrupts中看到当前的中断资源申请信息:
[root@tq2440 ]# cat /proc/interrupts CPU0 7: 926 s3c-eint 7 Edge eth08: 0 s3c 8 Edge s3c2410-rtc tick13: 567308 s3c 13 Edge samsung_time_irq26: 0 s3c 26 Edge ohci_hcd:usb127: 4 s3c 27 Edge 54000000.i2c //I2C30: 0 s3c 30 Edge s3c2410-rtc alarm32: 53 s3c-level 32 Level 50000000.serial //UART0 RXD33: 230 s3c-level 33 Level 50000000.serial //UART0 TXD59: 0 s3c-level 59 Edge 53000000.watchdog
上面这些参数的含义:
相关代码:
- kernel/irq/debugfs.c
- kernel/irq/irqdomain.c
- kernel/fs/proc.c
- fs/proc/interrupts.c
查看具体irq:
- cat /proc/irq/27
5.案例
5.1.内核中断
/*
* Interrupt on DTS
*
* (C) 2018.11.14 <buddy.zhang@aliyun.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*//*
* demo: demo2@2 {
* compatible = "demo,demo_intr";
* reg = <2>;
* interrupt-parent = <&gpio0>;
* interrupts = <11 2>;
* status = "okay";
* };
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/interrupt.h>#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>/* define name for device and driver */
#define DEV_NAME "demo_intr"
static int irq;static irqreturn_t demo_irq_handler(int irq, void *dev_id)
{printk("Hello World\n");return IRQ_HANDLED;
}/* probe platform driver */
static int demo_probe(struct platform_device *pdev)
{struct device_node *np = pdev->dev.of_node;int ret;/* Obtain interrupt ID from DTS */irq = of_irq_get(np, 0);/* Request irq handler */ret = request_threaded_irq(irq, NULL, demo_irq_handler,IRQF_ONESHOT | IRQF_TRIGGER_FALLING, "demo", NULL);if (ret) {printk("Failed to acquire irq %d\n", irq);return -EINVAL;}return 0;
}/* remove platform driver */
static int demo_remove(struct platform_device *pdev)
{/* Release Interrupt */free_irq(irq, NULL);return 0;
}static const struct of_device_id demo_of_match[] = {{ .compatible = "demo,demo_intr", },{ },
};
MODULE_DEVICE_TABLE(of, demo_of_match);/* platform driver information */
static struct platform_driver demo_driver = {.probe = demo_probe,.remove = demo_remove,.driver = {.owner = THIS_MODULE,.name = DEV_NAME, .of_match_table = demo_of_match,},
};module_platform_driver(demo_driver);
5.2.gpio中断案例
arch/arm/boot/dts/imx6q-novena.dts:
268 touch: stmpe811@44 {
269 compatible = "st,stmpe811";
270 reg = <0x44>;
271 irq-gpio = <&gpio5 13 GPIO_ACTIVE_HIGH>;
drivers/mfd/stmpe.c: 1292 pdata->irq_gpio = of_get_named_gpio_flags(np, "irq-gpio", 0,1293 &pdata->irq_trigger);1371 ret = devm_gpio_request_one(ci->dev, pdata->irq_gpio, GPIOF_DIR_IN, "stmpe");1378 stmpe->irq = gpio_to_irq(pdata->irq_gpio);1404 if (stmpe->irq >= 0) {1405 ret = stmpe_irq_init(stmpe, np);1408 1409 ret = devm_request_threaded_irq(ci->dev, stmpe->irq, NULL,1410 stmpe_irq, pdata->irq_trigger | IRQF_ONESHOT,1411 "stmpe", stmpe);1417 }
参考:
https://biscuitos.github.io/blog/DTS-interrupt/
















