linux IRQ Management(六)- DTS及调试

  • 了解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 triggered
    2 = high-to-low edge triggered
    4 = active high level-sensitive
    8 = active low level-sensitive

Example:
    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_RISING
        2 = 下降沿 IRQ_TYPE_EDGE_FALLING
        4 = 高电平有效 IRQ_TYPE_LEVEL_HGIH
        8 = 低电平有效 IRQ_TYPE_LEVEL_LOW
    bits[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      eth0
  8:          0       s3c   8 Edge      s3c2410-rtc tick
 13:     567308       s3c  13 Edge      samsung_time_irq
 26:          0       s3c  26 Edge      ohci_hcd:usb1
 27:          4       s3c  27 Edge      54000000.i2c       //I2C
 30:          0       s3c  30 Edge      s3c2410-rtc alarm
 32:         53  s3c-level  32 Level     50000000.serial   //UART0 RXD
 33:        230  s3c-level  33 Level     50000000.serial   //UART0 TXD
 59:          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/

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值