reset: simple: Add reset callback
authorMaxime Ripard <maxime@cerno.tech>
Wed, 27 May 2020 15:47:32 +0000 (17:47 +0200)
committerPhilipp Zabel <p.zabel@pengutronix.de>
Tue, 16 Jun 2020 12:19:57 +0000 (14:19 +0200)
The reset-simple code lacks a reset callback that is still pretty easy to
implement. The only real thing to consider is the delay needed for a device
to be reset, so let's expose that as part of the reset-simple driver data.

Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
drivers/reset/reset-simple.c
include/linux/reset/reset-simple.h

index c854aa351640246b7070f0c9d52ad977485d5c6f..e066614818a35a9b30e5f37815b7c60808e1cb72 100644 (file)
@@ -11,6 +11,7 @@
  * Maxime Ripard <maxime.ripard@free-electrons.com>
  */
 
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/io.h>
@@ -63,6 +64,24 @@ static int reset_simple_deassert(struct reset_controller_dev *rcdev,
        return reset_simple_update(rcdev, id, false);
 }
 
+static int reset_simple_reset(struct reset_controller_dev *rcdev,
+                             unsigned long id)
+{
+       struct reset_simple_data *data = to_reset_simple_data(rcdev);
+       int ret;
+
+       if (!data->reset_us)
+               return -ENOTSUPP;
+
+       ret = reset_simple_assert(rcdev, id);
+       if (ret)
+               return ret;
+
+       usleep_range(data->reset_us, data->reset_us * 2);
+
+       return reset_simple_deassert(rcdev, id);
+}
+
 static int reset_simple_status(struct reset_controller_dev *rcdev,
                               unsigned long id)
 {
@@ -80,6 +99,7 @@ static int reset_simple_status(struct reset_controller_dev *rcdev,
 const struct reset_control_ops reset_simple_ops = {
        .assert         = reset_simple_assert,
        .deassert       = reset_simple_deassert,
+       .reset          = reset_simple_reset,
        .status         = reset_simple_status,
 };
 EXPORT_SYMBOL_GPL(reset_simple_ops);
index 08ccb25a55e657486696788e0492f9c38e94a7ea..c3e44f45b0f758c39e8aafb675910c5219bf9d1d 100644 (file)
  * @status_active_low: if true, bits read back as cleared while the reset is
  *                     asserted. Otherwise, bits read back as set while the
  *                     reset is asserted.
+ * @reset_us: Minimum delay in microseconds needed that needs to be
+ *            waited for between an assert and a deassert to reset the
+ *            device. If multiple consumers with different delay
+ *            requirements are connected to this controller, it must
+ *            be the largest minimum delay. 0 means that such a delay is
+ *            unknown and the reset operation is unsupported.
  */
 struct reset_simple_data {
        spinlock_t                      lock;
@@ -34,6 +40,7 @@ struct reset_simple_data {
        struct reset_controller_dev     rcdev;
        bool                            active_low;
        bool                            status_active_low;
+       unsigned int                    reset_us;
 };
 
 extern const struct reset_control_ops reset_simple_ops;