24_设备树获取按键信息

在设备树中建立button节点,编写简单驱动进行测试

Posted by Jerry Chen on August 18, 2019

获取GPIO编号的方式

获取编号-设置为输入方式

方法:获取GPIO编号,设置该GPIO为输入模式。

建立BUTTON节点

目标设备树文件:linux-4.14.2_iTop-4412_scp/arch/arm/boot/dts/exynos4412-itop-elite.dts

首先屏蔽文件中存在”&gpx1 1”的键值对。

然后在根节点/{…}内新增如下子节点,注意status属性为”okay”

1
2
3
4
5
itop_gpio_in {
    compatible = "gpio_in";
    status = "okay";
    gpioin = <&gpx1 1 0>;
};

上面的信息指GPX1[1]初始低电平。

重新编译设备树烧录到开发板。

编写驱动文件

button_demo_drv.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("jerry");

#define DRV_NAME "gpio_in"

static int gpio_pin = 0;

static int demo_probe(struct platform_device *pdv){
	struct device_node *node = pdv->dev.of_node;
	int ret,value;
	
	printk("button probe ok!\n");
	
	gpio_pin = of_get_named_gpio(node, "gpioin", 0);
	if (gpio_pin < 0)
        printk("gpio_pin is not available \n");
	
	ret = gpio_request(gpio_pin, "gpio-in");
	if(ret!=0){
		printk("gpio_pin request %d faigpio.", gpio_pin);
		return ret;
	}
	printk("gpio_pin is %d\n",gpio_pin);
	gpio_free(gpio_pin);
	
	gpio_direction_input(gpio_pin);
	value = gpio_get_value(gpio_pin);
	printk("the value is %d\n",value);
	
	return 0;
}

static int demo_remove(struct platform_device *pdv){
	printk(KERN_EMERG "%s ok!\n",__FUNCTION__);
	return 0;
}

static const struct of_device_id of_demo_dt_match[] = {
	{.compatible = DRV_NAME},
	{},
};

MODULE_DEVICE_TABLE(of,of_demo_dt_match);

static struct platform_driver platform_drv_demo = {
	.driver	= {
		.name	= DRV_NAME,
		.owner	= THIS_MODULE,
		.of_match_table = of_demo_dt_match,
	},
	.probe	= demo_probe,
	.remove	= demo_remove,
};

static int __init demo_init(void){
	printk(KERN_EMERG "%s ok!\n",__FUNCTION__);
	platform_driver_register(&platform_drv_demo);
	return 0;
}
static void __exit demo_exit(void){
	printk(KERN_EMERG "%s ok!\n",__FUNCTION__);
	platform_driver_unregister(&platform_drv_demo);
	return;
}

module_init(demo_init);
module_exit(demo_exit);

Makefile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash

export ARCH=arm

obj-m += button_demo_drv.o

KDIR := /home/jerry/Projects/itop4412_kernel_4_14_2_bsp/linux-4.14.2_iTop-4412_scp/

PWD ?= $(shell pwd)

all:
	make -C $(KDIR) M=$(PWD) modules

clean:
	rm -rf *.o

交叉编译然后加载到内核后发现probe可以正常执行,打印当前按键的键值。

此外还可以用pinctrl直接设置输入模式,获取节点属性进行设置。

获取编号-设置为中断方式

方法:获取GPIO编号,转irq编号,根据irq编号申请中断。

建立BUTTON节点

目标设备树文件:linux-4.14.2_iTop-4412_scp/arch/arm/boot/dts/exynos4412-itop-elite.dts

首先屏蔽文件中存在”&gpx1 1”的键值对。

然后在根节点/{…}内新增如下子节点,注意status属性为”okay”

1
2
3
4
5
itop_inter {
    compatible = "itop4412,inter_pin";
    status = "okay";
    inter_gpio = <&gpx1 1 0>;
};

上面的信息指GPX1[1]初始低电平。

重新编译设备树烧录到开发板。

编写驱动文件

button_demo_drv.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/irq.h>
#include <linux/interrupt.h>

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("jerry");

#define DRV_NAME "itop4412,inter_pin"

static int inter_pin = 0;
static int irq = 0;

static irqreturn_t eint_interrupt(int irq, void *dev_id) {

	printk("%s(%d)\n", __FUNCTION__, __LINE__);
	printk("HOME KEY HIGH TO LOW!\n");

	return IRQ_HANDLED;
}

static int demo_probe(struct platform_device *pdv){
	struct device_node *node = pdv->dev.of_node;
	int ret;
	
	printk("button probe ok!\n");
	
	inter_pin = of_get_named_gpio(node, "inter_gpio", 0);
	if (inter_pin < 0)
        printk("inter_pin is not available \n");
	
	ret = gpio_request(inter_pin, "home-key-inter");
	if (ret) {
		printk("%s: request GPIO %d failed, ret = %d\n", DRV_NAME,inter_pin, ret);
		return ret;
	}
	gpio_direction_input(inter_pin);
	gpio_free(inter_pin);
	
	irq = gpio_to_irq(inter_pin);
	ret = request_irq(irq, eint_interrupt,IRQ_TYPE_EDGE_FALLING, "home-key-inter", pdv);
	if (ret < 0) {
		printk("Request IRQ %d failed, %d\n", irq,ret);
		return -1;
	}
	
	return 0;
}

static int demo_remove(struct platform_device *pdv){
	free_irq(irq,pdv); /*释放中断资源*/
	printk(KERN_EMERG "%s ok!\n",__FUNCTION__);
	return 0;
}

static const struct of_device_id of_demo_dt_match[] = {
	{.compatible = DRV_NAME},
	{},
};

MODULE_DEVICE_TABLE(of,of_demo_dt_match);

static struct platform_driver platform_drv_demo = {
	.driver	= {
		.name	= DRV_NAME,
		.owner	= THIS_MODULE,
		.of_match_table = of_demo_dt_match,
	},
	.probe	= demo_probe,
	.remove	= demo_remove,
};

static int __init demo_init(void){
	printk(KERN_EMERG "%s ok!\n",__FUNCTION__);
	platform_driver_register(&platform_drv_demo);
	return 0;
}
static void __exit demo_exit(void){
	printk(KERN_EMERG "%s ok!\n",__FUNCTION__);
	platform_driver_unregister(&platform_drv_demo);
	return;
}

module_init(demo_init);
module_exit(demo_exit);

Makefile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash

export ARCH=arm

obj-m += button_demo_drv.o

KDIR := /home/jerry/Projects/itop4412_kernel_4_14_2_bsp/linux-4.14.2_iTop-4412_scp/

PWD ?= $(shell pwd)

all:
	make -C $(KDIR) M=$(PWD) modules

clean:
	rm -rf *.o

交叉编译然后加载到内核后发现probe可以正常执行,每次按下home键产生一个中断。

设备树中断属性获取中断号方式

方法:获取irq编号,根据irq编号申请中断(这里就不申请了)。

设备树文件修改

目标设备树文件:linux-4.14.2_iTop-4412_scp/arch/arm/boot/dts/exynos4412-itop-elite.dts

首先屏蔽文件中存在”&gpx1 1”、”&gpx1 2”的键值对。

然后在根节点/{…}内新增如下子节点,注意status属性为”okay”

1
2
3
4
5
6
itop-4412-gpio-keys {
    compatible = "itop-4412,gpio-keys";
    status = "okay";
    interrupt-parent = <&gpx1>;
    interrupts = <1 0>, <2 0>;
};

上面的信息指GPX1[1]、GPX1[2]设为中断。

重新编译设备树烧录到开发板。

编写驱动文件

button_demo_drv.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_irq.h>

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("jerry");

#define DRV_NAME "itop-4412,gpio-keys"

static int demo_probe(struct platform_device *pdv){
	struct device_node *node = pdv->dev.of_node;
	int irq[2];
	
	printk("button probe ok!\n");
	
	irq[0] = irq_of_parse_and_map(node,0);
	printk("irq number is %d\n",irq[0]);
	
	irq[1] = irq_of_parse_and_map(node,1);
	printk("irq number is %d\n",irq[1]);
	
	return 0;
}

static int demo_remove(struct platform_device *pdv){
	printk(KERN_EMERG "%s ok!\n",__FUNCTION__);
	return 0;
}

static const struct of_device_id of_demo_dt_match[] = {
	{.compatible = DRV_NAME},
	{},
};

MODULE_DEVICE_TABLE(of,of_demo_dt_match);

static struct platform_driver platform_drv_demo = {
	.driver	= {
		.name	= DRV_NAME,
		.owner	= THIS_MODULE,
		.of_match_table = of_demo_dt_match,
	},
	.probe	= demo_probe,
	.remove	= demo_remove,
};

static int __init demo_init(void){
	printk(KERN_EMERG "%s ok!\n",__FUNCTION__);
	platform_driver_register(&platform_drv_demo);
	return 0;
}
static void __exit demo_exit(void){
	printk(KERN_EMERG "%s ok!\n",__FUNCTION__);
	platform_driver_unregister(&platform_drv_demo);
	return;
}

module_init(demo_init);
module_exit(demo_exit);

Makefile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash

export ARCH=arm

obj-m += button_demo_drv.o

KDIR := /home/jerry/Projects/itop4412_kernel_4_14_2_bsp/linux-4.14.2_iTop-4412_scp/

PWD ?= $(shell pwd)

all:
	make -C $(KDIR) M=$(PWD) modules

clean:
	rm -rf *.o

交叉编译然后加载到内核后发现probe可以正常执行,打印两个中断号。