【Linux】编写一个Linux按键中断Demo

文章目录

1. 前言

在内核里面实现了按键驱动,drivers/input/keyboard/gpio_keys.c,我们可以参考它来学着写一个按键中断程序。

2. 硬件介绍

通过下面的硬件我们可以知道按键检测GPIO默认是高电平,如果按键被按下就变成低电平。所以,我们可以配置GPIO为中断模式,检测KEY是否被按下。
【Linux】编写一个Linux按键中断Demo

3. 编写按键驱动程序

  • 在设备树中添加按键使用的引脚,如下:
    imx_gpio_keys {
    	compatible = "imx,gpio_key";
    	gpios = <&gpio5 1 GPIO_ACTIVE_HIGH
    			 &gpio4 14 GPIO_ACTIVE_HIGH>;
    	
    	pinctrl-names = "default";
    	pinctrl-0 = <&pinctrl_gpio_key1
    				 &pinctrl_gpio_key2>;
    };
    
  • 在probe函数中从设备树获取GPIO,并且从GPIO中获得中断号
    count = of_gpio_count(node);
    if(!count){
    	printk("[%s:%d] There isn't gpio available!\n", __FUNCTION__, __LINE__);
    	return -1;
    }
    
    pGpioKeyCfg = kzalloc(count * sizeof(struct gpio_key_cfg), GFP_KERNEL);
    
    for(i = 0; i < count; i++)
    {
    	pGpioKeyCfg[i].gpio_num = of_get_gpio_flags(node, i, &flag);
    	if(pGpioKeyCfg[i].gpio_num < 0){
    		printk("[%s:%d] of_get_gpio_flags is fail!!!\n", __FUNCTION__, __LINE__);
    		return -1;
    	}
    
    	pGpioKeyCfg[i].gpio_flag = flag & OF_GPIO_ACTIVE_LOW; // 获取GPIO的flag
    	pGpioKeyCfg[i].gpiod = gpio_to_desc(pGpioKeyCfg[i].gpio_num); // 获取GPIO的描述符
    	pGpioKeyCfg[i].gpio_irq = gpio_to_irq(pGpioKeyCfg[i].gpio_num); // 获取GPIO的中断号
    }
    
  • 申请中断和编写中断函数
    for(i = 0; i < count; i++)
    {
    	request_irq(pGpioKeyCfg[i].gpio_irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "gpio_key", &pGpioKeyCfg[i]);
    }
    
    static irqreturn_t gpio_key_isr(int irq, void *dev_id)
    {
    	int val;
    	struct gpio_key_cfg *pGpioKey = dev_id;
    
    	val = gpiod_get_value(pGpioKey->gpiod);
    
    	printk("key %d %d\n", pGpioKey->gpio_num, val);
    
    	return IRQ_HANDLED;
    }
    

4. 配置设备树

IMX平台可以通过“i.MX Pins Tool v6”配置gpio,一般一个引脚作为中断时,要通过 PinCtrl 把它设置为 GPIO 功能。配置效果如下:
【Linux】编写一个Linux按键中断Demo
工具生成的代码,对应修改dtsi如下:

diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi b/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi
index 6b70f287e..52c5bd0ee 100644
--- a/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi
+++ b/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi
@@ -326,7 +326,7 @@
 &qspi {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_qspi>;
-	status = "okay";
+	status = "disabled";
 
 	flash0: n25q256a@0 {
 		#address-cells = <1>;
@@ -748,4 +748,10 @@
 			MX6UL_PAD_LCD_RESET__WDOG1_WDOG_ANY    0x30b0
 		>;
 	};
+	
+	pinctrl_gpio_key2: gpio_key2 {
+		fsl,pins = <
+			MX6UL_PAD_NAND_CE1_B__GPIO4_IO14       0x000010B0
+		>;
+	};
 };
diff --git a/arch/arm/boot/dts/imx6ull-14x14-evk.dts b/arch/arm/boot/dts/imx6ull-14x14-evk.dts
index bb8f91034..44818b470 100644
--- a/arch/arm/boot/dts/imx6ull-14x14-evk.dts
+++ b/arch/arm/boot/dts/imx6ull-14x14-evk.dts
@@ -10,8 +10,27 @@
 / {
 	model = "Freescale i.MX6 ULL 14x14 EVK Board";
 	compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";
+	
+	imx_gpio_keys {
+		compatible = "imx,gpio_key";
+		gpios = <&gpio5 1 GPIO_ACTIVE_HIGH
+				 &gpio4 14 GPIO_ACTIVE_HIGH>;
+		
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_key1
+					 &pinctrl_gpio_key2>;
+	};
 };
 
+&iomuxc_snvs {
+	pinctrl_gpio_key1: gpio_key1 {
+		fsl,pins = <
+			MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01        0x000110A0
+		>;
+	};
+};
+
+
 &clks {
 	assigned-clocks = <&clks IMX6UL_CLK_PLL3_PFD2>,
 			  <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;

5. 烧录验证

编译烧录验证如下:
【Linux】编写一个Linux按键中断Demo

6. 工程代码下载地址

完整的实验工程Demo代码下载地址如下:
正在上传中…

上一篇:of_node_put【转】


下一篇:常用名词