GPIO子系统
GPIO子系统API函数
对于驱动开发人员,设置好设备树以后就可以使用 gpio 子系统提供的 API 函数来操作指定的 GPIO, gpio 子系统向驱动开发人员屏蔽了具体的读写寄存器过程。这就是驱动分层与分离的好处,大家各司其职,做好自己的本职工作即可。 gpio 子系统提供的常用的 API 函数有下面几个:
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申请成功,其他值失败
gpio_free函数, 释放gpio
1
| void gpio_free(unsigned gpio)
|
gpio: 释放的gpio
返回值无
gpio_direction_input函数 , 设置gpio为输入
1
| void gpio_direction_input(unsigned gpio)
|
gpio:要设置的gpio
返回值:设置成功,负值设置失败
gpio_direction_output函数 ,设置某个 GPIO 为输出
1
| int gpio_direction_output(unsigned gpio, int value)
|
gpio:要设置为输出的 GPIO 标号。
value: GPIO 默认输出值。
返回值: 0,设置成功;负值,设置失败。
gpio_get_value函数, 于获取某个 GPIO 的值
1 2
| #define gpio_get_value __gpio_get_value int __gpio_get_value(unsigned gpio)
|
gpio:要获取的 GPIO 标号。
返回值: 非负值,得到的 GPIO 值;负值,获取失败。
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{ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_gpio>; gpio = <&gpio1 0 GPIO_ACTIVE_LOW>; }; }
|
gpio 相关的 OF 函数
在驱动程序中需要读取 gpio 属性内容, Linux 内核提供了几个与 GPIO 有关的 OF 函数,常用的几个 OF 函数如下所示:
1
| int of_gpio_named_count(struct device_node *np, const char *propname)
|
np:设备节点。
propname:要统计的 GPIO 属性。
返回值: 正值,统计到的 GPIO 数量;负值,失败。
1
| int of_gpio_count(struct device_node *np)
|
np:设备节点。
返回值: 正值,统计到的 GPIO 数量;负值,失败。
1 2 3 4
| int of_get_named_gpio(struct device_node *np, const char *propname, int index) 号
|
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");
|