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口方向的操作:
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驱动对其它驱动提供的
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,这样就可以用那些操作函数了。