Linux驱动开发---gpio和gpiod

时间:2021-07-06 10:35:52

一、旧的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;

}