写在前面的话:对于 GPIO 按键,我们并不需要去写驱动程序,使用内核自带的驱动程序 drivers/input/keyboard/gpio_keys.c 就可以,然后你需要做的只是修改设备树指定引脚及键值。
根据驱动文件中的platform_driver中的.of_match_table的compatible属性名去找对应在dts文件中的节点做修改。
查看原理图确定按键引脚
修改设备树文件
查看原理图确定按键使用的引脚,再在设备树中添加节点,在节点里指定中断信息
例子:
gpio_keys_100ask {
compatible = "100ask,gpio_key";
gpios = <&gpio5 1 GPIO_ACTIVE_HIGH
&gpio4 14 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&key1_pinctrl
&key2_pinctrl>;
};
在硬件上,“中断控制器”只有 GIC 这一个,但是我们在软件上也可以把下图中的“GPIO ”称为“中断控制器”。很多芯片有多个 GPIO 模块,比如 GPIO1 、 GPIO2 等等。所以软件上的“中断控制器”就有很多个: GIC 、 GPIO1 、 GPIO2 等 等。
一个外设,它的中断信号接到哪个“中断控制器”的哪个“中断引脚”,这个中断的触发方式是怎样的? 这 3 个问题,在设备树里使用中断时,都要有所体现。
⚫ interrupt-parent=<&XXXX>
你要用哪一个中断控制器里的中断?
⚫ interrupts
你要用哪一个中断?
Interrupts 里要用几个 cell ,由 interrupt-parent 对应的中断控制器决定。在中断控制器里有“#interrupt-cells ”属性,它指明了要用几个 cell来描述中断。
比如:下图为dtsi文件中的 gpio 5 定义,也表明了此io既是gpio控制器也是中断控制器,它的parent是GIC gpio5: gpio@020ac000 {compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";reg = <0x020ac000 0x4000>;interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,<GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;gpio-controller;#gpio-cells = <2>;interrupt-controller;#interrupt-cells = <2>;
对于一个引脚要用作中断时:
a) 要通过 PinCtrl 把它设置为 GPIO 功能;
b) 表明自身:是哪一个 GPIO 模块里的哪一个引脚
写驱动程序
⚫ 首先要获得中断号
在Linux中,如果要使用gpio_to_irq函数获取GPIO引脚对应的中断号,通常是在驱动程序中进行的,而不是在设备树中。设备树通常只描述硬件连接和属性,而不涉及中断处理。因此,为了获取GPIO引脚对应的中断号,需要在相应的驱动程序中进行。
例如,在使用了这些GPIO键的驱动程序中,可以使用gpio_to_irq
函数来获取GPIO引脚对应的中断号。
⚫ 然后编写中断处理函数;
⚫ 最后 request_irq
具体来说,request_irq
函数做了以下几件事情:
-
注册中断处理函数:将你提供的中断处理函数注册到内核中,以便在中断发生时调用该函数执行中断处理操作。
-
请求分配中断号:告诉内核你需要一个中断号来处理中断。内核会分配一个可用的中断号给你的设备,并将中断处理函数与这个中断号关联起来。
-
配置中断属性:你可以指定中断的一些属性,例如中断类型(边沿触发、电平触发等)、中断处理函数的上下文(共享中断或独占中断)、中断处理函数的参数等。
-
关联中断上下文:如果你的设备需要访问中断处理函数之外的其他数据,你可以将这些数据通过中断处理函数的上下文参数传递给中断处理函数。
在代码中获取中断:
1、对于 platform_device
一个节点能被转换为 platform_device ,如果它的设备树里指定了中断属 性,那么可以从 platform_device 中获得“中断资源”,函数如下,可以使用下 列函数获得 ORESOURCE_IRQ 资源,即中断号:
2、 对于 I2C 设备、 SPI 设备
对于 I2C 设备节点, I2C 总线驱动在处理设备树里的 I2C 子节点时,也会处 理其中的中断信息。一个 I2C 设备会被转换为一个 i2c_client 结构体,中断号会保存在 i2c_client 的 irq 成员里
对于 SPI 设备节点, SPI 总线驱动在处理设备树里的 SPI 子节点时,也会处理其中的中断信息。一个 SPI 设备会被转换为一个 spi_device 结构体,中断号会保存在 spi_device 的 irq 成员里
i2c代码如下:
3、调用 of_irq_get 获得中断号
如果你的设备节点既不能转换为 platform_device ,它也不是 I2C 设备, 不是 SPI 设备,那么在驱动程序中可以自行调用 of_irq_get 函数去解析设备树,得到中断号。
对于 GPIO 参考:drivers/input/keyboard/gpio_keys.c 可以使用 gpio_to_irq 或 gpiod_to_irq 获得中断号。
irq = gpiod_to_irq(bdata->gpiod);
把修改后的dts文件编译得到新的dtb文件,拷贝到板子的boot目录下;
先进入驱动程序目录,执行 make 即可,把编译后的驱动程序ko文件拷贝到板子网络文件系统文件夹下;
重启开发板;
进入根目录insmod装载ko文件;
测试;
总结:
对于此例按键驱动,用gpio接收按键中断信号,要做的就是
1)注意设备树中的Pinctrl设置好按键对应引脚的gpio功能,dtsi文件中写明了该gpio节点也是中断控制器
2)在驱动程序中获得中断号;申请中断(注册一个中断处理函数,并分配一个中断号来处理该中断);写明中断处理函数。