来源:百问网
作者:韦东山
本文字数:3436,阅读时长:5分钟
1.设备树里中断节点的语法
1.1 设备树里的中断控制器
中断的硬件框图如下:
在硬件上,“中断控制器”只有GIC这一个,但是我们在软件上也可以把上图中的“GPIO”称为“中断控制器”。很多芯片有多个GPIO模块,比如GPIO1、GPIO2等等。所以软件上的“中断控制器”就有很多个:GIC、GPIO1、GPIO2等等。
GPIO1连接到GIC,GPIO2连接到GIC,所以GPIO1的父亲是GIC,GPIO2的父亲是GIC。
假设GPIO1有32个中断源,但是它把其中的16个汇聚起来向GIC发出一个中断,把另外16个汇聚起来向GIC发出另一个中断。这就意味着GPIO1会用到GIC的两个中断,会涉及GIC里的2个hwirq。
这些层级关系、中断号(hwirq),都会在设备树中有所体现。
在设备树中,中断控制器节点中必须有一个属性:interrupt-controller,表明它是“中断控制器”。
还必须有一个属性:#interrupt-cells,表明引用这个中断控制器的话需要多少个cell。
#interrupt-cells的值一般有如下取值:
① #interrupt-cells=<1>
别的节点要使用这个中断控制器时,只需要一个cell来表明使用“哪一个中断”。
② #interrupt-cells=<2>
别的节点要使用这个中断控制器时,需要一个cell来表明使用“哪一个中断”;
还需要另一个cell来描述中断,一般是表明触发类型:
第2个cell的bits[3:0] 用来表示中断触发类型(trigger type and level flags):
1 = low-to-high edge triggered,上升沿触发
2 = high-to-low edge triggered,下降沿触发
4 = active high level-sensitive,高电平触发
8 = active low level-sensitive,低电平触发
示例如下:
vic: intc@10140000 { compatible = "arm,versatile-vic"; interrupt-controller; #interrupt-cells = <1>; reg = <0x10140000 0x1000>; };
如果中断控制器有级联关系,下级的中断控制器还需要表明它的“interrupt-parent”是谁,用了interrupt-parent”中的哪一个“interrupts”,请看下一小节。
1.2 设备树里使用中断
一个外设,它的中断信号接到哪个“中断控制器”的哪个“中断引脚”,这个中断的触发方式是怎样的?
这3个问题,在设备树里使用中断时,都要有所体现。
① interrupt-parent=<&XXXX>
你要用哪一个中断控制器里的中断?
② interrupts
你要用哪一个中断?
Interrupts里要用几个cell,由interrupt-parent对应的中断控制器决定。在中断控制器里有“#interrupt-cells”属性,它指明了要用几个cell来描述中断。
比如:
i2c@7000c000 { gpioext: gpio-adnp@41 { compatible = "ad,gpio-adnp"; interrupt-parent = <&gpio>; interrupts = <160 1>; gpio-controller; #gpio-cells = <1>; interrupt-controller; #interrupt-cells = <2>; }; ...... };
③ 新写法:interrupts-extended
一个“interrupts-extended”属性就可以既指定“interrupt-parent”,也指定“interrupts”,比如:
interrupts-extended = <&intc1 5 1>, <&intc2 1 0>;
2.设备树里中断节点的示例
以100ASK_IMX6ULL开发板为例,在arch/arm/boot/dts目录下可以看到2个文件:imx6ull.dtsi、100a,把里面有关中断的部分内容抽取出来。
从设备树反推IMX6ULL的中断体系,如下,比之前的框图多了一个“GPC INTC”:
GPC INTC的英文是:General Power Controller, Interrupt Controller。它提供中断屏蔽、中断状态查询功能,实际上这些功能在GIC里也实现了,个人觉得有点多余。除此之外,它还提供唤醒功能,这才是保留它的原因。
3.在代码中获得中断
之前我们提到过,设备树中的节点有些能被转换为内核里的platform_device,有些不能,回顾如下:
A. 根节点下含有compatile属性的子节点,会转换为platform_device
B. 含有特定compatile属性的节点的子节点,会转换为platform_device
如果一个节点的compatile属性,它的值是这4者之一:“simple-bus”,“simple-mfd”,“isa”,“arm,amba-bus”,
那么它的子结点(需含compatile属性)也可以转换为platform_device。
C. 总线I2C、SPI节点下的子节点:不转换为platform_device
某个总线下到子节点,应该交给对应的总线驱动程序来处理, 它们不应该被转换为platform_device。
3.1 对于platform_device
一个节点能被转换为platform_device,如果它的设备树里指定了中断属性,那么可以从platform_device中获得“中断资源”,函数如下,可以使用下列函数获得IORESOURCE_IRQ资源,即中断号:
/** * platform_get_resource - get a resource for a device * @dev: platform device * @type: resource type // 取哪类资源?IORESOURCE_MEM、IORESOURCE_REG * // IORESOURCE_IRQ等 * @num: resource index // 这类资源中的哪一个? */ struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num);
3.2 对于I2C设备、SPI设备
对于I2C设备节点,I2C总线驱动在处理设备树里的I2C子节点时,也会处理其中的中断信息。一个I2C设备会被转换为一个i2c_client结构体,中断号会保存在i2c_client的irq成员里,代码如下(drivers/i2c):
对于SPI设备节点,SPI总线驱动在处理设备树里的SPI子节点时,也会处理其中的中断信息。一个SPI设备会被转换为一个spi_device结构体,中断号会保存在spi_device的irq成员里,代码如下(drivers/spi):
3.3. 调用of_irq_get获得中断号
如果你的设备节点既不能转换为platform_device,它也不是I2C设备,不是SPI设备,那么在驱动程序中可以自行调用of_irq_get函数去解析设备树,得到中断号。
3.4. 对于GPIO
参考:
drivers/input/keyboard
可以使用gpio_to_irq或gpiod_to_irq获得中断号。
举例,假设在设备树中有如下节点:
gpio-keys { compatible = "gpio-keys"; pinctrl-names = "default"; user { label = "User Button"; gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>; gpio-key,wakeup; linux,code = <KEY_1>; }; };
那么可以使用下面的函数获得引脚和flag:
button->gpio = of_get_gpio_flags(pp, 0, &flags); bdata->gpiod = gpio_to_desc(button->gpio);
再去使用gpiod_to_irq获得中断号:
irq = gpiod_to_irq(bdata->gpiod);
点击“了解更多”阅读更多相关章节
1.《(软件中断如何触发)外部中断如何触发》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。
2.《(软件中断如何触发)外部中断如何触发》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/keji/3270958.html