reset: Add devres helpers to request pre-deasserted reset controls
authorPhilipp Zabel <p.zabel@pengutronix.de>
Wed, 25 Sep 2024 16:40:10 +0000 (18:40 +0200)
committerPhilipp Zabel <p.zabel@pengutronix.de>
Tue, 1 Oct 2024 15:39:53 +0000 (17:39 +0200)
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: Uwe 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: Philipp Zabel <p.zabel@pengutronix.de>
drivers/reset/core.c
include/linux/reset.h

index 682d618..22f67fc 100644 (file)
@@ -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);
index 99296af..2986ced 100644 (file)
@@ -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()