裸机使用中断需要通过寄存器手动配置,但有了 Linux 系统后,Linux内核提供了完善的中断框架,我们只需要申请中断,然后注册中断服务函数即可。
一、设备树中断属性
既然驱动中要注册中断服务函数,我们首先需要知道三个点:
- 中断类型: GIC 目前存在的中断请求有128种,每一种对应一个中断控制器
- 中断引脚: 指定具体是哪一个引脚会触发
- 触发方式: 上升沿触发、下降沿触发、高电平触发、低电平触发
设备树中涉及到中断的属性主要有四个
1、指定中断类型
在设备树中每一种中断请求表现为一个节点,且包含属性 interrupt-controller。涉及到的属性还有 #interrupt-cells,指定引用节点中 interrupts 属性中包含的信息个数(注意不是当前节点的interrupts属性)
当某个外设节点要引入中断时,需要通过 interrupt-parent 属性描述自己属于哪一种类型的中断,比如下面的 sii902x 节点的中断类型属于 gpio1。gpio1节点的 interrupts 属性已经包含了中断号等内容,后续与 gpio1 相关的子节点直接引用即可。
2、指定中断引脚、触发方式
中断的触发需要借助引脚的高低电平实现,所以当某个外设节点引入中断后,需要指定是哪个引脚会触发中断,使用的设备树属性为 interrupts,该属性包含两个信息(中断引脚、触发方式)
格式如下:
interrupts = <引脚编号 触发方式>,···<引脚编号 触发方式>;
引脚编号:引脚编号可以直接使用数字,如果是 gpio1_IO10,这里可以填 10
触发方式:Linux内核提供了宏定义来表示触发方式(irq.h)
#define IRQ_TYPE_NONE 0 /* 无触发 */
#define IRQ_TYPE_EDGE_RISING 1 /* 上升沿触发 */
#define IRQ_TYPE_EDGE_FALLING 2 /* 下降沿触发 */
#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING) /* 双边沿触发 */
#define IRQ_TYPE_LEVEL_HIGH 4 /* 高电平触发 */
#define IRQ_TYPE_LEVEL_LOW 8 /* 低电平触发 */
二、设备树中断节点
还是以LED为例,我们在之前的 LED 节点中引入中断,LED 使用的引脚为 GPIO1_IO03,所属中断类型为gpio1,引脚编号为 3,触发类型为上升沿触发。在应用层每隔1s切换一次 LED 的状态,以此来测试是否进入中断。
创建的设备树节点如下:
gpio-led {pinctrl-names = "default";pinctrl-0 = <&pinctrl_gpio_leds>;led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;interrupt-parent = <&gpio1>; // 中断类型为gpio1interrupts = <3 IRQ_TYPE_EDGE_RISING>; // 中断引脚为GPIO1_IO03,触发方式为上升沿status = "okay";
};