内核GPIO编程说明
参考资料:https://www.kernel.org/doc/Documentation/gpio/
从官方资料来看,linux内核中的gpio接口目前有新旧两个版本,新的版本的接口是descriptor-based的,而旧的是integer-based的。旧的接口已出于兼容性的考虑仍被支持,但已不再建议使用。网上目前大多GPIO编程说明都是旧的版本,所以这篇说明就以介绍新的接口版本为主。
1.驱动首先需要包含头文件:
#include <linux/gpio/consumer.h>
2.调用gpio设备所需函数,函数返回描述符或错误码
struct gpio_desc *gpiod_get(struct device *dev, const char *con_id,
enum gpiod_flags flags)
如果设备需要使用多个gpio,则需在函数中添加index参数:
struct gpio_desc *gpiod_get_index(struct device *dev,
const char *con_id, unsigned int idx,
enum gpiod_flags flags)
其中gpiod_flag控制初始化模式,有以下几种:
* GPIOD_ASIS or 0 不进行初始化
* GPIOD_IN 将gpio初始化为input模式
* GPIOD_OUT_LOW 将gpio初始化为低电平output
* GPIOD_OUT_HIGH 将gpio初始化为高电平output
也可以用以下两个函数调用可用gpio。当没有gpio调用成功时,返回null
struct gpio_desc *gpiod_get_optional(struct device *dev,
const char *con_id,
enum gpiod_flags flags)
struct gpio_desc *gpiod_get_index_optional(struct device *dev,
const char *con_id,
unsigned int index,
enum gpiod_flags flags)
或者在获取多个gpio时只要调用一个函数即可:
struct gpio_descs *gpiod_get_array(struct device *dev,
const char *con_id,
enum gpiod_flags flags)
该函数返回结构体gpi_descs:
struct gpio_descs {
unsigned int ndescs;
struct gpio_desc *desc[];
}
3. 释放一个gpio使用函数:
void gpiod_put(struct gpio_desc *desc)
或者释放多个gpio使用
void gpiod_put_array(struct gpio_descs *descs)
在调用这些函数后,被释放的描述符不可再被使用。
4.GPIO的设置
调用以下函数来的设置gpio的方向:
int gpiod_direction_input(struct gpio_desc *desc)
int gpiod_direction_output(struct gpio_desc *desc, int value)
获取当前方向:
int gpiod_get_direction(const struct gpio_desc *desc)
函数返回GPIOF_DIR_IN/GPIOF_DIR_OUT
5.GPIO的访问
GPIO的访问可通过主存的读写指令完成,这种操作不需要sleep,所以在内部硬中断时也可以被调用,安全性较高。使用以下函数来进行该原子访问操作:
int gpiod_get_value(const struct gpio_desc *desc);
void gpiod_set_value(struct gpio_desc *desc, int value);
另一种gpio设备访问必须使用消息总线如I2C或SPI,这种操作需要在队列中等待,所以不再能在IRQ中被调用:
int gpiod_get_value_cansleep(const struct gpio_desc *desc)
void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
分辨此类gpio设备:
int gpiod_cansleep(const struct gpio_desc *desc)
6.输出信号
有些设备采用低电平有效的方式输出逻辑信号。此时低电平输出1,高电平输出0。此时可以通过访问raw_value的方式来访问实际电路上的值,与逻辑处理无关:
int gpiod_get_raw_value(const struct gpio_desc *desc)
void gpiod_set_raw_value(struct gpio_desc *desc, int value)
int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value)
int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
逻辑关系汇总如下:
Function (example) active-low property physical line
gpiod_set_raw_value(desc, 0); don’t care low
gpiod_set_raw_value(desc, 1); don’t care high
gpiod_set_value(desc, 0); default (active-high) low
gpiod_set_value(desc, 1); default (active-high) high
gpiod_set_value(desc, 0); active-low high
gpiod_set_value(desc, 1); active-low low
可以使用如下函数判断一个设备是否是低电平有效的设备。
int gpiod_is_active_low(const struct gpio_desc *desc)
可以通过以下函数对一组GPIO进行输出设置:
void gpiod_set_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
7.映射到IRQs
int gpiod_to_irq(const struct gpio_desc *desc)
8.GPIO和ACPI
在ACPI系统上,GPIO设备在GpioIo()/GpioInt()从_CRS中获得的资源列表中被描述,这些资源不能在系统GPIO中被使用。
参考资料:https://www.kernel.org/doc/Documentation/gpio/
从官方资料来看,linux内核中的gpio接口目前有新旧两个版本,新的版本的接口是descriptor-based的,而旧的是integer-based的。旧的接口已出于兼容性的考虑仍被支持,但已不再建议使用。网上目前大多GPIO编程说明都是旧的版本,所以这篇说明就以介绍新的接口版本为主。
1.驱动首先需要包含头文件:
#include <linux/gpio/consumer.h>
2.调用gpio设备所需函数,函数返回描述符或错误码
struct gpio_desc *gpiod_get(struct device *dev, const char *con_id,
enum gpiod_flags flags)
如果设备需要使用多个gpio,则需在函数中添加index参数:
struct gpio_desc *gpiod_get_index(struct device *dev,
const char *con_id, unsigned int idx,
enum gpiod_flags flags)
其中gpiod_flag控制初始化模式,有以下几种:
* GPIOD_ASIS or 0 不进行初始化
* GPIOD_IN 将gpio初始化为input模式
* GPIOD_OUT_LOW 将gpio初始化为低电平output
* GPIOD_OUT_HIGH 将gpio初始化为高电平output
也可以用以下两个函数调用可用gpio。当没有gpio调用成功时,返回null
struct gpio_desc *gpiod_get_optional(struct device *dev,
const char *con_id,
enum gpiod_flags flags)
struct gpio_desc *gpiod_get_index_optional(struct device *dev,
const char *con_id,
unsigned int index,
enum gpiod_flags flags)
或者在获取多个gpio时只要调用一个函数即可:
struct gpio_descs *gpiod_get_array(struct device *dev,
const char *con_id,
enum gpiod_flags flags)
该函数返回结构体gpi_descs:
struct gpio_descs {
unsigned int ndescs;
struct gpio_desc *desc[];
}
3. 释放一个gpio使用函数:
void gpiod_put(struct gpio_desc *desc)
或者释放多个gpio使用
void gpiod_put_array(struct gpio_descs *descs)
在调用这些函数后,被释放的描述符不可再被使用。
4.GPIO的设置
调用以下函数来的设置gpio的方向:
int gpiod_direction_input(struct gpio_desc *desc)
int gpiod_direction_output(struct gpio_desc *desc, int value)
获取当前方向:
int gpiod_get_direction(const struct gpio_desc *desc)
函数返回GPIOF_DIR_IN/GPIOF_DIR_OUT
5.GPIO的访问
GPIO的访问可通过主存的读写指令完成,这种操作不需要sleep,所以在内部硬中断时也可以被调用,安全性较高。使用以下函数来进行该原子访问操作:
int gpiod_get_value(const struct gpio_desc *desc);
void gpiod_set_value(struct gpio_desc *desc, int value);
另一种gpio设备访问必须使用消息总线如I2C或SPI,这种操作需要在队列中等待,所以不再能在IRQ中被调用:
int gpiod_get_value_cansleep(const struct gpio_desc *desc)
void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
分辨此类gpio设备:
int gpiod_cansleep(const struct gpio_desc *desc)
6.输出信号
有些设备采用低电平有效的方式输出逻辑信号。此时低电平输出1,高电平输出0。此时可以通过访问raw_value的方式来访问实际电路上的值,与逻辑处理无关:
int gpiod_get_raw_value(const struct gpio_desc *desc)
void gpiod_set_raw_value(struct gpio_desc *desc, int value)
int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value)
int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
逻辑关系汇总如下:
Function (example) active-low property physical line
gpiod_set_raw_value(desc, 0); don’t care low
gpiod_set_raw_value(desc, 1); don’t care high
gpiod_set_value(desc, 0); default (active-high) low
gpiod_set_value(desc, 1); default (active-high) high
gpiod_set_value(desc, 0); active-low high
gpiod_set_value(desc, 1); active-low low
可以使用如下函数判断一个设备是否是低电平有效的设备。
int gpiod_is_active_low(const struct gpio_desc *desc)
可以通过以下函数对一组GPIO进行输出设置:
void gpiod_set_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
7.映射到IRQs
int gpiod_to_irq(const struct gpio_desc *desc)
8.GPIO和ACPI
在ACPI系统上,GPIO设备在GpioIo()/GpioInt()从_CRS中获得的资源列表中被描述,这些资源不能在系统GPIO中被使用。