Hello Michal, Although properly commented, I find the reset_reset_bulk() implementation counterintuitive. Are we so certain that the Linux implementation is the right and obvious one? I personally would prefer to have it assert all resets at the same time. It is faster and prevents races if the resets are interdependent.
Kind regards, Maarten Brock > -----Original Message----- > From: U-Boot <[email protected]> On Behalf Of Michal Simek > Sent: Wednesday 13 May 2026 11:42 > To: [email protected]; [email protected]; Simon Glass <[email protected]> > Cc: Tom Rini <[email protected]> > Subject: [PATCH v3 1/5] reset: Add reset_reset() and reset_reset_bulk() API > > Add reset_reset() and reset_reset_bulk() functions to the reset > controller API. These functions assert and then deassert reset signals > in a single call, providing a convenient way to pulse/toggle a reset > line. > > This mimics the Linux kernel's reset_control_reset() and > reset_control_bulk_reset() APIs. The new functions are useful for > drivers that need to cycle a reset line during initialization or > error recovery but with also passing delay parameter. > > If a driver implements the rst_reset op, it will be called directly > with the delay parameter. Otherwise, the reset core performs > reset_assert(), optional udelay(), and reset_deassert() as fallback. > > Signed-off-by: Michal Simek <[email protected]> > Reviewed-by: Simon Glass <[email protected]> > --- > > Changes in v3: > - extend function documentation > > Changes in v2: > - Add delay_us parameter to specify delay between assert and deassert > - Pass delay_us to rst_reset op so drivers can use it if needed > - Return -ENOSYS in stubs when !CONFIG_DM_RESET (like clk.h) > - Fix line length to stay within 80 characters > > drivers/reset/reset-uclass.c | 34 +++++++++++++++++++++++++ > include/reset-uclass.h | 19 ++++++++++++++ > include/reset.h | 49 ++++++++++++++++++++++++++++++++++++ > 3 files changed, 102 insertions(+) > > diff --git a/drivers/reset/reset-uclass.c b/drivers/reset/reset-uclass.c > index fe4cebf54f15..c199e3e5da71 100644 > --- a/drivers/reset/reset-uclass.c > +++ b/drivers/reset/reset-uclass.c > @@ -13,6 +13,7 @@ > #include <reset-uclass.h> > #include <dm/devres.h> > #include <dm/lists.h> > +#include <linux/delay.h> > > static inline struct reset_ops *reset_dev_ops(struct udevice *dev) > { > @@ -225,6 +226,39 @@ int reset_deassert_bulk(struct reset_ctl_bulk *bulk) > return 0; > } > > +int reset_reset(struct reset_ctl *reset_ctl, ulong delay_us) > +{ > + struct reset_ops *ops = reset_dev_ops(reset_ctl->dev); > + int ret; > + > + debug("%s(reset_ctl=%p, delay_us=%lu)\n", __func__, reset_ctl, > + delay_us); > + > + if (ops->rst_reset) > + return ops->rst_reset(reset_ctl, delay_us); > + > + ret = reset_assert(reset_ctl); > + if (ret < 0) > + return ret; > + > + udelay(delay_us); > + > + return reset_deassert(reset_ctl); > +} > + > +int reset_reset_bulk(struct reset_ctl_bulk *bulk, ulong delay_us) > +{ > + int i, ret; > + > + for (i = 0; i < bulk->count; i++) { > + ret = reset_reset(&bulk->resets[i], delay_us); > + if (ret < 0) > + return ret; > + } > + > + return 0; > +} > + > int reset_status(struct reset_ctl *reset_ctl) > { > struct reset_ops *ops = reset_dev_ops(reset_ctl->dev); > diff --git a/include/reset-uclass.h b/include/reset-uclass.h > index 9a0696dd1e3b..7af090b60b57 100644 > --- a/include/reset-uclass.h > +++ b/include/reset-uclass.h > @@ -76,6 +76,25 @@ struct reset_ops { > * @return 0 if OK, or a negative error code. > */ > int (*rst_deassert)(struct reset_ctl *reset_ctl); > + /** > + * rst_reset - Reset a HW module. > + * > + * This optional function triggers a reset pulse on the reset line. > + * If not implemented, reset_reset() falls back to rst_assert(), > + * udelay(@delay_us), then rst_deassert(); that delay is therefore > + * observed only on the fallback path. > + * > + * When rst_reset is provided, @delay_us is controller-specific: the > + * implementation should honour it if the hardware needs a minimum > + * assertion time before release. It may ignore @delay_us when the > + * pulse shape is fixed elsewhere (for example a firmware pulse). > + * > + * @reset_ctl: The reset signal to pulse. > + * @delay_us: Minimum delay in microseconds between assert and > + * deassert where applicable; see above. > + * @return 0 if OK, or a negative error code. > + */ > + int (*rst_reset)(struct reset_ctl *reset_ctl, ulong delay_us); > /** > * rst_status - Check reset signal status. > * > diff --git a/include/reset.h b/include/reset.h > index 036a786d2ace..58574b983f66 100644 > --- a/include/reset.h > +++ b/include/reset.h > @@ -320,6 +320,45 @@ int reset_deassert(struct reset_ctl *reset_ctl); > */ > int reset_deassert_bulk(struct reset_ctl_bulk *bulk); > > +/** > + * reset_reset - Reset a HW module by asserting and deasserting a reset > signal. > + * > + * This function will assert and then deassert the specified reset signal, > + * thus resetting the affected HW module. This is a convenience function > + * that combines reset_assert() and reset_deassert(). > + * > + * If the controller implements struct reset_ops.rst_reset, that callback > + * is used and @delay_us is interpreted as documented there. Otherwise the > + * core performs reset_assert(), udelay(@delay_us), then reset_deassert(). > + * > + * @reset_ctl: A reset control struct that was previously successfully > + * requested by reset_get_by_*(). > + * @delay_us: Delay in microseconds between assert and deassert on the > + * fallback path; meaning is driver-specific when rst_reset is > used. > + * Use 0 for no delay on the fallback path. > + * Return: 0 if OK, or a negative error code. > + */ > +int reset_reset(struct reset_ctl *reset_ctl, ulong delay_us); > + > +/** > + * reset_reset_bulk - Reset all HW modules in a reset control bulk struct. > + * > + * This calls reset_reset() on each entry in order. Each line therefore > + * completes its own assert/delay/deassert (or controller rst_reset) before > + * the next entry starts. That matches Linux reset_control_bulk_reset(). > + * > + * When several lines must stay asserted together for @delay_us (typical > + * multi-reset controllers), use reset_assert_bulk(), udelay(@delay_us), > + * and reset_deassert_bulk() instead. > + * > + * @bulk: A reset control bulk struct that was previously successfully > + * requested by reset_get_bulk(). > + * @delay_us: Delay in microseconds passed to each reset_reset(); see > + * reset_reset() and struct reset_ops.rst_reset. > + * Return: 0 if OK, or a negative error code. > + */ > +int reset_reset_bulk(struct reset_ctl_bulk *bulk, ulong delay_us); > + > /** > * rst_status - Check reset signal status. > * > @@ -443,6 +482,16 @@ static inline int reset_deassert_bulk(struct > reset_ctl_bulk *bulk) > return 0; > } > > +static inline int reset_reset(struct reset_ctl *reset_ctl, ulong delay_us) > +{ > + return -ENOSYS; > +} > + > +static inline int reset_reset_bulk(struct reset_ctl_bulk *bulk, ulong > delay_us) > +{ > + return -ENOSYS; > +} > + > static inline int reset_status(struct reset_ctl *reset_ctl) > { > return -ENOTSUPP; > -- > 2.43.0

