1 修改设备树文件
因为按键KEY0采用中断的方式,所以要在按键的设备节点下添加引脚中断的相关属性,具体内容如下所示:
1 key {
2 #address-cells = <1>;
3 #size-cells = <1>;
4 compatible = "key";
5 pinctrl-names = "default";
6 pinctrl-0 = <&pinctrl_key>;
7 key-gpio = <&gpio1 18 GPIO_ACTIVE_LOW>; /* KEY0 */
8 interrupt-parent = <&gpio1>;
9 interrupts = <18 IRQ_TYPE_EDGE_BOTH>; /* FALLING RISING */
10 status = "okay";
11 };
第 8 行,设置 interrupt-parent 属性值为“gpio1”,因为 KEY0 所使用的 GPIO 为
GPIO1_IO18,也就是设置 KEY0 的 GPIO 中断控制器为 gpio1。
第 9 行,设置 interrupts 属性,也就是设置中断源,第一个 cells 的 18 表示 GPIO1 组的 18号 IO。IRQ_TYPE_EDGE_BOTH 表示上升沿和下降沿同时有效,相当于 KEY0 按下和释放都会触发中断。IRQ_TYPE_EDGE_BOTH 定义在文件 include/linux/irq.h 中,定义如下:
76 enum {
77 IRQ_TYPE_NONE = 0x00000000,
78 IRQ_TYPE_EDGE_RISING = 0x00000001,
79 IRQ_TYPE_EDGE_FALLING = 0x00000002,
80 IRQ_TYPE_EDGE_BOTH = (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING),
81 IRQ_TYPE_LEVEL_HIGH = 0x00000004,
82 IRQ_TYPE_LEVEL_LOW = 0x00000008,
83 IRQ_TYPE_LEVEL_MASK = (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH),
…
100 };
设备树编写完成以后使用“make dtbs”命令重新编译设备树,然后使用新编译出来的
topeet_emmc_4_3.dtb文件启动 Linux 系统。
2 按键中断驱动程序
本实验例程路径:i.MX6UL终结者光盘资料/06_Linux驱动例程/10_key_irq
创建key_irq.c文件,具体内容如下:
1 #include <linux/types.h>
2 #include <linux/kernel.h>
3 #include <linux/delay.h>
4 #include <linux/ide.h>
5 #include <linux/init.h>
6 #include <linux/module.h>
7 #include <linux/errno.h>
8 #include <linux/gpio.h>
9 #include <linux/cdev.h>
10 #include <linux/device.h>
11 #include <linux/of.h>
12 #include <linux/of_address.h>
13 #include <linux/of_gpio.h>
14 #include <linux/semaphore.h>
15 #include <linux/timer.h>
16 #include <linux/of_irq.h>
17 #include <linux/irq.h>
18 #include <asm/mach/map.h>
19 #include <asm/uaccess.h>
20 #include <asm/io.h>
21
22 #define IMX6UIRQ_CNT 1 /* 设备号个数 */
23 #define IMX6UIRQ_NAME "imx6uirq" /* 名字 */
24 #define KEY0VALUE 0X01 /* KEY0 按键值 */
25 #define INVAKEY 0XFF /* 无效的按键值 */
26 #define KEY_NUM 1 /* 按键数量 */
27
28 /* 中断 IO 描述结构体 */
29 struct irq_keydesc {
30 int gpio; /* gpio */
31 int irqnum; /* 中断号 */
32 unsigned char value; /* 按键对应的键值 */
33 char name[10]; /* 名字 */
34 irqreturn_t (*handler)(int, void *); /* 中断服务函数 */
35 };
36
37 /* imx6uirq 设备结构体 */
38 struct imx6uirq_dev{
39 dev_t devid; /* 设备号 */
40 struct cdev cdev; /* cdev */
41 struct class *class; /* 类 */
42 struct device *device; /* 设备 */
43 int major; /* 主设备号 */
44 int minor; /* 次设备号 */
45 struct device_node *nd; /* 设备节点 */
46 atomic_t keyvalue; /* 有效的按键键值 */
47 atomic_t releasekey; /* 标记是否完成一次完成的按键*/
48 struct timer_list timer; /* 定义一个定时器*/
49 struct irq_keydesc irqkeydesc[KEY_NUM]; /* 按键描述数组 */
50 unsigned char curkeynum; /* 当前的按键号 */
51 };