Commit d872bed8 authored by Philipp Zabel's avatar Philipp Zabel
Browse files

reset: Add devres helpers to request pre-deasserted reset controls



Add devres helpers

 - devm_reset_control_bulk_get_exclusive_deasserted
 - devm_reset_control_bulk_get_optional_exclusive_deasserted
 - devm_reset_control_bulk_get_optional_shared_deasserted
 - devm_reset_control_bulk_get_shared_deasserted
 - devm_reset_control_get_exclusive_deasserted
 - devm_reset_control_get_optional_exclusive_deasserted
 - devm_reset_control_get_optional_shared_deasserted
 - devm_reset_control_get_shared_deasserted

to request and immediately deassert reset controls. During cleanup,
reset_control_assert() will be called automatically on the returned
reset controls.

Acked-by: default avatarUwe Kleine-König <u.kleine-koenig@baylibre.com>
Link: https://lore.kernel.org/r/20240925-reset-get-deasserted-v2-2-b3601bbd0458@pengutronix.de


Signed-off-by: default avatarPhilipp Zabel <p.zabel@pengutronix.de>
parent dad35f7d
Loading
Loading
Loading
Loading
+46 −2
Original line number Diff line number Diff line
@@ -1236,23 +1236,46 @@ static void devm_reset_control_release(struct device *dev, void *res)
	reset_control_put(*(struct reset_control **)res);
}

static void devm_reset_control_release_deasserted(struct device *dev, void *res)
{
	struct reset_control *rstc = *(struct reset_control **)res;

	reset_control_assert(rstc);
	reset_control_put(rstc);
}

struct reset_control *
__devm_reset_control_get(struct device *dev, const char *id, int index,
			 enum reset_control_flags flags)
{
	struct reset_control **ptr, *rstc;
	bool deasserted = flags & RESET_CONTROL_FLAGS_BIT_DEASSERTED;

	ptr = devres_alloc(devm_reset_control_release, sizeof(*ptr),
	ptr = devres_alloc(deasserted ? devm_reset_control_release_deasserted :
			   devm_reset_control_release, sizeof(*ptr),
			   GFP_KERNEL);
	if (!ptr)
		return ERR_PTR(-ENOMEM);

	flags &= ~RESET_CONTROL_FLAGS_BIT_DEASSERTED;

	rstc = __reset_control_get(dev, id, index, flags);
	if (IS_ERR_OR_NULL(rstc)) {
		devres_free(ptr);
		return rstc;
	}

	if (deasserted) {
		int ret;

		ret = reset_control_deassert(rstc);
		if (ret) {
			reset_control_put(rstc);
			devres_free(ptr);
			return ERR_PTR(ret);
		}
	}

	*ptr = rstc;
	devres_add(dev, ptr);

@@ -1272,24 +1295,45 @@ static void devm_reset_control_bulk_release(struct device *dev, void *res)
	reset_control_bulk_put(devres->num_rstcs, devres->rstcs);
}

static void devm_reset_control_bulk_release_deasserted(struct device *dev, void *res)
{
	struct reset_control_bulk_devres *devres = res;

	reset_control_bulk_assert(devres->num_rstcs, devres->rstcs);
	reset_control_bulk_put(devres->num_rstcs, devres->rstcs);
}

int __devm_reset_control_bulk_get(struct device *dev, int num_rstcs,
				  struct reset_control_bulk_data *rstcs,
				  enum reset_control_flags flags)
{
	struct reset_control_bulk_devres *ptr;
	bool deasserted = flags & RESET_CONTROL_FLAGS_BIT_DEASSERTED;
	int ret;

	ptr = devres_alloc(devm_reset_control_bulk_release, sizeof(*ptr),
	ptr = devres_alloc(deasserted ? devm_reset_control_bulk_release_deasserted :
			   devm_reset_control_bulk_release, sizeof(*ptr),
			   GFP_KERNEL);
	if (!ptr)
		return -ENOMEM;

	flags &= ~RESET_CONTROL_FLAGS_BIT_DEASSERTED;

	ret = __reset_control_bulk_get(dev, num_rstcs, rstcs, flags);
	if (ret < 0) {
		devres_free(ptr);
		return ret;
	}

	if (deasserted) {
		ret = reset_control_bulk_deassert(num_rstcs, rstcs);
		if (ret) {
			reset_control_bulk_put(num_rstcs, rstcs);
			devres_free(ptr);
			return ret;
		}
	}

	ptr->num_rstcs = num_rstcs;
	ptr->rstcs = rstcs;
	devres_add(dev, ptr);
+113 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ struct reset_control_bulk_data {
#define RESET_CONTROL_FLAGS_BIT_SHARED		BIT(0)	/* not exclusive */
#define RESET_CONTROL_FLAGS_BIT_OPTIONAL	BIT(1)
#define RESET_CONTROL_FLAGS_BIT_ACQUIRED	BIT(2)	/* iff exclusive, not released */
#define RESET_CONTROL_FLAGS_BIT_DEASSERTED	BIT(3)

/**
 * enum reset_control_flags - Flags that can be passed to the reset_control_get functions
@@ -35,21 +36,35 @@ struct reset_control_bulk_data {
 *                    These values cannot be OR'd.
 *
 * @RESET_CONTROL_EXCLUSIVE:				exclusive, acquired,
 * @RESET_CONTROL_EXCLUSIVE_DEASSERTED:			exclusive, acquired, deasserted
 * @RESET_CONTROL_EXCLUSIVE_RELEASED:			exclusive, released,
 * @RESET_CONTROL_SHARED:				shared
 * @RESET_CONTROL_SHARED_DEASSERTED:			shared, deasserted
 * @RESET_CONTROL_OPTIONAL_EXCLUSIVE:			optional, exclusive, acquired
 * @RESET_CONTROL_OPTIONAL_EXCLUSIVE_DEASSERTED:	optional, exclusive, acquired, deasserted
 * @RESET_CONTROL_OPTIONAL_EXCLUSIVE_RELEASED:		optional, exclusive, released
 * @RESET_CONTROL_OPTIONAL_SHARED:			optional, shared
 * @RESET_CONTROL_OPTIONAL_SHARED_DEASSERTED:		optional, shared, deasserted
 */
enum reset_control_flags {
	RESET_CONTROL_EXCLUSIVE				= RESET_CONTROL_FLAGS_BIT_ACQUIRED,
	RESET_CONTROL_EXCLUSIVE_DEASSERTED		= RESET_CONTROL_FLAGS_BIT_ACQUIRED |
							  RESET_CONTROL_FLAGS_BIT_DEASSERTED,
	RESET_CONTROL_EXCLUSIVE_RELEASED		= 0,
	RESET_CONTROL_SHARED				= RESET_CONTROL_FLAGS_BIT_SHARED,
	RESET_CONTROL_SHARED_DEASSERTED			= RESET_CONTROL_FLAGS_BIT_SHARED |
							  RESET_CONTROL_FLAGS_BIT_DEASSERTED,
	RESET_CONTROL_OPTIONAL_EXCLUSIVE		= RESET_CONTROL_FLAGS_BIT_OPTIONAL |
							  RESET_CONTROL_FLAGS_BIT_ACQUIRED,
	RESET_CONTROL_OPTIONAL_EXCLUSIVE_DEASSERTED	= RESET_CONTROL_FLAGS_BIT_OPTIONAL |
							  RESET_CONTROL_FLAGS_BIT_ACQUIRED |
							  RESET_CONTROL_FLAGS_BIT_DEASSERTED,
	RESET_CONTROL_OPTIONAL_EXCLUSIVE_RELEASED	= RESET_CONTROL_FLAGS_BIT_OPTIONAL,
	RESET_CONTROL_OPTIONAL_SHARED			= RESET_CONTROL_FLAGS_BIT_OPTIONAL |
							  RESET_CONTROL_FLAGS_BIT_SHARED,
	RESET_CONTROL_OPTIONAL_SHARED_DEASSERTED	= RESET_CONTROL_FLAGS_BIT_OPTIONAL |
							  RESET_CONTROL_FLAGS_BIT_SHARED |
							  RESET_CONTROL_FLAGS_BIT_DEASSERTED,
};

#ifdef CONFIG_RESET_CONTROLLER
@@ -596,6 +611,25 @@ __must_check devm_reset_control_get_exclusive(struct device *dev,
	return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_EXCLUSIVE);
}

/**
 * devm_reset_control_get_exclusive_deasserted - resource managed
 *                                    reset_control_get_exclusive() +
 *                                    reset_control_deassert()
 * @dev: device to be reset by the controller
 * @id: reset line name
 *
 * Managed reset_control_get_exclusive() + reset_control_deassert(). For reset
 * controllers returned from this function, reset_control_assert() +
 * reset_control_put() is called automatically on driver detach.
 *
 * See reset_control_get_exclusive() for more information.
 */
static inline struct reset_control * __must_check
devm_reset_control_get_exclusive_deasserted(struct device *dev, const char *id)
{
	return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_EXCLUSIVE_DEASSERTED);
}

/**
 * devm_reset_control_bulk_get_exclusive - resource managed
 *                                         reset_control_bulk_get_exclusive()
@@ -712,6 +746,25 @@ static inline struct reset_control *devm_reset_control_get_shared(
	return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_SHARED);
}

/**
 * devm_reset_control_get_shared_deasserted - resource managed
 *                                            reset_control_get_shared() +
 *                                            reset_control_deassert()
 * @dev: device to be reset by the controller
 * @id: reset line name
 *
 * Managed reset_control_get_shared() + reset_control_deassert(). For reset
 * controllers returned from this function, reset_control_assert() +
 * reset_control_put() is called automatically on driver detach.
 *
 * See devm_reset_control_get_shared() for more information.
 */
static inline struct reset_control * __must_check
devm_reset_control_get_shared_deasserted(struct device *dev, const char *id)
{
	return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_SHARED_DEASSERTED);
}

/**
 * devm_reset_control_bulk_get_shared - resource managed
 *                                      reset_control_bulk_get_shared()
@@ -732,6 +785,28 @@ devm_reset_control_bulk_get_shared(struct device *dev, int num_rstcs,
	return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, RESET_CONTROL_SHARED);
}

/**
 * devm_reset_control_bulk_get_shared_deasserted - resource managed
 *                                                 reset_control_bulk_get_shared() +
 *                                                 reset_control_bulk_deassert()
 * @dev: device to be reset by the controller
 * @num_rstcs: number of entries in rstcs array
 * @rstcs: array of struct reset_control_bulk_data with reset line names set
 *
 * Managed reset_control_bulk_get_shared() + reset_control_bulk_deassert(). For
 * reset controllers returned from this function, reset_control_bulk_assert() +
 * reset_control_bulk_put() are called automatically on driver detach.
 *
 * See devm_reset_control_bulk_get_shared() for more information.
 */
static inline int __must_check
devm_reset_control_bulk_get_shared_deasserted(struct device *dev, int num_rstcs,
					      struct reset_control_bulk_data *rstcs)
{
	return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs,
					     RESET_CONTROL_SHARED_DEASSERTED);
}

/**
 * devm_reset_control_get_optional_exclusive - resource managed
 *                                             reset_control_get_optional_exclusive()
@@ -750,6 +825,25 @@ static inline struct reset_control *devm_reset_control_get_optional_exclusive(
	return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_EXCLUSIVE);
}

/**
 * devm_reset_control_get_optional_exclusive_deasserted - resource managed
 *                                                        reset_control_get_optional_exclusive() +
 *                                                        reset_control_deassert()
 * @dev: device to be reset by the controller
 * @id: reset line name
 *
 * Managed reset_control_get_optional_exclusive() + reset_control_deassert().
 * For reset controllers returned from this function, reset_control_assert() +
 * reset_control_put() is called automatically on driver detach.
 *
 * See devm_reset_control_get_optional_exclusive() for more information.
 */
static inline struct reset_control *
devm_reset_control_get_optional_exclusive_deasserted(struct device *dev, const char *id)
{
	return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_EXCLUSIVE_DEASSERTED);
}

/**
 * devm_reset_control_bulk_get_optional_exclusive - resource managed
 *                                                  reset_control_bulk_get_optional_exclusive()
@@ -789,6 +883,25 @@ static inline struct reset_control *devm_reset_control_get_optional_shared(
	return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_SHARED);
}

/**
 * devm_reset_control_get_optional_shared_deasserted - resource managed
 *                                                     reset_control_get_optional_shared() +
 *                                                     reset_control_deassert()
 * @dev: device to be reset by the controller
 * @id: reset line name
 *
 * Managed reset_control_get_optional_shared() + reset_control_deassert(). For
 * reset controllers returned from this function, reset_control_assert() +
 * reset_control_put() is called automatically on driver detach.
 *
 * See devm_reset_control_get_optional_shared() for more information.
 */
static inline struct reset_control *
devm_reset_control_get_optional_shared_deasserted(struct device *dev, const char *id)
{
	return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_SHARED_DEASSERTED);
}

/**
 * devm_reset_control_bulk_get_optional_shared - resource managed
 *                                               reset_control_bulk_get_optional_shared()