dm: spi: Fix spi_free_slave() freed memory write
[platform/kernel/u-boot.git] / drivers / reset / reset-uclass.c
index 9a5c9c9..071c389 100644 (file)
@@ -1,16 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (c) 2016, NVIDIA CORPORATION.
- *
- * SPDX-License-Identifier: GPL-2.0
  */
 
 #include <common.h>
 #include <dm.h>
 #include <fdtdec.h>
+#include <log.h>
+#include <malloc.h>
 #include <reset.h>
 #include <reset-uclass.h>
-
-DECLARE_GLOBAL_DATA_PTR;
+#include <dm/devres.h>
+#include <dm/lists.h>
 
 static inline struct reset_ops *reset_dev_ops(struct udevice *dev)
 {
@@ -32,41 +33,34 @@ static int reset_of_xlate_default(struct reset_ctl *reset_ctl,
        return 0;
 }
 
-int reset_get_by_index(struct udevice *dev, int index,
-                      struct reset_ctl *reset_ctl)
+static int reset_get_by_index_tail(int ret, ofnode node,
+                                  struct ofnode_phandle_args *args,
+                                  const char *list_name, int index,
+                                  struct reset_ctl *reset_ctl)
 {
-       struct ofnode_phandle_args args;
-       int ret;
        struct udevice *dev_reset;
        struct reset_ops *ops;
 
-       debug("%s(dev=%p, index=%d, reset_ctl=%p)\n", __func__, dev, index,
-             reset_ctl);
+       assert(reset_ctl);
        reset_ctl->dev = NULL;
-
-       ret = dev_read_phandle_with_args(dev, "resets", "#reset-cells", 0,
-                                         index, &args);
-       if (ret) {
-               debug("%s: fdtdec_parse_phandle_with_args() failed: %d\n",
-                     __func__, ret);
+       if (ret)
                return ret;
-       }
 
-       ret = uclass_get_device_by_ofnode(UCLASS_RESET, args.node,
+       ret = uclass_get_device_by_ofnode(UCLASS_RESET, args->node,
                                          &dev_reset);
        if (ret) {
                debug("%s: uclass_get_device_by_ofnode() failed: %d\n",
                      __func__, ret);
-               debug("%s %d\n", ofnode_get_name(args.node), args.args[0]);
+               debug("%s %d\n", ofnode_get_name(args->node), args->args[0]);
                return ret;
        }
        ops = reset_dev_ops(dev_reset);
 
        reset_ctl->dev = dev_reset;
        if (ops->of_xlate)
-               ret = ops->of_xlate(reset_ctl, &args);
+               ret = ops->of_xlate(reset_ctl, args);
        else
-               ret = reset_of_xlate_default(reset_ctl, &args);
+               ret = reset_of_xlate_default(reset_ctl, args);
        if (ret) {
                debug("of_xlate() failed: %d\n", ret);
                return ret;
@@ -81,15 +75,43 @@ int reset_get_by_index(struct udevice *dev, int index,
        return 0;
 }
 
-int reset_get_bulk(struct udevice *dev, struct reset_ctl_bulk *bulk)
+int reset_get_by_index(struct udevice *dev, int index,
+                      struct reset_ctl *reset_ctl)
+{
+       struct ofnode_phandle_args args;
+       int ret;
+
+       ret = dev_read_phandle_with_args(dev, "resets", "#reset-cells", 0,
+                                        index, &args);
+
+       return reset_get_by_index_tail(ret, dev_ofnode(dev), &args, "resets",
+                                      index > 0, reset_ctl);
+}
+
+int reset_get_by_index_nodev(ofnode node, int index,
+                            struct reset_ctl *reset_ctl)
+{
+       struct ofnode_phandle_args args;
+       int ret;
+
+       ret = ofnode_parse_phandle_with_args(node, "resets", "#reset-cells", 0,
+                                            index > 0, &args);
+
+       return reset_get_by_index_tail(ret, node, &args, "resets",
+                                      index > 0, reset_ctl);
+}
+
+static int __reset_get_bulk(struct udevice *dev, ofnode node,
+                           struct reset_ctl_bulk *bulk)
 {
        int i, ret, err, count;
-       
+
        bulk->count = 0;
 
-       count = dev_count_phandle_with_args(dev, "resets", "#reset-cells");
-       if (!count)
-               return 0;
+       count = ofnode_count_phandle_with_args(node, "resets", "#reset-cells",
+                                              0);
+       if (count < 1)
+               return count;
 
        bulk->resets = devm_kcalloc(dev, count, sizeof(struct reset_ctl),
                                    GFP_KERNEL);
@@ -97,7 +119,7 @@ int reset_get_bulk(struct udevice *dev, struct reset_ctl_bulk *bulk)
                return -ENOMEM;
 
        for (i = 0; i < count; i++) {
-               ret = reset_get_by_index(dev, i, &bulk->resets[i]);
+               ret = reset_get_by_index_nodev(node, i, &bulk->resets[i]);
                if (ret < 0)
                        goto bulk_get_err;
 
@@ -115,6 +137,11 @@ bulk_get_err:
        return ret;
 }
 
+int reset_get_bulk(struct udevice *dev, struct reset_ctl_bulk *bulk)
+{
+       return __reset_get_bulk(dev, dev_ofnode(dev), bulk);
+}
+
 int reset_get_by_name(struct udevice *dev, const char *name,
                     struct reset_ctl *reset_ctl)
 {
@@ -148,7 +175,7 @@ int reset_free(struct reset_ctl *reset_ctl)
 
        debug("%s(reset_ctl=%p)\n", __func__, reset_ctl);
 
-       return ops->free(reset_ctl);
+       return ops->rfree(reset_ctl);
 }
 
 int reset_assert(struct reset_ctl *reset_ctl)
@@ -195,6 +222,15 @@ int reset_deassert_bulk(struct reset_ctl_bulk *bulk)
        return 0;
 }
 
+int reset_status(struct reset_ctl *reset_ctl)
+{
+       struct reset_ops *ops = reset_dev_ops(reset_ctl->dev);
+
+       debug("%s(reset_ctl=%p)\n", __func__, reset_ctl);
+
+       return ops->rst_status(reset_ctl);
+}
+
 int reset_release_all(struct reset_ctl *reset_ctl, int count)
 {
        int i, ret;
@@ -218,6 +254,109 @@ int reset_release_all(struct reset_ctl *reset_ctl, int count)
        return 0;
 }
 
+static void devm_reset_release(struct udevice *dev, void *res)
+{
+       reset_free(res);
+}
+
+struct reset_ctl *devm_reset_control_get_by_index(struct udevice *dev,
+                                                 int index)
+{
+       int rc;
+       struct reset_ctl *reset_ctl;
+
+       reset_ctl = devres_alloc(devm_reset_release, sizeof(struct reset_ctl),
+                                __GFP_ZERO);
+       if (unlikely(!reset_ctl))
+               return ERR_PTR(-ENOMEM);
+
+       rc = reset_get_by_index(dev, index, reset_ctl);
+       if (rc)
+               return ERR_PTR(rc);
+
+       devres_add(dev, reset_ctl);
+       return reset_ctl;
+}
+
+struct reset_ctl *devm_reset_control_get(struct udevice *dev, const char *id)
+{
+       int rc;
+       struct reset_ctl *reset_ctl;
+
+       reset_ctl = devres_alloc(devm_reset_release, sizeof(struct reset_ctl),
+                                __GFP_ZERO);
+       if (unlikely(!reset_ctl))
+               return ERR_PTR(-ENOMEM);
+
+       rc = reset_get_by_name(dev, id, reset_ctl);
+       if (rc)
+               return ERR_PTR(rc);
+
+       devres_add(dev, reset_ctl);
+       return reset_ctl;
+}
+
+struct reset_ctl *devm_reset_control_get_optional(struct udevice *dev,
+                                                 const char *id)
+{
+       struct reset_ctl *r = devm_reset_control_get(dev, id);
+
+       if (IS_ERR(r))
+               return NULL;
+
+       return r;
+}
+
+static void devm_reset_bulk_release(struct udevice *dev, void *res)
+{
+       struct reset_ctl_bulk *bulk = res;
+
+       reset_release_all(bulk->resets, bulk->count);
+}
+
+struct reset_ctl_bulk *devm_reset_bulk_get_by_node(struct udevice *dev,
+                                                  ofnode node)
+{
+       int rc;
+       struct reset_ctl_bulk *bulk;
+
+       bulk = devres_alloc(devm_reset_bulk_release,
+                           sizeof(struct reset_ctl_bulk),
+                           __GFP_ZERO);
+       if (unlikely(!bulk))
+               return ERR_PTR(-ENOMEM);
+
+       rc = __reset_get_bulk(dev, node, bulk);
+       if (rc)
+               return ERR_PTR(rc);
+
+       devres_add(dev, bulk);
+       return bulk;
+}
+
+struct reset_ctl_bulk *devm_reset_bulk_get_optional_by_node(struct udevice *dev,
+                                                           ofnode node)
+{
+       struct reset_ctl_bulk *bulk;
+
+       bulk = devm_reset_bulk_get_by_node(dev, node);
+
+       if (IS_ERR(bulk))
+               return NULL;
+
+       return bulk;
+}
+
+struct reset_ctl_bulk *devm_reset_bulk_get(struct udevice *dev)
+{
+       return devm_reset_bulk_get_by_node(dev, dev_ofnode(dev));
+}
+
+struct reset_ctl_bulk *devm_reset_bulk_get_optional(struct udevice *dev)
+{
+       return devm_reset_bulk_get_optional_by_node(dev, dev_ofnode(dev));
+}
+
 UCLASS_DRIVER(reset) = {
        .id             = UCLASS_RESET,
        .name           = "reset",