Commit ae9847f4 authored by Ricardo Ribalda Delgado's avatar Ricardo Ribalda Delgado Committed by Linus Walleij
Browse files

gpiolib: Fix gpio_direction_* for single direction GPIOs



GPIOs with no programmable direction are not required to implement
direction_output nor direction_input.

If we try to set an output direction on an output-only GPIO or input
direction on an input-only GPIO simply return 0.

This allows this single direction GPIO to be used by libgpiod.

Signed-off-by: default avatarRicardo Ribalda Delgado <ricardo.ribalda@gmail.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 32d064a1
Loading
Loading
Loading
Loading
+28 −8
Original line number Diff line number Diff line
@@ -2543,19 +2543,27 @@ EXPORT_SYMBOL_GPL(gpiochip_free_own_desc);
int gpiod_direction_input(struct gpio_desc *desc)
{
	struct gpio_chip	*chip;
	int			status = -EINVAL;
	int			status = 0;

	VALIDATE_DESC(desc);
	chip = desc->gdev->chip;

	if (!chip->get || !chip->direction_input) {
	if (!chip->get && chip->direction_input) {
		gpiod_warn(desc,
			"%s: missing get() or direction_input() operations\n",
			"%s: missing get() and direction_input() operations\n",
			__func__);
		return -EIO;
	}

	if (chip->direction_input) {
		status = chip->direction_input(chip, gpio_chip_hwgpio(desc));
	} else if (chip->get_direction &&
		  (chip->get_direction(chip, gpio_chip_hwgpio(desc)) != 1)) {
		gpiod_warn(desc,
			"%s: missing direction_input() operation\n",
			__func__);
		return -EIO;
	}
	if (status == 0)
		clear_bit(FLAG_IS_OUT, &desc->flags);

@@ -2577,16 +2585,28 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value)
{
	struct gpio_chip *gc = desc->gdev->chip;
	int val = !!value;
	int ret;
	int ret = 0;

	if (!gc->set || !gc->direction_output) {
	if (!gc->set && !gc->direction_output) {
		gpiod_warn(desc,
		       "%s: missing set() or direction_output() operations\n",
		       "%s: missing set() and direction_output() operations\n",
		       __func__);
		return -EIO;
	}

	if (gc->direction_output) {
		ret = gc->direction_output(gc, gpio_chip_hwgpio(desc), val);
	} else {
		if (gc->get_direction &&
		    gc->get_direction(gc, gpio_chip_hwgpio(desc))) {
			gpiod_warn(desc,
				"%s: missing direction_output() operation\n",
				__func__);
			return -EIO;
		}
		gc->set(gc, gpio_chip_hwgpio(desc), val);
	}

	if (!ret)
		set_bit(FLAG_IS_OUT, &desc->flags);
	trace_gpio_value(desc_to_gpio(desc), 0, val);