diff options
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r-- | drivers/gpio/gpiolib.c | 36 |
1 files changed, 32 insertions, 4 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e806cd9a14ba..b393dbab1844 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -218,6 +218,14 @@ int gpiod_get_direction(struct gpio_desc *desc) chip = gpiod_to_chip(desc); offset = gpio_chip_hwgpio(desc); + /* + * Open drain emulation using input mode may incorrectly report + * input here, fix that up. + */ + if (test_bit(FLAG_OPEN_DRAIN, &desc->flags) && + test_bit(FLAG_IS_OUT, &desc->flags)) + return 0; + if (!chip->get_direction) return -ENOTSUPP; @@ -1444,6 +1452,7 @@ err_remove_of_chip: gpiochip_free_hogs(chip); of_gpiochip_remove(chip); err_free_gpiochip_mask: + gpiochip_remove_pin_ranges(chip); gpiochip_free_valid_mask(chip); err_remove_from_list: spin_lock_irqsave(&gpio_lock, flags); @@ -1499,8 +1508,8 @@ void gpiochip_remove(struct gpio_chip *chip) gdev->chip = NULL; gpiochip_irqchip_remove(chip); acpi_gpiochip_remove(chip); - gpiochip_remove_pin_ranges(chip); of_gpiochip_remove(chip); + gpiochip_remove_pin_ranges(chip); gpiochip_free_valid_mask(chip); /* * We accept no more calls into the driver from this point, so @@ -1875,9 +1884,16 @@ static void gpiochip_irq_disable(struct irq_data *d) { struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + /* + * Since we override .irq_disable() we need to mimic the + * behaviour of __irq_disable() in irq/chip.c. + * First call .irq_disable() if it exists, else mimic the + * behaviour of mask_irq() which calls .irq_mask() if + * it exists. + */ if (chip->irq.irq_disable) chip->irq.irq_disable(d); - else + else if (chip->irq.chip->irq_mask) chip->irq.chip->irq_mask(d); gpiochip_disable_irq(chip, d->hwirq); } @@ -2869,6 +2885,17 @@ int gpiod_is_active_low(const struct gpio_desc *desc) } EXPORT_SYMBOL_GPL(gpiod_is_active_low); +/** + * gpiod_toggle_active_low - toggle whether a GPIO is active-low or not + * @desc: the gpio descriptor to change + */ +void gpiod_toggle_active_low(struct gpio_desc *desc) +{ + VALIDATE_DESC_VOID(desc); + change_bit(FLAG_ACTIVE_LOW, &desc->flags); +} +EXPORT_SYMBOL_GPL(gpiod_toggle_active_low); + /* I/O calls are only valid after configuration completed; the relevant * "is this a valid GPIO" error checks should already have been done. * @@ -3982,8 +4009,9 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, if (chip->ngpio <= p->chip_hwnum) { dev_err(dev, - "requested GPIO %d is out of range [0..%d] for chip %s\n", - idx, chip->ngpio, chip->label); + "requested GPIO %u (%u) is out of range [0..%u] for chip %s\n", + idx, p->chip_hwnum, chip->ngpio - 1, + chip->label); return ERR_PTR(-EINVAL); } |