gpio linux 实现模型

GPIO是与硬件体系密切相关的,linux提供一个模型来让驱动统一处理GPIO,即各个板卡都有实现自己的gpio_chip控制模块:request, free, input,output, get,set,irq...


        然后把控制模块注册到内核中,这时会改变全局gpio数组:gpio_desc[]. 


        当用户请求gpio时,就会到这个数组中找到,并调用这个GPIO对应的gpio_chip的处理函数。


        gpio实现为一组可用的 gpio_chip, 由驱动传入对应 gpio的全局序号 去 request, dataout ,datain, free. 这时会调用gpio_chip中具体的实现。


       寄存器读写函数:   __raw_writel()   __raw_writeb()   __raw_readl()   __raw_readb()


        gpio是一组可控件的脚,由多个寄存器同时控制。通过设置对应的寄存器可以达到设置GPIO口对应状态与功能。
数据状态,输入输出方向,清零,中断(那个边沿触发), 一般是一组(bank)一组的。


//****************linux 中 GPIO模型****************************************//
注册方法:
1:struct gpio_chip: 表示一个gpio controller.通过这个结构抽象化所有的 GPIO源,而让板上其它的模块可以用相同的接口调用使用这些GPIO。
2: struct gpio_desc: 表示一个gpio口,含对应的 gpio_chip.
3: ARCH_NR_GPIOS:  与板相关的GPIO口数量,即是全局GPIO数组:static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
4: 注册 gpio_chip时,就是根据 chip 的数据 修改全局 GPIO数组中 gpio_desc 字段(chip, flags)。

 

*********************************************

GPIO的驱动主要就是读取GPIO口的状态,或者设置GPIO口的状态。就是这么简单,但是为了能够写好的这个驱动,在LINUX上作了一些软件上的分层。


为了让其它驱动可以方便的操作到GPIO,在LINUX里实现了对GPIO操作的统一接口,这个接口实则上就是GPIO驱动的框架,具体的实现文件为gpiolib.c

在配置内核的时候,我们必须使用CONFIG_GENERIC_GPIO这个宏来支持GPIO驱动。

这里我们把目光放到gpiolib.c上,主要对外提供的接口函数,在其头文件gpio.h里可以看到:

具体的GPIO描述符:

structgpio_chip {

… ...

int (*request)(struct gpio_chip *chip, unsigned offset);

void (*free)(struct gpio_chip *chip, unsigned offset);

int (*direction_input)(struct gpio_chip *chip, unsignedoffset);

int (*get)(struct gpio_chip *chip, unsigned offset);

int (*direction_output)(struct gpio_chip *chip, unsignedoffset, int value);

int (*set_debounce)(struct gpio_chip *chip, unsigned offset,

unsigneddebounce);

void (*set)(struct gpio_chip *chip, unsigned offset, int value);

int (*to_irq)(struct gpio_chip *chip, unsigned offset);

void (*dbg_show)(struct seq_file *s, struct gpio_chip *chip);

int base;

u16 ngpio;

… ...

};

 


申请和释放GPIO资源:

externint gpio_request(unsigned gpio, const char *label);

 


externvoid gpio_free(unsigned gpio);

 


设置GPIO口方向的操作www.linuxidc.com:

externint gpio_direction_input(unsigned gpio);

externint gpio_direction_output(unsigned gpio, int value);

 


设置GPIO口高低电平值操作:

externint gpio_get_value_cansleep(unsigned gpio);

externvoid gpio_set_value_cansleep(unsigned gpio, int value);

 


externint __gpio_get_value(unsigned gpio);

externvoid __gpio_set_value(unsigned gpio, int value);

 


GPIO驱动的关系图:

gpio linux 实现模型_第1张图片

 

如上图所示,右上方部分为GPIO驱动对其它驱动提供的GPIO操作接口,其对应的右下方部分为GPIO硬件操作接口,也就是说对外提供的接口最终会一一对应的对硬件GPIO进行操作。

再来看左边部分,左上方部分为一全局数组,记录各个GPIO的描述符,即对应左下方的gpio_desc结构体,其中gpio_chip指向硬件层的GPIO,flags为一标志位,用来指示当前GPIO是否已经占用,当用gpio_request申请GPIO资源时,flags位就会置位,当调用gpio_free释放GPIO资源时,flags就会清零。label是一个字符串指针,用来作说明。

在软件上,我们首先通过函数gpiochip_add注册一个gpio_chip对应的gpio_desc到全局数组gpio描述符中。其中,一个描述符对应一个GPIO,所以如果我们要使用多个GPIO,那么就在gpio_chip结构体的ngpio指定个数,base为起始的GPIO号。

 

 

如果你想使用GPIO驱动,那么在配置内核的时候请把该驱动选上,即定义宏CONFIG_GENERIC_GPIO,然后在你的驱动里加入头文件linux/gpio.h,这样就可以用那些操作函数了。

 

 

你可能感兴趣的:(linux,框架,struct,File,input,output)