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

Reply via email to