Linux驱动开发基础

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

目录

1 设备树里中断节点的语法

1.1 设备树里的中断控制器

1.2 设备树里使用中断

2  设备树里中断节点的示例

3 在代码中获得中断

3.1 对于 platform_device 

3.2  对于 I2C 设备、SPI 设备

3.3  调用 of_irq_get 获得中断号

3.4 对于 GPIO 


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); 

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: linux

“Linux驱动开发基础” 的相关文章