GPIO子系统

GPIO子系统API函数

对于驱动开发人员,设置好设备树以后就可以使用 gpio 子系统提供的 API 函数来操作指定的 GPIO, gpio 子系统向驱动开发人员屏蔽了具体的读写寄存器过程。这就是驱动分层与分离的好处,大家各司其职,做好自己的本职工作即可。 gpio 子系统提供的常用的 API 函数有下面几个:

  1. gpio_request函数,用于申请一个 GPIO 管脚

    在使用一个 GPIO 之前一定要使用 gpio_request进行申请

    1
    int gpio_request(unsigned gpio, const char *label)

    gpio:要申请的gpio号,使用of_get_named_gpio函数从设备树获取指定gpio属性

    label: gpio的名字

    返回值:0申请成功,其他值失败

  2. gpio_free函数, 释放gpio

    1
    void gpio_free(unsigned gpio)

    gpio: 释放的gpio

    返回值无

  3. gpio_direction_input函数 , 设置gpio为输入

    1
    void gpio_direction_input(unsigned gpio)

    gpio:要设置的gpio

    返回值:设置成功,负值设置失败

  4. gpio_direction_output函数 ,设置某个 GPIO 为输出

    1
    int gpio_direction_output(unsigned gpio, int value)

    gpio:要设置为输出的 GPIO 标号。
    value: GPIO 默认输出值。
    返回值: 0,设置成功;负值,设置失败。

  5. gpio_get_value函数, 于获取某个 GPIO 的值

    1
    2
    #define gpio_get_value __gpio_get_value
    int __gpio_get_value(unsigned gpio)

    gpio:要获取的 GPIO 标号。
    返回值: 非负值,得到的 GPIO 值;负值,获取失败。

  6. gpio_set_value函数, 设置某个 GPIO 的值

1
2
#define gpio_set_value __gpio_set_value
void __gpio_set_value(unsigned gpio, int value)

​ gpio:要设置的 GPIO 标号。
​ value: 要设置的值。
​ 返回值: 无

设备树中添加GPIO节点模板

  • 创建设备节点
  • 添加pinctrl信息
  • 添加GPIO属性信息
1
2
3
4
5
6
7
8
/{
gpio{ /*把gpio节点添加到根节点下*/
pinctrl-names = "default";/*添加 pinctrl-names 属性*/
pinctrl-0 = <&pinctrl_gpio>;/*添加 pinctrl-0 节点,使用的 PIN 信息保存在 pinctrl_gpio 节点中*/
gpio = <&gpio1 0 GPIO_ACTIVE_LOW>;/*设备用的gpio*/

};
}

gpio 相关的 OF 函数

在驱动程序中需要读取 gpio 属性内容, Linux 内核提供了几个与 GPIO 有关的 OF 函数,常用的几个 OF 函数如下所示:

1
int of_gpio_named_count(struct device_node *np, const char *propname)//获取设备树某个属性定义了几个gpio信息

np:设备节点。
propname:要统计的 GPIO 属性。
返回值: 正值,统计到的 GPIO 数量;负值,失败。

1
int of_gpio_count(struct device_node *np)//统计的是“gpios”这个属性的 GPIO 数量

np:设备节点。
返回值: 正值,统计到的 GPIO 数量;负值,失败。

1
2
3
4
int of_get_named_gpio(struct device_node *np,
const char *propname,
int index)//此函数会将设备树中类似<&gpio5 7 GPIO_ACTIVE_LOW>的属性信息转换为对应的 GPIO 编

np:设备节点。

propname:包含要获取 GPIO 信息的属性名。

index: GPIO 索引,因为一个属性里面可能包含多个 GPIO,此参数指定要获取哪个 GPIO的编号,如果只有一个 GPIO 信息的话此参数为 0。
返回值: 正值,获取到的 GPIO ;负值,失败。

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/mach/map.h>

#define off 0
#define on 1


struct gpioled_dev{
dev_t devid;
struct class *class;
struct device *device;
struct cdev cdev;
int major;
int minor;
struct device_node *nd;
int led_gpio;
};
struct gpioled_dev gpioled;
static int gpio_open(struct inode *inode ,struct file *filp)
{
filp->private_data = &gpioled;
return 0;
}
static int gpio_release(struct inode *inode , struct file *filp)
{
return 0;
}
static ssize_t gpio_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
return 0;
}
static ssize_t gpio_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
int val;
unsigned char databuf[1];
unsigned char state;
struct gpioled_dev *dev = filp->private_data;
val = copy_from_user(databuf, buf, cnt);
if(val < 0)
{
printk("kernl write failed \r\n");
return -EFAULT;
}
state = databuf[0];
if(state == on)
{
gpio_set_value(dev->led_gpio, 0);
}else if(state == off)
{
gpio_set_value(dev->led_gpio, 1);
}
return 0;
}
static struct file_operations gpioled_ops ={
.owner = THIS_MODULE,
.open = gpio_open,
.read = gpio_read,
.write = gpio_write,
.release = gpio_release,
};
static int __init gpio_init(void)
{
int ret = 0;

gpioled.nd = of_find_node_by_path("/gpioled");
if(gpioled.nd == NULL)
{
printk("gpioled node can not found\r\n");
return -EINVAL;
}else{
printk("gpioled node found\r\n");
}
gpioled.led_gpio = of_get_named_gpio(gpioled.nd, "led-gpio",0);
if(gpioled.led_gpio < 0)
{
printk("can not led-gpio\r\n");
return -EINVAL;
}
ret = gpio_direction_output(gpioled.led_gpio, 1);
if(ret < 0)
{
printk("can't see gpio\r\n");
}
if(gpioled.major)
{
gpioled.devid = MKDEV(gpioled.major, 0);
register_chrdev_region(gpioled.devid, 1, "led");
}else{
alloc_chrdev_region(&gpioled.devid, 0, 1, "led");
gpioled.major = MAJOR(gpioled.devid);
gpioled.minor = MINOR(gpioled.devid);
}
gpioled.cdev.owner = THIS_MODULE;
cdev_init(&gpioled.cdev, &gpioled_ops);
cdev_add(&gpioled.cdev, gpioled.devid, 1);
gpioled.class = class_create(THIS_MODULE, "led");
if(IS_ERR(gpioled.class))
{
return PTR_ERR(gpioled.class);
}
gpioled.device = device_create(gpioled.class, NULL,gpioled.devid, NULL,"led");
if(IS_ERR(gpioled.device))
{
return PTR_ERR(gpioled.device);
}

return 0;
}
static void __exit gpio_exit(void)
{
cdev_del(&gpioled.cdev);
unregister_chrdev_region(gpioled.devid, 1);
device_destroy(gpioled.class, gpioled.devid);
class_destroy(gpioled.class);
}
module_init(gpio_init);
module_exit(gpio_exit);
MODULE_LICENSE("GPL");