前言:
gpio子系统的内容在drivers/gpio文件夹下,主要文件有:
- devres.c :devres.c是针对gpio api增加的devres机制的支持
- gpiolib.c :gpiolib.c是gpio子系统的核心实现
- gpiolib-of.c :gpiolib-of.c是对设备树的支持
- gpiolib-acpi.c :
- gpio-xxx.c :
目录:
一、驱动流程步骤+函数分析
二、驱动讲解
三、驱动伪代码实现
四、驱动思想分析**
正文;
一、驱动流程步骤
GPIO子系统驱动流程分为以下几个步骤:
1、请求一个GPIO组
2、设置GPIO方向输出\输入
3、将GPIO通过System导出,应用层可以通过文件操作gpio
4、如果设置为输出模式(设置值),输入模式(获取值)
5、将GPIO转为对应的IRQ,然后注册改IRQ的中断handler
6、释放请求的一个或者一个组GPIO
二、函数分析;
a、申请一个GPIO组:
int gpio_request(unsigned gpio, const char *label):
参数1:gpio号
参数2:这个数据保留到pin数据结构们勇于debug
返回值:零正常,负数错误
经过拓展的函数:(gpio_request_one),(gpio_request_array)
b、释放一个GPIO组:
void gpio_free(unsigned gpio)
参数1:GPIO编号
返回值:无
c、配置GPIO对应的方向:
(设置输入方向函数)
int gpio_direction_input(unsigned gpio);
参数1:GPIO口的编号
返回值:零正常,负数错误
(设置输出方向函数)
int gpio_direction_output(unsigned gpio, int value);
参数1:GPIO口的编号
参数2:GPIO口默认端口输出0还是1
返回值:零正常,负数错误
d、 测试GPIO是否合法:
int gpio_is_valid(int number)
参数;GPIO编号
返回值:零正常,负数错误
e、获取GPIO的引脚值或者设置GPIO引脚值
(输出状态)
void gpio_set_value(unsigned gpio, int value);
参数1:GPIO的编号
参数2:设置对应的输出值(0/1)
返回值:无
(输入状态)
int gpio_get_value(unsigned gpio);
参数1:GPIO编号
返回值:对应的GPIO引脚状态(0/1),负数错误
f、获取对应引脚的GPIO编号
int gpio_to_irq(unsigned gpio);
参数1:GPIO编号
返回值:中断编号
拓展:将对应的中断编号给request_irq()函数进行注册,实现中断服务函数
释放对应的中断资源fee_irq(),两个函数的形参都必须要中断编号
g、将GPIO端口导出到用户空间、
(GPIO导入函数)
int gpio_export(unsigned gpio, bool direction_may_change);
参数1、GPIO编号
参数2、表示用户程序是否允许修改gpio的方向
假如可以则参数为为真:direction_may_change
拓展:分析这个函数的本身就是创建system(文件子系统),生成文件可以在以
路径找到( /sys/class/gpio* )
export/unexport文件
gpioN指代具体的gpio引脚
gpio_chipN指代gpio控制器
(撤销GPIO导入)
void gpio_unexport(unsigned gpio)
参数1:GPIO编号
返回值:无
驱动工程师需要实现的步骤
要注意的是对应的内核版本有没有对应的设备树。一般来说3.0一下版本的内核是没有带设备树
作为一种情况,在3.10以上的内核是带有对应的设备树所以要注意;帮助手册一般是(gpio.txt)
没有带设备树的
通过GPIO.h头文件就可以获取得到。
带设备树的
更新一下设备树:make ARCH=arm exynos4_defconfig
make ARCH=arm dtbs
一、首先需要去到对应芯片的设备树的下面添加一个设备树节点
led_noe{
gpiox_1_led = <&gpx1 0 0 >
}
<&gpx1 0 0 >分析;
参数1:继承对应的GPIO
参数2:具体的GPIO号
参数3:默认的GPIO电平状态
首先在对应的设备树下做好一个节点:要注意的是这个节点是在设备树根目录下。
内核提供一个函数通过设备树给我们获取到对应的GPIO号:
static inline int of_get_named_gpio(struct device_node *np,
const char *propname, int index)
功能:解析设备树的中的GPIO
参数1:设备树节点结构体 通过of_find_node_by_path()函数获取得到
参数2:设备树的键值堆 gpiox_1_led
参数3:索引号 (led_noe第几个的GPIO 从0开始)
返回值:成功返回GPIO号 失败错误码
上面函数的参数1,作为一个结构体,是通过下面这个函数获取回来的。
struct device_node *of_find_node_by_path(const char *path)
参数1:节点路径 ( #define "/led_node" )
返回值:地址,错误为NULL
二、通过获取回来的GPIO号,然后进行一个检查是否合法
int gpio_is_valid(int number)
三、设置GPIO的输入或者输出方向
i
nt gpio_direction_input(unsigned gpio); 或者是
int gpio_direction_output(unsigned gpio, int value);
四、可以获取GPIO的状态或者设置GPIO的状态
当输出的状态下可以读取或者设备GPIO的状态
void gpio_set_value(unsigned gpio, int value);
int gpio_get_value(unsigned gpio);
或者当时输入方向的时候可以读取对应的GPIO引脚状态
int gpio_get_value(unsigned gpio);
五、要在退出函数哪里将申请的这些资源都退出
void gpio_unexport(unsigned gpio)