Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e10f72bf authored by Andrew Jeffery's avatar Andrew Jeffery Committed by Linus Walleij
Browse files

gpio: gpiolib: Generalise state persistence beyond sleep



General support for state persistence is added to gpiolib with the
introduction of a new pinconf parameter to propagate the request to
hardware. The existing persistence support for sleep is adapted to
include hardware support if the GPIO driver provides it. Persistence
continues to be enabled by default; in-kernel consumers can opt out, but
userspace (currently) does not have a choice.

The *_SLEEP_MAY_LOSE_VALUE and *_SLEEP_MAINTAIN_VALUE symbols are
renamed, dropping the SLEEP prefix to reflect that the concept is no
longer sleep-specific.  I feel that renaming to just *_MAY_LOSE_VALUE
could initially be misinterpreted, so I've further changed the symbols
to *_TRANSITORY and *_PERSISTENT to address this.

The sysfs interface is modified only to keep consistency with the
chardev interface in enforcing persistence for userspace exports.

Signed-off-by: default avatarAndrew Jeffery <andrew@aj.id.au>
Reviewed-by: default avatarCharles Keepax <ckeepax@opensource.cirrus.com>
Acked-by: default avatarRob Herring <robh@kernel.org>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent e2843cb6
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -153,8 +153,8 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
			*flags |= GPIO_OPEN_SOURCE;
	}

	if (of_flags & OF_GPIO_SLEEP_MAY_LOSE_VALUE)
		*flags |= GPIO_SLEEP_MAY_LOSE_VALUE;
	if (of_flags & OF_GPIO_TRANSITORY)
		*flags |= GPIO_TRANSITORY;

	return desc;
}
@@ -214,6 +214,8 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,

	if (xlate_flags & OF_GPIO_ACTIVE_LOW)
		*lflags |= GPIO_ACTIVE_LOW;
	if (xlate_flags & OF_GPIO_TRANSITORY)
		*lflags |= GPIO_TRANSITORY;

	if (of_property_read_bool(np, "input"))
		*dflags |= GPIOD_IN;
+9 −5
Original line number Diff line number Diff line
@@ -474,11 +474,15 @@ static ssize_t export_store(struct class *class,
			status = -ENODEV;
		goto done;
	}

	status = gpiod_set_transitory(desc, false);
	if (!status) {
		status = gpiod_export(desc, true);
		if (status < 0)
			gpiod_free(desc);
		else
			set_bit(FLAG_SYSFS, &desc->flags);
	}

done:
	if (status)
+57 −4
Original line number Diff line number Diff line
@@ -514,6 +514,10 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
		if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)
			set_bit(FLAG_OPEN_SOURCE, &desc->flags);

		ret = gpiod_set_transitory(desc, false);
		if (ret < 0)
			goto out_free_descs;

		/*
		 * Lines have to be requested explicitly for input
		 * or output, else the line will be treated "as is".
@@ -2529,6 +2533,49 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
}
EXPORT_SYMBOL_GPL(gpiod_set_debounce);

/**
 * gpiod_set_transitory - Lose or retain GPIO state on suspend or reset
 * @desc: descriptor of the GPIO for which to configure persistence
 * @transitory: True to lose state on suspend or reset, false for persistence
 *
 * Returns:
 * 0 on success, otherwise a negative error code.
 */
int gpiod_set_transitory(struct gpio_desc *desc, bool transitory)
{
	struct gpio_chip *chip;
	unsigned long packed;
	int gpio;
	int rc;

	/*
	 * Handle FLAG_TRANSITORY first, enabling queries to gpiolib for
	 * persistence state.
	 */
	if (transitory)
		set_bit(FLAG_TRANSITORY, &desc->flags);
	else
		clear_bit(FLAG_TRANSITORY, &desc->flags);

	/* If the driver supports it, set the persistence state now */
	chip = desc->gdev->chip;
	if (!chip->set_config)
		return 0;

	packed = pinconf_to_config_packed(PIN_CONFIG_PERSIST_STATE,
					  !transitory);
	gpio = gpio_chip_hwgpio(desc);
	rc = chip->set_config(chip, gpio, packed);
	if (rc == -ENOTSUPP) {
		dev_dbg(&desc->gdev->dev, "Persistence not supported for GPIO %d\n",
				gpio);
		return 0;
	}

	return rc;
}
EXPORT_SYMBOL_GPL(gpiod_set_transitory);

/**
 * gpiod_is_active_low - test whether a GPIO is active-low or not
 * @desc: the gpio descriptor to test
@@ -3116,8 +3163,7 @@ bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset)
	if (offset >= chip->ngpio)
		return false;

	return !test_bit(FLAG_SLEEP_MAY_LOSE_VALUE,
			 &chip->gpiodev->descs[offset].flags);
	return !test_bit(FLAG_TRANSITORY, &chip->gpiodev->descs[offset].flags);
}
EXPORT_SYMBOL_GPL(gpiochip_line_is_persistent);

@@ -3554,8 +3600,10 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,

	if (lflags & GPIO_OPEN_SOURCE)
		set_bit(FLAG_OPEN_SOURCE, &desc->flags);
	if (lflags & GPIO_SLEEP_MAY_LOSE_VALUE)
		set_bit(FLAG_SLEEP_MAY_LOSE_VALUE, &desc->flags);

	status = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY));
	if (status < 0)
		return status;

	/* No particular flag request, return here... */
	if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) {
@@ -3669,6 +3717,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
	bool active_low = false;
	bool single_ended = false;
	bool open_drain = false;
	bool transitory = false;
	int ret;

	if (!fwnode)
@@ -3683,6 +3732,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
			active_low = flags & OF_GPIO_ACTIVE_LOW;
			single_ended = flags & OF_GPIO_SINGLE_ENDED;
			open_drain = flags & OF_GPIO_OPEN_DRAIN;
			transitory = flags & OF_GPIO_TRANSITORY;
		}
	} else if (is_acpi_node(fwnode)) {
		struct acpi_gpio_info info;
@@ -3711,6 +3761,9 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
			lflags |= GPIO_OPEN_SOURCE;
	}

	if (transitory)
		lflags |= GPIO_TRANSITORY;

	ret = gpiod_configure_flags(desc, propname, lflags, dflags);
	if (ret < 0) {
		gpiod_put(desc);
+1 −1
Original line number Diff line number Diff line
@@ -209,7 +209,7 @@ struct gpio_desc {
#define FLAG_OPEN_SOURCE 8	/* Gpio is open source type */
#define FLAG_USED_AS_IRQ 9	/* GPIO is connected to an IRQ */
#define FLAG_IS_HOGGED	11	/* GPIO is hogged */
#define FLAG_SLEEP_MAY_LOSE_VALUE 12	/* GPIO may lose value in sleep */
#define FLAG_TRANSITORY 12	/* GPIO may lose value in sleep or reset */

	/* Connection label */
	const char		*label;
+3 −3
Original line number Diff line number Diff line
@@ -29,8 +29,8 @@
#define GPIO_OPEN_DRAIN (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_DRAIN)
#define GPIO_OPEN_SOURCE (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_SOURCE)

/* Bit 3 express GPIO suspend/resume persistence */
#define GPIO_SLEEP_MAINTAIN_VALUE 0
#define GPIO_SLEEP_MAY_LOSE_VALUE 8
/* Bit 3 express GPIO suspend/resume and reset persistence */
#define GPIO_PERSISTENT 0
#define GPIO_TRANSITORY 8

#endif
Loading