Merge tag 'v5.13-rc2' into spi-5.13
[linux-2.6-microblaze.git] / drivers / reset / core.c
index dbf881b..71c1c82 100644 (file)
@@ -358,6 +358,30 @@ int reset_control_reset(struct reset_control *rstc)
 }
 EXPORT_SYMBOL_GPL(reset_control_reset);
 
+/**
+ * reset_control_bulk_reset - reset the controlled devices in order
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset controls set
+ *
+ * Issue a reset on all provided reset controls, in order.
+ *
+ * See also: reset_control_reset()
+ */
+int reset_control_bulk_reset(int num_rstcs,
+                            struct reset_control_bulk_data *rstcs)
+{
+       int ret, i;
+
+       for (i = 0; i < num_rstcs; i++) {
+               ret = reset_control_reset(rstcs[i].rstc);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(reset_control_bulk_reset);
+
 /**
  * reset_control_rearm - allow shared reset line to be re-triggered"
  * @rstc: reset controller
@@ -461,6 +485,36 @@ int reset_control_assert(struct reset_control *rstc)
 }
 EXPORT_SYMBOL_GPL(reset_control_assert);
 
+/**
+ * reset_control_bulk_assert - asserts the reset lines in order
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset controls set
+ *
+ * Assert the reset lines for all provided reset controls, in order.
+ * If an assertion fails, already asserted resets are deasserted again.
+ *
+ * See also: reset_control_assert()
+ */
+int reset_control_bulk_assert(int num_rstcs,
+                             struct reset_control_bulk_data *rstcs)
+{
+       int ret, i;
+
+       for (i = 0; i < num_rstcs; i++) {
+               ret = reset_control_assert(rstcs[i].rstc);
+               if (ret)
+                       goto err;
+       }
+
+       return 0;
+
+err:
+       while (i--)
+               reset_control_deassert(rstcs[i].rstc);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(reset_control_bulk_assert);
+
 /**
  * reset_control_deassert - deasserts the reset line
  * @rstc: reset controller
@@ -511,6 +565,36 @@ int reset_control_deassert(struct reset_control *rstc)
 }
 EXPORT_SYMBOL_GPL(reset_control_deassert);
 
+/**
+ * reset_control_bulk_deassert - deasserts the reset lines in reverse order
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset controls set
+ *
+ * Deassert the reset lines for all provided reset controls, in reverse order.
+ * If a deassertion fails, already deasserted resets are asserted again.
+ *
+ * See also: reset_control_deassert()
+ */
+int reset_control_bulk_deassert(int num_rstcs,
+                               struct reset_control_bulk_data *rstcs)
+{
+       int ret, i;
+
+       for (i = num_rstcs - 1; i >= 0; i--) {
+               ret = reset_control_deassert(rstcs[i].rstc);
+               if (ret)
+                       goto err;
+       }
+
+       return 0;
+
+err:
+       while (i < num_rstcs)
+               reset_control_assert(rstcs[i++].rstc);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(reset_control_bulk_deassert);
+
 /**
  * reset_control_status - returns a negative errno if not supported, a
  * positive value if the reset line is asserted, or zero if the reset
@@ -588,6 +672,36 @@ int reset_control_acquire(struct reset_control *rstc)
 }
 EXPORT_SYMBOL_GPL(reset_control_acquire);
 
+/**
+ * reset_control_bulk_acquire - acquires reset controls for exclusive use
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset controls set
+ *
+ * This is used to explicitly acquire reset controls requested with
+ * reset_control_bulk_get_exclusive_release() for temporary exclusive use.
+ *
+ * See also: reset_control_acquire(), reset_control_bulk_release()
+ */
+int reset_control_bulk_acquire(int num_rstcs,
+                              struct reset_control_bulk_data *rstcs)
+{
+       int ret, i;
+
+       for (i = 0; i < num_rstcs; i++) {
+               ret = reset_control_acquire(rstcs[i].rstc);
+               if (ret)
+                       goto err;
+       }
+
+       return 0;
+
+err:
+       while (i--)
+               reset_control_release(rstcs[i].rstc);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(reset_control_bulk_acquire);
+
 /**
  * reset_control_release() - releases exclusive access to a reset control
  * @rstc: reset control
@@ -610,6 +724,26 @@ void reset_control_release(struct reset_control *rstc)
 }
 EXPORT_SYMBOL_GPL(reset_control_release);
 
+/**
+ * reset_control_bulk_release() - releases exclusive access to reset controls
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset controls set
+ *
+ * Releases exclusive access right to reset controls previously obtained by a
+ * call to reset_control_bulk_acquire().
+ *
+ * See also: reset_control_release(), reset_control_bulk_acquire()
+ */
+void reset_control_bulk_release(int num_rstcs,
+                               struct reset_control_bulk_data *rstcs)
+{
+       int i;
+
+       for (i = 0; i < num_rstcs; i++)
+               reset_control_release(rstcs[i].rstc);
+}
+EXPORT_SYMBOL_GPL(reset_control_bulk_release);
+
 static struct reset_control *__reset_control_get_internal(
                                struct reset_controller_dev *rcdev,
                                unsigned int index, bool shared, bool acquired)
@@ -814,6 +948,32 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id,
 }
 EXPORT_SYMBOL_GPL(__reset_control_get);
 
+int __reset_control_bulk_get(struct device *dev, int num_rstcs,
+                            struct reset_control_bulk_data *rstcs,
+                            bool shared, bool optional, bool acquired)
+{
+       int ret, i;
+
+       for (i = 0; i < num_rstcs; i++) {
+               rstcs[i].rstc = __reset_control_get(dev, rstcs[i].id, 0,
+                                                   shared, optional, acquired);
+               if (IS_ERR(rstcs[i].rstc)) {
+                       ret = PTR_ERR(rstcs[i].rstc);
+                       goto err;
+               }
+       }
+
+       return 0;
+
+err:
+       mutex_lock(&reset_list_mutex);
+       while (i--)
+               __reset_control_put_internal(rstcs[i].rstc);
+       mutex_unlock(&reset_list_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(__reset_control_bulk_get);
+
 static void reset_control_array_put(struct reset_control_array *resets)
 {
        int i;
@@ -845,6 +1005,23 @@ void reset_control_put(struct reset_control *rstc)
 }
 EXPORT_SYMBOL_GPL(reset_control_put);
 
+/**
+ * reset_control_bulk_put - free the reset controllers
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset controls set
+ */
+void reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs)
+{
+       mutex_lock(&reset_list_mutex);
+       while (num_rstcs--) {
+               if (IS_ERR_OR_NULL(rstcs[num_rstcs].rstc))
+                       continue;
+               __reset_control_put_internal(rstcs[num_rstcs].rstc);
+       }
+       mutex_unlock(&reset_list_mutex);
+}
+EXPORT_SYMBOL_GPL(reset_control_bulk_put);
+
 static void devm_reset_control_release(struct device *dev, void *res)
 {
        reset_control_put(*(struct reset_control **)res);
@@ -874,6 +1051,44 @@ struct reset_control *__devm_reset_control_get(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(__devm_reset_control_get);
 
+struct reset_control_bulk_devres {
+       int num_rstcs;
+       struct reset_control_bulk_data *rstcs;
+};
+
+static void devm_reset_control_bulk_release(struct device *dev, void *res)
+{
+       struct reset_control_bulk_devres *devres = res;
+
+       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,
+                                 bool shared, bool optional, bool acquired)
+{
+       struct reset_control_bulk_devres *ptr;
+       int ret;
+
+       ptr = devres_alloc(devm_reset_control_bulk_release, sizeof(*ptr),
+                          GFP_KERNEL);
+       if (!ptr)
+               return -ENOMEM;
+
+       ret = __reset_control_bulk_get(dev, num_rstcs, rstcs, shared, optional, acquired);
+       if (ret < 0) {
+               devres_free(ptr);
+               return ret;
+       }
+
+       ptr->num_rstcs = num_rstcs;
+       ptr->rstcs = rstcs;
+       devres_add(dev, ptr);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(__devm_reset_control_bulk_get);
+
 /**
  * __device_reset - find reset controller associated with the device
  *                  and perform reset