This patch introduces another two variants of gpiod_get_array, fwnode_gpiod_get_array and devm_fwnode_gpiod_get_array, to return GPIO descriptor array to comsumers. Unlike gpiod_get_array, which calls dev_fwnode(dev) to get firmware node in gpiod_get_index, new variants allow consumers to pass firmware node by themselves. It's applicable to below circumstance: fwnode_for_each_child_node(fw_parent, fw_child) or for_each_child_of_node struct gpio_descs *array = devm_fwnode_gpiod_get_array( dev, fw_child,...). or fwnode_gpiod_get_array Signed-off-by: Song Chen <chensong_2000@xxxxxx> --- drivers/gpio/gpiolib-devres.c | 43 ++++++++++++++++ drivers/gpio/gpiolib.c | 96 +++++++++++++++++++++++++++++------ include/linux/gpio/consumer.h | 28 ++++++++++ 3 files changed, 151 insertions(+), 16 deletions(-) diff --git a/drivers/gpio/gpiolib-devres.c b/drivers/gpio/gpiolib-devres.c index 08205f355ceb..f8b2a3fe02ba 100644 --- a/drivers/gpio/gpiolib-devres.c +++ b/drivers/gpio/gpiolib-devres.c @@ -192,6 +192,49 @@ struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev, } EXPORT_SYMBOL_GPL(devm_fwnode_gpiod_get_index); +/** + * devm_fwnode_gpiod_get_array - Resource-managed gpiod_get_array_by_fwnode() + * @dev: GPIO consumer + * @fwnode: firmware node containing GPIO reference + * @con_id: function within the GPIO consumer + * @flags: optional GPIO initialization flags + * + * Managed gpiod_get_array_by_fwnode(). GPIO descriptors returned from this function are + * automatically disposed on driver detach. See gpiod_get_array_by_fwnode() for detailed + * information about behavior and return values. + * + * Returns: + * The GPIO descriptors corresponding to the function @con_id of device + * dev, %-ENOENT if no GPIO has been assigned to the requested function, + * or another IS_ERR() code if an error occurred while trying to acquire + * the GPIOs. + */ +struct gpio_descs *devm_fwnode_gpiod_get_array(struct device *dev, + struct fwnode_handle *fwnode, + const char *con_id, + enum gpiod_flags flags) +{ + struct gpio_descs **dr; + struct gpio_descs *descs; + + dr = devres_alloc(devm_gpiod_release_array, + sizeof(struct gpio_descs *), GFP_KERNEL); + if (!dr) + return ERR_PTR(-ENOMEM); + + descs = gpiod_get_array_by_fwnode(dev, fwnode, con_id, flags); + if (IS_ERR(descs)) { + devres_free(dr); + return descs; + } + + *dr = descs; + devres_add(dev, dr); + + return descs; +} +EXPORT_SYMBOL_GPL(devm_fwnode_gpiod_get_array); + /** * devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional() * @dev: GPIO consumer diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 679ed764cb14..dbb39e6bb568 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -4469,6 +4469,33 @@ struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode, } EXPORT_SYMBOL_GPL(fwnode_gpiod_get_index); +/** + * fwnode_gpiod_get_array - obtain multiple GPIOs from a multi-index GPIO function + * @fwnode: handle of the firmware node + * @con_id: function within the GPIO consumer + * @flags: GPIO initialization flags + * + * This function can be used for drivers that get their configuration + * from opaque firmware. + * + * The function properly finds the corresponding GPIOs using whatever is the + * underlying firmware interface and then makes sure that the GPIO + * descriptors are requested before they are returned to the caller. + * + * Returns: + * On successful request the GPIO descriptors are configured in accordance with + * provided @flags. + * + * In case of error an ERR_PTR() is returned. + */ +struct gpio_descs *fwnode_gpiod_get_array(struct fwnode_handle *fwnode, + const char *con_id, + enum gpiod_flags flags) +{ + return gpiod_get_array_by_fwnode(NULL, fwnode, con_id, flags); +} +EXPORT_SYMBOL_GPL(fwnode_gpiod_get_array); + /** * gpiod_count - return the number of GPIOs associated with a device / function * @dev: GPIO consumer, can be NULL for system-global GPIOs @@ -4731,21 +4758,8 @@ static void gpiochip_free_hogs(struct gpio_chip *gc) gpiochip_free_own_desc(desc); } -/** - * gpiod_get_array - obtain multiple GPIOs from a multi-index GPIO function - * @dev: GPIO consumer, can be NULL for system-global GPIOs - * @con_id: function within the GPIO consumer - * @flags: optional GPIO initialization flags - * - * This function acquires all the GPIOs defined under a given function. - * - * Returns: - * The GPIO descriptors corresponding to the function @con_id of device - * dev, -ENOENT if no GPIO has been assigned to the requested function, - * or another IS_ERR() code if an error occurred while trying to acquire - * the GPIOs. - */ -struct gpio_descs *__must_check gpiod_get_array(struct device *dev, +static struct gpio_descs *__gpiod_get_array(struct device *dev, + struct fwnode_handle *fwnode, const char *con_id, enum gpiod_flags flags) { @@ -4766,7 +4780,12 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev, return ERR_PTR(-ENOMEM); for (descs->ndescs = 0; descs->ndescs < count; descs->ndescs++) { - desc = gpiod_get_index(dev, con_id, descs->ndescs, flags); + if (fwnode) + desc = gpiod_find_and_request(dev, fwnode, con_id, descs->ndescs, + flags, NULL, false); + else + desc = gpiod_get_index(dev, con_id, descs->ndescs, flags); + if (IS_ERR(desc)) { gpiod_put_array(descs); return ERR_CAST(desc); @@ -4858,8 +4877,53 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev, *array_info->invert_mask); return descs; } + +/** + * gpiod_get_array - obtain multiple GPIOs from a multi-index GPIO function + * @dev: GPIO consumer, can be NULL for system-global GPIOs + * @con_id: function within the GPIO consumer + * @flags: optional GPIO initialization flags + * + * This function acquires all the GPIOs defined under a given function. + * + * Returns: + * The GPIO descriptors corresponding to the function @con_id of device + * dev, -ENOENT if no GPIO has been assigned to the requested function, + * or another IS_ERR() code if an error occurred while trying to acquire + * the GPIOs. + */ +struct gpio_descs *__must_check gpiod_get_array(struct device *dev, + const char *con_id, + enum gpiod_flags flags) +{ + return __gpiod_get_array(dev, NULL, con_id, flags); +} EXPORT_SYMBOL_GPL(gpiod_get_array); +/** + * gpiod_get_array_by_fwnode - obtain multiple GPIOs from a multi-index GPIO function + * @dev: GPIO consumer, can be NULL for system-global GPIOs + * @fwnode: Firmware node to lookup + * @con_id: function within the GPIO consumer + * @flags: optional GPIO initialization flags + * + * This function acquires all the GPIOs defined under a given function. + * + * Returns: + * The GPIO descriptors corresponding to the function @con_id of device + * dev, -ENOENT if no GPIO has been assigned to the requested function, + * or another IS_ERR() code if an error occurred while trying to acquire + * the GPIOs. + */ +struct gpio_descs *__must_check gpiod_get_array_by_fwnode(struct device *dev, + struct fwnode_handle *fwnode, + const char *con_id, + enum gpiod_flags flags) +{ + return __gpiod_get_array(dev, fwnode, con_id, flags); +} +EXPORT_SYMBOL_GPL(gpiod_get_array_by_fwnode); + /** * gpiod_get_array_optional - obtain multiple GPIOs from a multi-index GPIO * function diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index db2dfbae8edb..7143bf7045ce 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -80,6 +80,10 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev, struct gpio_descs *__must_check gpiod_get_array_optional(struct device *dev, const char *con_id, enum gpiod_flags flags); +struct gpio_descs *__must_check gpiod_get_array_by_fwnode(struct device *dev, + struct fwnode_handle *fwnode, + const char *con_id, + enum gpiod_flags flags); void gpiod_put(struct gpio_desc *desc); void gpiod_put_array(struct gpio_descs *descs); @@ -175,11 +179,18 @@ struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode, const char *con_id, int index, enum gpiod_flags flags, const char *label); +struct gpio_descs *fwnode_gpiod_get_array(struct fwnode_handle *fwnode, + const char *con_id, + enum gpiod_flags flags); struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev, struct fwnode_handle *child, const char *con_id, int index, enum gpiod_flags flags, const char *label); +struct gpio_descs *devm_fwnode_gpiod_get_array(struct device *dev, + struct fwnode_handle *fwnode, + const char *con_id, + enum gpiod_flags flags); #else /* CONFIG_GPIOLIB */ @@ -548,6 +559,14 @@ struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode, return ERR_PTR(-ENOSYS); } +static inline +struct gpio_descs *fwnode_gpiod_get_array(struct fwnode_handle *fwnode, + const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + static inline struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev, struct fwnode_handle *fwnode, @@ -558,6 +577,15 @@ struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev, return ERR_PTR(-ENOSYS); } +static inline +struct gpio_descs *devm_fwnode_gpiod_get_array(struct device *dev, + struct fwnode_handle *fwnode, + const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + #endif /* CONFIG_GPIOLIB */ static inline -- 2.25.1