gpiolib: Split GPIO flags parsing and GPIO configuration
When requesting a GPIO through the legacy or the gpiod_* API the gpiochip request operation is first called and then the GPIO flags are parsed and the GPIO is configured. This prevents the gpiochip from rejecting the request if the flags are not supported by the device. To fix this split the parse-and-configure operation in two and parse flags before requesting the GPIO. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
98c85d583a
commit
923b93e451
2 changed files with 40 additions and 20 deletions
|
@ -28,10 +28,6 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
|
|||
if (!desc && gpio_is_valid(gpio))
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
err = gpiod_request(desc, label);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (flags & GPIOF_OPEN_DRAIN)
|
||||
set_bit(FLAG_OPEN_DRAIN, &desc->flags);
|
||||
|
||||
|
@ -41,6 +37,10 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
|
|||
if (flags & GPIOF_ACTIVE_LOW)
|
||||
set_bit(FLAG_ACTIVE_LOW, &desc->flags);
|
||||
|
||||
err = gpiod_request(desc, label);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (flags & GPIOF_DIR_IN)
|
||||
err = gpiod_direction_input(desc);
|
||||
else
|
||||
|
|
|
@ -927,6 +927,14 @@ static int __gpiod_request(struct gpio_desc *desc, const char *label)
|
|||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
}
|
||||
done:
|
||||
if (status < 0) {
|
||||
/* Clear flags that might have been set by the caller before
|
||||
* requesting the GPIO.
|
||||
*/
|
||||
clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
|
||||
clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
|
||||
clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
@ -2041,13 +2049,28 @@ struct gpio_desc *__must_check gpiod_get_optional(struct device *dev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_get_optional);
|
||||
|
||||
/**
|
||||
* gpiod_parse_flags - helper function to parse GPIO lookup flags
|
||||
* @desc: gpio to be setup
|
||||
* @lflags: gpio_lookup_flags - returned from of_find_gpio() or
|
||||
* of_get_gpio_hog()
|
||||
*
|
||||
* Set the GPIO descriptor flags based on the given GPIO lookup flags.
|
||||
*/
|
||||
static void gpiod_parse_flags(struct gpio_desc *desc, unsigned long lflags)
|
||||
{
|
||||
if (lflags & GPIO_ACTIVE_LOW)
|
||||
set_bit(FLAG_ACTIVE_LOW, &desc->flags);
|
||||
if (lflags & GPIO_OPEN_DRAIN)
|
||||
set_bit(FLAG_OPEN_DRAIN, &desc->flags);
|
||||
if (lflags & GPIO_OPEN_SOURCE)
|
||||
set_bit(FLAG_OPEN_SOURCE, &desc->flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiod_configure_flags - helper function to configure a given GPIO
|
||||
* @desc: gpio whose value will be assigned
|
||||
* @con_id: function within the GPIO consumer
|
||||
* @lflags: gpio_lookup_flags - returned from of_find_gpio() or
|
||||
* of_get_gpio_hog()
|
||||
* @dflags: gpiod_flags - optional GPIO initialization flags
|
||||
*
|
||||
* Return 0 on success, -ENOENT if no GPIO has been assigned to the
|
||||
|
@ -2055,17 +2078,10 @@ EXPORT_SYMBOL_GPL(gpiod_get_optional);
|
|||
* occurred while trying to acquire the GPIO.
|
||||
*/
|
||||
static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
|
||||
unsigned long lflags, enum gpiod_flags dflags)
|
||||
enum gpiod_flags dflags)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (lflags & GPIO_ACTIVE_LOW)
|
||||
set_bit(FLAG_ACTIVE_LOW, &desc->flags);
|
||||
if (lflags & GPIO_OPEN_DRAIN)
|
||||
set_bit(FLAG_OPEN_DRAIN, &desc->flags);
|
||||
if (lflags & GPIO_OPEN_SOURCE)
|
||||
set_bit(FLAG_OPEN_SOURCE, &desc->flags);
|
||||
|
||||
/* No particular flag request, return here... */
|
||||
if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) {
|
||||
pr_debug("no flags found for %s\n", con_id);
|
||||
|
@ -2132,11 +2148,13 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
|
|||
return desc;
|
||||
}
|
||||
|
||||
gpiod_parse_flags(desc, lookupflags);
|
||||
|
||||
status = gpiod_request(desc, con_id);
|
||||
if (status < 0)
|
||||
return ERR_PTR(status);
|
||||
|
||||
status = gpiod_configure_flags(desc, con_id, lookupflags, flags);
|
||||
status = gpiod_configure_flags(desc, con_id, flags);
|
||||
if (status < 0) {
|
||||
dev_dbg(dev, "setup of GPIO %s failed\n", con_id);
|
||||
gpiod_put(desc);
|
||||
|
@ -2190,14 +2208,14 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
|
|||
if (IS_ERR(desc))
|
||||
return desc;
|
||||
|
||||
ret = gpiod_request(desc, NULL);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
/* Only value flag can be set from both DT and ACPI is active_low */
|
||||
if (active_low)
|
||||
set_bit(FLAG_ACTIVE_LOW, &desc->flags);
|
||||
|
||||
ret = gpiod_request(desc, NULL);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return desc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod);
|
||||
|
@ -2250,6 +2268,8 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
|
|||
chip = gpiod_to_chip(desc);
|
||||
hwnum = gpio_chip_hwgpio(desc);
|
||||
|
||||
gpiod_parse_flags(desc, lflags);
|
||||
|
||||
local_desc = gpiochip_request_own_desc(chip, hwnum, name);
|
||||
if (IS_ERR(local_desc)) {
|
||||
pr_err("requesting hog GPIO %s (chip %s, offset %d) failed\n",
|
||||
|
@ -2257,7 +2277,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
|
|||
return PTR_ERR(local_desc);
|
||||
}
|
||||
|
||||
status = gpiod_configure_flags(desc, name, lflags, dflags);
|
||||
status = gpiod_configure_flags(desc, name, dflags);
|
||||
if (status < 0) {
|
||||
pr_err("setup of hog GPIO %s (chip %s, offset %d) failed\n",
|
||||
name, chip->label, hwnum);
|
||||
|
|
Loading…
Reference in a new issue