On Wednesday 14 January 2015 14:11:16 Alexandre Courbot wrote: > On Sat, Jan 10, 2015 at 12:19 AM, Rojhalat Ibrahim <imr@xxxxxxxxxxx> wrote: > > Introduce new functions for conveniently obtaining and disposing of an entire > > array of GPIOs with one function call. > > Excellent, thanks for following up with this! :) > > > > > Suggested-by: Alexandre Courbot <acourbot@xxxxxxxxxx> > > Signed-off-by: Rojhalat Ibrahim <imr@xxxxxxxxxxx> > > --- > > Documentation/gpio/consumer.txt | 28 ++++++++++++- > > drivers/gpio/gpiolib.c | 84 ++++++++++++++++++++++++++++++++++++++++ > > include/linux/gpio/consumer.h | 42 ++++++++++++++++++++ > > 3 files changed, 153 insertions(+), 1 deletion(-) > > > > diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt > > index c67f806..d02f341 100644 > > --- a/Documentation/gpio/consumer.txt > > +++ b/Documentation/gpio/consumer.txt > > @@ -58,7 +58,6 @@ pattern where a GPIO is optional, the gpiod_get_optional() and > > gpiod_get_index_optional() functions can be used. These functions return NULL > > instead of -ENOENT if no GPIO has been assigned to the requested function: > > > > - > > struct gpio_desc *gpiod_get_optional(struct device *dev, > > const char *con_id, > > enum gpiod_flags flags) > > @@ -68,6 +67,29 @@ instead of -ENOENT if no GPIO has been assigned to the requested function: > > unsigned int index, > > enum gpiod_flags flags) > > > > +For a function using multiple GPIOs all of those can be obtained with one call: > > + > > + int gpiod_get_array(struct device *dev, > > + const char *con_id, > > + struct gpio_desc **desc_array, > > + unsigned int count, > > + enum gpiod_flags flags) > > + > > +In this case an array for storing the GPIO descriptors and the number of GPIOs > > +are required as additional arguments. This function either returns the > > +requested number of GPIOs or an error code. It will not return a positive > > +number if some but not all of the requested GPIOs could be obtained. > > I wonder if the following interface would not be more convenient, at > least for the most common cases: > > struct gpiod_descs *gpiod_get_array(struct device *dev, const char > *con_id, enum gpiod_flags flags); > > Which would *allocate* the array of descriptors to the right number of > GPIOs and return them all. The current way of doing requires the user > to 1) figure out how many GPIOs there are under (dev, con_id), 2) > allocate a the GPIO array and 3) call this function. The array must > also be explicitly freed after calling gpiod_put_array(). > > struct gpiod_descs would be something like this: > > struct gpiod_descs { > unsigned count; > struct gpiod_desc*[]; > } > > It uses a zero-length array to store the actual descriptors and > carries the count so the user does not have to remember it (it will > always be needed anyway, and that way we don't have to pass it > explicitly to gpiod_put_array()). > > The nice thing with this interface is that it works identically to > gpiod_get(), excepted it can handle 1 GPIO or more. This would be > handy in order to implement sysfs v2 on top of it (see > https://lkml.org/lkml/2015/1/3/50). > > We could even have a macro to iterate over the GPIOs: > > #define for_each_gpio(gpiod_descs, gpiod_desc) ... > I see your point. It certainly makes sense. The gpiod_get_array function would have to not only allocate the array of descriptors but also the struct containing the pointer to the array. Alternatively gpiod_get_array could return a struct gpiod_descs instead of a pointer to such a struct: struct gpiod_descs gpiod_get_array(struct device *dev, const char *con_id, enum gpiod_flags flags); Errors could be returned either as a negative count or in an additional struct member. Would that also be an acceptable interface? Or should a gpiod_get_ function always return a pointer? > If you think your current interface is necessary because users need to > work with already-allocated arrays of descriptors, could you then > rename it under a more "private" name (maybe > gpiod_fill_array/gpiod_free_array?) and build the > gpiod_get_array/gpiod_put_array I suggest on top of it? > I think that's unnecessary for now. > Also for the sake of completeness, may I suggest adding the following > function to the gpiod interface: > > int gpiod_count(struct device *dev, const char *con_id); > > Which returns the number of GPIOs that are declared for (dev, con_id)? > Right now gpiod_get_array() can only be used properly under the device > tree (which provides of_gpio_named_count()), but we also need to > enable it for ACPI and platform data. > > Having this function will allow users of gpiod_get_index() to know the > boundaries they have to work with, no matter how the GPIO mappings are > provided. It will also be needed if you implement the version of > gpiod_get_array() I suggest. > > In your patch 2/2, you will then also want to replace the call to > of_gpio_count() in mdio_mux_gpio_probe() by a call to gpiod_count(). > I'll look into that. > > +The following function behaves differently: > > + > > + int gpiod_get_array_optional(struct device *dev, > > + const char *con_id, > > + struct gpio_desc **desc_array, > > + unsigned int could, > > + enum gpiod_flags flags) > > + > > +This one returns the number of GPIOs actually available which can be smaller > > +than the requested number or even 0. > > There is no user for this function yet but I agree it is good to have. > So for the interface you propose that would mean: gpiod_get_array returns with exactly the number of GPIO descriptors as gpiod_count returns or an error code whereas gpiod_get_array_optional can also return with fewer or no descriptors at all. Right? Or is one of the two unnecessary? > > + > > Device-managed variants of these functions are also defined: > > Do you plan to also add devm variants of the new get_array() function(s)? > I probably should. Need to look into it. > > > > struct gpio_desc *devm_gpiod_get(struct device *dev, const char *con_id, > > @@ -91,6 +113,10 @@ A GPIO descriptor can be disposed of using the gpiod_put() function: > > > > void gpiod_put(struct gpio_desc *desc) > > > > +For an array of GPIOs this function can be used: > > + > > + void gpiod_put_array(struct gpio_desc **desc_array, unsigned int count) > > + > > It is strictly forbidden to use a descriptor after calling this function. The > > This paragraph will probably require a s/this/these to be gramatically correct. > Right. > > device-managed variant is, unsurprisingly: > > > > diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c > > index 56b7c5d..d45fa9c 100644 > > --- a/drivers/gpio/gpiolib.c > > +++ b/drivers/gpio/gpiolib.c > > @@ -1925,6 +1925,76 @@ struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev, > > EXPORT_SYMBOL_GPL(__gpiod_get_index_optional); > > > > /** > > + * 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 > > + * @desc_array: descriptor array for the acquired GPIOs > > + * @count: number of GPIOs to obtain in the consumer > > + * @flags: optional GPIO initialization flags > > + * > > + * This function obtains the specified number of GPIOs starting with index 0 > > + * for functions that define several GPIOs. > > + * > > + * Return the actual number of acquired GPIOs, -ENOENT if the actual number of > > + * GPIOs assigned to the requested function is smaller than @count, > > + * or another IS_ERR() code if an error occurred while trying to acquire the > > + * GPIOs. > > + */ > > +int __must_check __gpiod_get_array(struct device *dev, const char *con_id, > > + struct gpio_desc **desc_array, > > + unsigned int count, > > + enum gpiod_flags flags) > > +{ > > + int r; > > + > > + r = gpiod_get_array_optional(dev, con_id, desc_array, count, flags); > > + if ((r >= 0) && (r != count)) { > > + gpiod_put_array(desc_array, r); > > + return -ENOENT; > > + } > > + return r; > > +} > > +EXPORT_SYMBOL_GPL(__gpiod_get_array); > > + > > +/** > > + * gpiod_get_array_optional - 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 > > + * @desc_array: descriptor array for the acquired GPIOs > > + * @count: number of GPIOs to obtain in the consumer > > + * @flags: optional GPIO initialization flags > > + * > > + * This is equivalent to gpiod_get_array(), except that when the actual number > > + * of GPIOs assigned to the requested function is smaller than @count it will > > + * not return an error but the number of GPIOs actually available. > > + */ > > +int __must_check __gpiod_get_array_optional(struct device *dev, > > + const char *con_id, > > + struct gpio_desc **desc_array, > > + unsigned int count, > > + enum gpiod_flags flags) > > +{ > > + struct gpio_desc *desc; > > + unsigned int n; > > + > > + for (n = 0; n < count; ) { > > + desc = gpiod_get_index(dev, con_id, n, flags); > > + if (IS_ERR(desc)) { > > + if (PTR_ERR(desc) != -ENOENT) { > > + gpiod_put_array(desc_array, n); > > + return PTR_ERR(desc); > > + } > > + break; > > + } > > + desc_array[n] = desc; > > + n++; > > + } > > + return n; > > +} > > +EXPORT_SYMBOL_GPL(__gpiod_get_array_optional); > > + > > +/** > > * gpiod_put - dispose of a GPIO descriptor > > * @desc: GPIO descriptor to dispose of > > * > > @@ -1936,6 +2006,20 @@ void gpiod_put(struct gpio_desc *desc) > > } > > EXPORT_SYMBOL_GPL(gpiod_put); > > > > +/** > > + * gpiod_put_array - dispose of multiple GPIO descriptors > > + * @desc_array: GPIO descriptor array > > + * @count: number of GPIOs in the array > > + */ > > +void gpiod_put_array(struct gpio_desc **desc_array, unsigned int count) > > +{ > > + unsigned int n; > > + > > + for (n = 0; n < count; n++) > > + gpiod_put(desc_array[n]); > > +} > > +EXPORT_SYMBOL_GPL(gpiod_put_array); > > The implementation looks good to me. I'd just like you to consider the > alternative interface I propose, as I suspect it might make the life > of users easier. > Thanks for reviewing this. -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html