Linux_kernel驱动之GPIO子系统

前言:
gpio子系统的内容在drivers/gpio文件夹下,主要文件有:

  1. devres.c :devres.c是针对gpio api增加的devres机制的支持
  2. gpiolib.c :gpiolib.c是gpio子系统的核心实现
  3. gpiolib-of.c :gpiolib-of.c是对设备树的支持
  4. gpiolib-acpi.c :
  5. 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)

你可能感兴趣的:(Linux_随笔,笔记)