获取GPIO编号的方式
建立LED节点
目标设备树文件:linux-4.14.2_iTop-4412_scp/arch/arm/boot/dts/exynos4412-itop-elite.dts
首先屏蔽文件中存在”&gpk1 1”、”&gpl2 0”的键值对。
然后在根节点/{…}内新增如下子节点,注意status属性为”okay”
1
2
3
4
5
6
myled_demo:led_demo{
compatible = "led_demo";
status = "okay";
gpio1 = <&gpl2 0 GPIO_ACTIVE_HIGH>;
gpio2 = <&gpk1 1 GPIO_ACTIVE_HIGH>;
};
上面的信息指GPL2[0]初始高电平,GPK1[1]初始高电平。
重新编译设备树烧录到开发板。
编写驱动文件
led_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>
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("jerry");
#define DRV_NAME "led_demo"
static int gpio_pin[2] = {-1};//存放gpio编号
static int demo_probe(struct platform_device *pdv){
struct device_node *node = pdv->dev.of_node;
int ret;
printk("led probe ok!\n");
gpio_pin[0] = of_get_named_gpio(node, "gpio1", 0);
gpio_pin[1] = of_get_named_gpio(node, "gpio2", 0);
if((gpio_pin[0] < 0)||(gpio_pin[1] < 0)){
printk("of_get_named_gpio error!\n");
return 0;
}
printk("gpio_pin[0] is %d\n",gpio_pin[0]);
printk("gpio_pin[1] is %d\n",gpio_pin[1]);
ret = gpio_request(gpio_pin[0], "led1");
if(ret!=0){
printk("gpio_pin[0] request %d failed.", gpio_pin[0]);
return ret;
}
ret = gpio_request(gpio_pin[1], "led2");
if(ret!=0){
printk("gpio_pin[1] request %d failed.", gpio_pin[1]);
return ret;
}
gpio_free(gpio_pin[0]);
gpio_free(gpio_pin[1]);
gpio_direction_output(gpio_pin[0],0);
gpio_set_value(gpio_pin[0], 1);
gpio_direction_output(gpio_pin[1],0);
gpio_set_value(gpio_pin[1], 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 += led_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可以正常执行,LED灯正常点亮。
pinctrl方式
设备树文件修改
1、目标文件pinctrl设备树:linux-4.14.2_iTop-4412_scp/arch/arm/boot/dts/exynos4412-pinctrl.dtsi
目的是新增控制gpl2[0]高低电平的两个子节点。因为gpl2节点在pinctrl_1节点下,所以新增如下节点作为pinctrl_1节点的子节点。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
leds_gpios1{
leds_gpios1_on:leds_gpios1-on {
samsung,pins = "gpl2-0" ;
samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
samsung,pin-val = <1>;
samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
};
leds_gpios1_off:leds_gpios1-off {
samsung,pins = "gpl2-0" ;
samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
samsung,pin-val = <0>;
samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
};
};
2、目标设备树文件:linux-4.14.2_iTop-4412_scp/arch/arm/boot/dts/exynos4412-itop-elite.dts
在根节点下新增如下节点:
1
2
3
4
5
6
7
leds_test_node {
compatible = "leds_test";
status = "okay";
pinctrl-names = "itop-leds1-on","itop-leds1-off";
pinctrl-0 = <&leds_gpios1_on>;
pinctrl-1 = <&leds_gpios1_off>;
};
重新编译设备树烧录到开发板。
驱动思想
使用pinctrl的api函数获取GPIO状态并设置。
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <linux/pinctrl/consumer.h>
...
static int xxx_probe(struct platform_device *pdev){
struct pinctrl *leds_pin_ctrl;
struct pinctrl_state *leds_state;
leds_pin_ctrl = devm_pinctrl_get(&pdev->dev); //返回句柄
leds_state = pinctrl_lookup_state(leds_pin_ctrl,"itop-leds1-on");//获取状态
pinctrl_select_state(leds_pin_ctrl, leds_state); //设置状态
devm_pinctrl_put(leds_pin_ctrl); //释放句柄
return 0;
}
编写驱动文件
led_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
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("jerry");
#define DRV_NAME "leds_test"
static int demo_probe(struct platform_device *pdv){
struct pinctrl *leds_pin_ctrl;
struct pinctrl_state *leds_state;
int ret;
printk("led pinctl probe ok!\n");
leds_pin_ctrl = devm_pinctrl_get(&pdv->dev);
if (IS_ERR(leds_pin_ctrl)){
printk("leds_pin_ctrl,failed,%ld\n",PTR_ERR(leds_pin_ctrl));
return -1;
}
leds_state = pinctrl_lookup_state(leds_pin_ctrl,"itop-leds1-on");
if (IS_ERR(leds_state)) {
printk("leds_state,failed,%ld\n",PTR_ERR(leds_state));
return -1;
}
ret = pinctrl_select_state(leds_pin_ctrl, leds_state);
if(ret<0){
printk("pinctrl_select_state,failed\n");
return -1;
}
devm_pinctrl_put(leds_pin_ctrl);
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 += led_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可以正常执行,LED灯正常点亮。