Commit 923b93e4 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Linus Walleij

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: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 98c85d58
...@@ -28,10 +28,6 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) ...@@ -28,10 +28,6 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
if (!desc && gpio_is_valid(gpio)) if (!desc && gpio_is_valid(gpio))
return -EPROBE_DEFER; return -EPROBE_DEFER;
err = gpiod_request(desc, label);
if (err)
return err;
if (flags & GPIOF_OPEN_DRAIN) if (flags & GPIOF_OPEN_DRAIN)
set_bit(FLAG_OPEN_DRAIN, &desc->flags); set_bit(FLAG_OPEN_DRAIN, &desc->flags);
...@@ -41,6 +37,10 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) ...@@ -41,6 +37,10 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
if (flags & GPIOF_ACTIVE_LOW) if (flags & GPIOF_ACTIVE_LOW)
set_bit(FLAG_ACTIVE_LOW, &desc->flags); set_bit(FLAG_ACTIVE_LOW, &desc->flags);
err = gpiod_request(desc, label);
if (err)
return err;
if (flags & GPIOF_DIR_IN) if (flags & GPIOF_DIR_IN)
err = gpiod_direction_input(desc); err = gpiod_direction_input(desc);
else else
......
...@@ -927,6 +927,14 @@ static int __gpiod_request(struct gpio_desc *desc, const char *label) ...@@ -927,6 +927,14 @@ static int __gpiod_request(struct gpio_desc *desc, const char *label)
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
} }
done: 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); spin_unlock_irqrestore(&gpio_lock, flags);
return status; return status;
} }
...@@ -2041,13 +2049,28 @@ struct gpio_desc *__must_check gpiod_get_optional(struct device *dev, ...@@ -2041,13 +2049,28 @@ struct gpio_desc *__must_check gpiod_get_optional(struct device *dev,
} }
EXPORT_SYMBOL_GPL(gpiod_get_optional); 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 * gpiod_configure_flags - helper function to configure a given GPIO
* @desc: gpio whose value will be assigned * @desc: gpio whose value will be assigned
* @con_id: function within the GPIO consumer * @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 * @dflags: gpiod_flags - optional GPIO initialization flags
* *
* Return 0 on success, -ENOENT if no GPIO has been assigned to the * Return 0 on success, -ENOENT if no GPIO has been assigned to the
...@@ -2055,17 +2078,10 @@ EXPORT_SYMBOL_GPL(gpiod_get_optional); ...@@ -2055,17 +2078,10 @@ EXPORT_SYMBOL_GPL(gpiod_get_optional);
* occurred while trying to acquire the GPIO. * occurred while trying to acquire the GPIO.
*/ */
static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, 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; 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... */ /* No particular flag request, return here... */
if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) { if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) {
pr_debug("no flags found for %s\n", con_id); 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, ...@@ -2132,11 +2148,13 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
return desc; return desc;
} }
gpiod_parse_flags(desc, lookupflags);
status = gpiod_request(desc, con_id); status = gpiod_request(desc, con_id);
if (status < 0) if (status < 0)
return ERR_PTR(status); return ERR_PTR(status);
status = gpiod_configure_flags(desc, con_id, lookupflags, flags); status = gpiod_configure_flags(desc, con_id, flags);
if (status < 0) { if (status < 0) {
dev_dbg(dev, "setup of GPIO %s failed\n", con_id); dev_dbg(dev, "setup of GPIO %s failed\n", con_id);
gpiod_put(desc); gpiod_put(desc);
...@@ -2190,14 +2208,14 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, ...@@ -2190,14 +2208,14 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
if (IS_ERR(desc)) if (IS_ERR(desc))
return 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 */ /* Only value flag can be set from both DT and ACPI is active_low */
if (active_low) if (active_low)
set_bit(FLAG_ACTIVE_LOW, &desc->flags); set_bit(FLAG_ACTIVE_LOW, &desc->flags);
ret = gpiod_request(desc, NULL);
if (ret)
return ERR_PTR(ret);
return desc; return desc;
} }
EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod); EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod);
...@@ -2250,6 +2268,8 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, ...@@ -2250,6 +2268,8 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
chip = gpiod_to_chip(desc); chip = gpiod_to_chip(desc);
hwnum = gpio_chip_hwgpio(desc); hwnum = gpio_chip_hwgpio(desc);
gpiod_parse_flags(desc, lflags);
local_desc = gpiochip_request_own_desc(chip, hwnum, name); local_desc = gpiochip_request_own_desc(chip, hwnum, name);
if (IS_ERR(local_desc)) { if (IS_ERR(local_desc)) {
pr_err("requesting hog GPIO %s (chip %s, offset %d) failed\n", 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, ...@@ -2257,7 +2277,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
return PTR_ERR(local_desc); return PTR_ERR(local_desc);
} }
status = gpiod_configure_flags(desc, name, lflags, dflags); status = gpiod_configure_flags(desc, name, dflags);
if (status < 0) { if (status < 0) {
pr_err("setup of hog GPIO %s (chip %s, offset %d) failed\n", pr_err("setup of hog GPIO %s (chip %s, offset %d) failed\n",
name, chip->label, hwnum); name, chip->label, hwnum);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment