本文转自http://blog.csdn.net/jklinux/article/details/78581120?locationnum=3&fps=1
参考内核源码里的Documentation/devicetree/bindings/gpio/gpio.txt
在设备树里的节点设备需要使用到gpio口,则需要在一个或多个节点属性里提供gpio口的信息.
关于gpio口信息的节点属性命名方式是: name-gpios , 其中name用于指此gpio口在设备里的具体用途.
如用于复位的io口,则属性可以命名为: reset-gpios
出于兼容旧版本设备树的原因,属性名里也可以不写name而直接使用gpios作为属性名.这种方式内核以后不再允许使用.
关于gpio口的节点属性名还可以命名: name-gpio, 但这种方式内核也不会再使用.
关于gpio口的属性值.
一个属性值可以写单个的gpio口信息, 也可以写多个的gpio口信息
单个gpio口信息的属性值: <&gpio控制器节点名 具体gpio口的标识符>
一个具有多个gpio口信息的属性值: <&gpio控制器节点名 具体gpio口的标识符>,<&gpio控制器节点名 具体gpio口的标识符> …;
具体gpio口的标识符是由多个数字组成, 数字的个数由所用的gpio控制器节点里的#gpio-cells属性值指定.
如:
sunxi-h3-h5.dtsi里关于gpio控制器的节点信息:
pio: pinctrl@01c20800 { /*也可以通过此基地址在芯片手册里确认具体是哪个控制器 */
...
gpio-controller; /* 标明此节点是gpio控制器 */
#gpio-cells = <3>; /* 标明每个gpio口的标识符由3个数字来识别(第0个数字表示gpio的组, 第1个数字表示组内的gpio口序号, 第3个数字表示gpio口的有效状态) */
/* 有些方案只用两个数字 */
...
};
----------
gpio口的有效状态在内核头文件include/dt-bindings/gpio/gpio.h里定义:
/* Bit 0 express polarity */
#define GPIO_ACTIVE_HIGH 0
#define GPIO_ACTIVE_LOW 1
/* Bit 1 express single-endedness */
#define GPIO_PUSH_PULL 0
#define GPIO_SINGLE_ENDED 2
#define GPIO_OPEN_DRAIN (GPIO_SINGLE_ENDED | GPIO_ACTIVE_LOW)
#define GPIO_OPEN_SOURCE (GPIO_SINGLE_ENDED | GPIO_ACTIVE_HIGH)
----------
则表示一个PA17口上接的led灯时,则可以如下指定:
myleds {
compatible = "myleds";
led0 {
label = "led0";
led0-gpios = <&pio 0 17 GPIO_ACTIVE_HIGH>
/* 0表示PA组的io口, 因h5里第0组的io口就是以PA开始命名的 */
};
};
如设备使用多个gpio口,也可以写在一个属性值里.
myleds {
...
leds-gpios = <&pio 0 18 GPIO_ACTIVE_HIGH>, <&pio 0 19 GPIO_ACTIVE_HIGH>;
...
};
在以前没用设备树的内核里使用u32类型的一个数值表示一个gpio口, 具体的数值由芯片厂商负责定义好.
调用gpio口时只需使用如下的函数即可:
#include
int gpio_direction_input(unsigned gpio);
int gpio_direction_output(unsigned gpio, int value);
int gpio_get_value(unsigned gpio);
void gpio_set_value(unsigned gpio, int value);
int gpio_to_irq(unsigned gpio);
使用设备树的内核里使用struct gpio_desc类型的一个对象表示设备树节点属性里的一个gpio口, 对象里的成员值由芯片厂商的驱动代码负责初始化,我们只需使用函数gpiod_get()获取即可.
可使用struct gpio_descs类型的一个对象装载struct gpio_desc多个对象(gpiod_get_array()函数获取).
#include
struct gpio_descs {
unsigned int ndescs;
struct gpio_desc *desc[];
};
在获取一个或多个在设备树设备节点属性里的gpio口时,可以指定获取的gpio口是作输入/输出.
#define GPIOD_FLAGS_BIT_DIR_SET BIT(0)
#define GPIOD_FLAGS_BIT_DIR_OUT BIT(1)
#define GPIOD_FLAGS_BIT_DIR_VAL BIT(2)
enum gpiod_flags {
GPIOD_ASIS = 0,
GPIOD_IN = GPIOD_FLAGS_BIT_DIR_SET, //作输入
GPIOD_OUT_LOW = GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT, //作输出且输出低电平
GPIOD_OUT_HIGH = GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT |
GPIOD_FLAGS_BIT_DIR_VAL, //作输出且输出高电平
};
int gpiod_count(struct device *dev, const char *con_id); //获取设备节点里的gpio口个数
//以下函数用于获取设备节点(不是它的子节点)属性值里gpio口的信息
//参数con_id用于指定自定义的属性名的前缀,如属性名"leds-gpios", 则con_id应为"leds"
//flags用于指定获取gpio口信息时指定gpio是作输入或输出高低电平
struct gpio_desc *__must_check gpiod_get(struct device *dev,
const char *con_id,
enum gpiod_flags flags);
struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
const char *con_id,
unsigned int idx,
enum gpiod_flags flags);
struct gpio_desc *__must_check gpiod_get_optional(struct device *dev,
const char *con_id,
enum gpiod_flags flags);
struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev,
const char *con_id,
unsigned int index,
enum gpiod_flags flags);
struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
const char *con_id,
enum gpiod_flags flags);
struct gpio_descs *__must_check gpiod_get_array_optional(struct device *dev,
const char *con_id,
enum gpiod_flags flags);
struct gpio_desc *__must_check devm_gpiod_get(struct device *dev,
const char *con_id,
enum gpiod_flags flags);
struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
const char *con_id,
unsigned int idx,
enum gpiod_flags flags);
struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev,
const char *con_id,
enum gpiod_flags flags);
struct gpio_desc *__must_check
devm_gpiod_get_index_optional(struct device *dev, const char *con_id,
unsigned int index, enum gpiod_flags flags);
struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev,
const char *con_id,
enum gpiod_flags flags);
struct gpio_descs *__must_check
devm_gpiod_get_array_optional(struct device *dev, const char *con_id,
enum gpiod_flags flags);
//下面4个*_put函数用于回收设备节点属性里关于gpio口的信息.
//**注意只有释放gpio_desc资源后才可重新获取**
void devm_gpiod_put(struct device *dev, struct gpio_desc *desc);
void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs);
void gpiod_put(struct gpio_desc *desc);
void gpiod_put_array(struct gpio_descs *descs);
//函数以devm开头的是有标明相应的资源是属于哪个struct device对象的功能.
////////////////////////////////////////////////////////////
//获取到gpio口的struct gpio_desc对象地址后,就可以通过下面函数操作gpio口
int gpiod_get_direction(struct gpio_desc *desc); //判断gpio是作输入或输出
int gpiod_direction_input(struct gpio_desc *desc); //gpio口作输入
int gpiod_direction_output(struct gpio_desc *desc, int value); //作输出, value用于指定输出的电平, 1表示输出有效电平,0表示输出失效电平。与在设备节点里设置GPIO_ACTIVIE_HIGHT/LOW有关
int gpiod_direction_output_raw(struct gpio_desc *desc, int value); //作输出, value用于直接指定是输出高低电平, 1表示高电平, 0表示低平, 带raw的函数是不会管ACTIVIE_LOW/ACTIVIE_HIGH的状态的
int gpiod_get_value(const struct gpio_desc *desc);
void gpiod_set_value(struct gpio_desc *desc, int value);
void gpiod_set_array_value(unsigned int array_size,
struct gpio_desc **desc_array, int *value_array);
int gpiod_get_raw_value(const struct gpio_desc *desc);
void gpiod_set_raw_value(struct gpio_desc *desc, int value);
void gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array);
int gpiod_get_value_cansleep(const struct gpio_desc *desc);
void gpiod_set_value_cansleep(struct gpio_desc *desc, int value);
void gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array);
int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc);
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value);
void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array);
///////////////////////////////////////////////////
int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); //设置过滤抖动电平信号
int gpiod_is_active_low(const struct gpio_desc *desc);
int gpiod_cansleep(const struct gpio_desc *desc);
int gpiod_to_irq(const struct gpio_desc *desc); //根据gpio_desc信息找到gpio口对应的中断号
struct gpio_desc *gpio_to_desc(unsigned gpio); //根据u32的gpio号找到gpio口对应的gpio_desc对象地址
int desc_to_gpio(const struct gpio_desc *desc); //根据gpio口的gpio_desc对象找到对象的u32的gpio号.
////////////////////////////////////////////////////
//获取设备节点里子节点关于gpio的属性值函数:
struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
const char *propname, int index,
enum gpiod_flags dflags,
const char *label);
struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
const char *con_id, int index,
struct fwnode_handle *child,
enum gpiod_flags flags,
const char *label);
static inline
struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev,
const char *con_id,
struct fwnode_handle *child,
enum gpiod_flags flags,
const char *label);