一、旧的gpio_api
在GTX5驱动中兼容了两种获取GPIO、IRQ资源的方法,在老的内核版本中是通过of_get_named_gpio(node,"goodix,reset-gpio", 0)方法去获取GPIO资源的资源号(一个int型的数值),然后再使用如下方法(代码段1)对GPIO资源进行操作。
代码段1
r =devm_gpio_request_one(&core_data->pdev->dev,
ts_bdata->reset_gpio,
GPIOF_OUT_INIT_LOW,
"ts_reset_gpio");
二、新的gpiod_api
但在内核3.13之后,引入了新的gpiod_api,该api使用“devm_gpiod_get”去获取GPIO资源,获取到的是一个类型为“struct gpio_desc”的结构体指针,在操作GPIO时使用的是“gpiod_direction_output”方法。这两个方法的调用示例如代码段2和代码段3中所示:
代码段2
devm_gpiod_get(&core_data->pdev->dev,
"goodix,reset-gpio",GPIOD_OUT_LOW) 的goodix_ts_core.c中
代码段3
gpiod_direction_output(dev->board_data->reset_gpiod, 0);
“devm_gpiod_get”方法在获取GPIO资源时,仍然是通过of_node去获取的,其具体实现,如代码段4中所示。
代码段4
Kernel\drivers\gpio\gpiolib.c
/**
* gpiod_get_index - obtain aGPIO from a multi-index GPIO function
* @dev: GPIO consumer, can be NULL for system-global GPIOs
* @con_id: function within the GPIO consumer
* @idx: index of the GPIO to obtain in the consumer
* @flags: optional GPIO initialization flags
*
* This variant of gpiod_get()allows to access GPIOs other than the first
* defined one for functions thatdefine several GPIOs.
*
* Return a valid GPIOdescriptor, -ENOENT if no GPIO has been assigned to the
* requested function and/orindex, or another IS_ERR() code if an error
* occured while trying toacquire the GPIO.
*/
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 *desc =NULL;
int status;
enum gpio_lookup_flagslookupflags = 0;
dev_dbg(dev, "GPIOlookup for consumer %s\n", con_id);
/* Using device tree? */
if (IS_ENABLED(CONFIG_OF)&& dev && dev->of_node) {
dev_dbg(dev,"using device tree for GPIO lookup\n");
desc =of_find_gpio(dev, con_id, idx, &lookupflags);
} else if(IS_ENABLED(CONFIG_ACPI) && dev && ACPI_HANDLE(dev)) {
dev_dbg(dev,"using ACPI for GPIO lookup\n");
desc =acpi_find_gpio(dev, con_id, idx, &lookupflags);
}
/*
* Either we are not using DT or ACPI, or theirlookup did not return
* a result. In that case, use platform lookupas a fallback.
*/
if (!desc || desc ==ERR_PTR(-ENOENT)) {
dev_dbg(dev,"using lookup tables for GPIO lookup\n");
desc =gpiod_find(dev, con_id, idx, &lookupflags);
}
if (IS_ERR(desc)) {
dev_dbg(dev,"lookup for GPIO %s failed\n", con_id);
return desc;
}
status =gpiod_request(desc, con_id);
if (status < 0)
returnERR_PTR(status);
if (lookupflags &GPIO_ACTIVE_LOW)
set_bit(FLAG_ACTIVE_LOW,&desc->flags);
if (lookupflags &GPIO_OPEN_DRAIN)
set_bit(FLAG_OPEN_DRAIN,&desc->flags);
if (lookupflags &GPIO_OPEN_SOURCE)
set_bit(FLAG_OPEN_SOURCE,&desc->flags);
/* No particular flagrequest, return here... */
if (!(flags &GPIOD_FLAGS_BIT_DIR_SET))
return desc;
/* Process flags */
if (flags &GPIOD_FLAGS_BIT_DIR_OUT)
status =gpiod_direction_output(desc,
flags & GPIOD_FLAGS_BIT_DIR_VAL);
else
status =gpiod_direction_input(desc);
if (status < 0) {
dev_dbg(dev,"setup of GPIO %s failed\n", con_id);
gpiod_put(desc);
returnERR_PTR(status);
}
return desc;
}
EXPORT_SYMBOL_GPL(__gpiod_get_index);
三、调用devm_gpiod_get时的注意点
使用该方法时,给方法传递的第二个参数一定要特别注意。追踪该方法在内核中的具体实现可知:devm_gpiod_get最终调用的是gpiolib.c中的“__gpiod_get_index”方法,而该方法最终调用的是“of_find_gpio”方法,查看该方法的实现可知,方法在查找GPIO资源时已经自动为我们加了“-gpio”、“-gpios”后缀,所以我们在调用devm_gpiod_get时,要对匹配字符串进行相应的修改。
比如在DTS中有如下的资源:
snowflate,reset-gpio= <&pio 256 0>;
那么在调用devm_gpiod_get去获取该资源时,第二个参数直接传"snowflate,reset"就可以了,而不是传递“snowflate,reset-gpio”。
代码段5
Kernel\drivers\gpio\gpiolib.c
staticstruct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
unsigned int idx,
enum gpio_lookup_flags *flags)
{
static const char *suffixes[] = { "gpios","gpio" };
char prop_name[32]; /* 32 is max size of property name */
enum of_gpio_flags of_flags;
struct gpio_desc *desc;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
if (con_id)
snprintf(prop_name, 32,"%s-%s", con_id, suffixes[i]);
else
snprintf(prop_name, 32, "%s",suffixes[i]);
desc = of_get_named_gpiod_flags(dev->of_node,prop_name, idx,
&of_flags);
if (!IS_ERR(desc) || (PTR_ERR(desc) ==-EPROBE_DEFER))
break;
}
if (IS_ERR(desc))
return desc;
if (of_flags & OF_GPIO_ACTIVE_LOW)
*flags |= GPIO_ACTIVE_LOW;
return desc;
}