Linux驱动开发基础
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
目录
1 设备树里中断节点的语法
参考文档内核 Documentation\devicetree\bindings\interrupt-controller\interrupts.txt
1.1 设备树里的中断控制器
中断的硬件框图如下
在硬件上“中断控制器”只有 GIC 这一个但是我们在软件上也可以把上图中的“GPIO”称为“中断控制器”。很多芯片有多个 GPIO 模块比如 GPIO1、GPIO2 等等。所以软件上的“中断控制器”就有很多个GIC、GPIO1、GPIO2 等等。
GPIO1 连接到 GICGPIO2 连接到 GIC所以 GPIO1 的父亲是 GICGPIO2的父亲是 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 设备树里中断节点的示例
从设备树反推 IMX6ULL 的中断体系如下比之前的框图多了一个“GPC INTC”
GPC INTC 的 英 文 是 General Power Controller, Interrupt Controller。它提供中断屏蔽、中断状态查询功能实际上这些功能在 GIC 里也实现了个人觉得有点多余。除此之外它还提供唤醒功能这才是保留它的原因。
3 在代码中获得中断
之 前 我 们 提 到 过 设 备 树 中 的 节 点 有 些 能 被 转 换 为 内 核 里 的platform_device有些不能回顾如下
- 根节点下含有 compatile 属性的子节点会转换为 platform_device
- 含有特定 compatile 属性的节点的子节点会转换为 platform_device 如果一个节点的 compatile 属性它的值是这 4 者之一"simple-bus","simple-mfd","isa","arm,amba-bus", 那么它的子结点(需含 compatile 属性)也可以转换为 platform_device。
- 总线 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/i2c-core.c)
对于 SPI 设备节点SPI 总线驱动在处理设备树里的 SPI 子节点时也会处理其中的中断信息。一个 SPI 设备会被转换为一个 spi_device 结构体中断号会保存在 spi_device 的 irq 成员里代码如下(drivers/spi/spi.c)
3.3 调用 of_irq_get 获得中断号
如果你的设备节点既不能转换为 platform_device它也不是 I2C 设备不是 SPI 设备那么在驱动程序中可以自行调用 of_irq_get 函数去解析设备树得到中断号。
3.4 对于 GPIO
可以使用 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);