All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/6] reset: APIs to manage a list of resets
@ 2017-06-01 16:51 Philipp Zabel
  2017-06-01 16:51 ` [PATCH v5 2/6] reset: Add APIs to manage array " Philipp Zabel
                   ` (2 more replies)
  0 siblings, 3 replies; 21+ messages in thread
From: Philipp Zabel @ 2017-06-01 16:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Vivek Gautam, Jon Hunter, Felipe Balbi, Greg Kroah-Hartman,
	Thierry Reding, linux-tegra, linux-usb, linux-arm-msm,
	Philipp Zabel

A set of patches to allow consumers to get and de/assert or trigger
a number of resets at the same time. A patch on top of Vivek's original
API extension is added to hide the reset_control_array behind a struct
reset_control so that the consumer doesn't have care about the difference
between a singular reset control and reset control controlling an array
of resets, except when requesting the control.

This series also contains reset controls patches for dwc3-of-simple
and tegra pmc drivers.
A small patch is added in this series to correctly re-order the
resource handling in dwc3_of_simple_remove().

The series is tested on torvald's master branch the device tree
patches to enable usb on db820c.

Changes since v4:
 - Added a patch to hide reset control arrays behind struct reset_control
   and adapted the consumer patches. This could be merged with the reset
   array API patch if we think this is a good idea.

Changes since v3:
 - Squashed of_reset_control_get_count() patch in the second patch that
   adds the reset control array APIs.
 - The error path after getting count through of_reset_control_get_count()
   now returns NULL pointer in case when 'optional' flag is true.
 - Added code in reset_control_array_assert() to deassert the
   already asserted resets in the error case.
 - Using of_reset_control_array_get_optional_exclusive() in dwc3 patch
   to request the reset control array.
 - Added a patch to fix the order in which resources are handled in
   dwc3_of_simple_remove() path.
 - Added tegra_powergate->reset to take care of single reset control
   passed from the client drivers.

Changes since v2:
 - Addressed comments to make APIs inline with gpiod API.
 - Moved number of reset controls in 'struct reset_control_array'
   so that the footprint is reduced.
 - of_reset_control_array_get() and devm_reset_control_array_get()
   now return pointer to the newly created reset control array.
 - Added comments to mention that the reset control array APIs don't
   guarantee any particular order when handling the reset controls.
 - Dropped 'name' from reset_control_array' since the interface is meant
   for a bunch of anonymous resets that can all be asserted or deasserted
   in arbitrary order.
 - Fixed returns for APIs reported by kbuild.
 - Fixed 'for' clause guards reported by kbuild.

Changes since v1:
 - Addressed comment for error handling in of_reset_control_get_count()
 - Added patch to manage reset controller array.
 - Rebased dwc3-of-simple changes based on the new set of APIs
   for reset control array.
 - Added a patch for soc/tegra/pmc driver to use the new set of
   reset control array APIs.

Philipp Zabel (2):
  reset: use kref for reference counting
  reset: hide reset control arrays behind struct reset_control

Vivek Gautam (4):
  reset: Add APIs to manage array of resets
  usb: dwc3: of-simple: Re-order resource handling in remove
  usb: dwc3: of-simple: Add support to get resets for the device
  soc/tegra: pmc: Use the new reset APIs to manage reset controllers

 drivers/reset/core.c              | 234 ++++++++++++++++++++++++++++++++++++--
 drivers/soc/tegra/pmc.c           |  82 ++++---------
 drivers/usb/dwc3/dwc3-of-simple.c |  29 ++++-
 include/linux/reset.h             |  73 ++++++++++++
 4 files changed, 344 insertions(+), 74 deletions(-)

-- 
2.11.0

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v5 1/6] reset: use kref for reference counting
  2017-06-01 16:51 [PATCH v5 0/6] reset: APIs to manage a list of resets Philipp Zabel
@ 2017-06-01 16:51     ` Philipp Zabel
       [not found] ` <20170601165203.15315-1-p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
  2017-06-01 16:52 ` [PATCH v5 4/6] usb: dwc3: of-simple: Re-order resource handling in remove Philipp Zabel
  2 siblings, 0 replies; 21+ messages in thread
From: Philipp Zabel @ 2017-06-01 16:51 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Vivek Gautam, Jon Hunter, Felipe Balbi, Greg Kroah-Hartman,
	Thierry Reding, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, Philipp Zabel

Use kref for reference counting and enjoy the advantages of refcount_t.

Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
 drivers/reset/core.c | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index cd739d2fa1603..0090784ff4105 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -13,6 +13,7 @@
 #include <linux/err.h>
 #include <linux/export.h>
 #include <linux/kernel.h>
+#include <linux/kref.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/reset.h>
@@ -40,7 +41,7 @@ struct reset_control {
 	struct reset_controller_dev *rcdev;
 	struct list_head list;
 	unsigned int id;
-	unsigned int refcnt;
+	struct kref refcnt;
 	bool shared;
 	atomic_t deassert_count;
 	atomic_t triggered_count;
@@ -288,7 +289,7 @@ static struct reset_control *__reset_control_get_internal(
 			if (WARN_ON(!rstc->shared || !shared))
 				return ERR_PTR(-EBUSY);
 
-			rstc->refcnt++;
+			kref_get(&rstc->refcnt);
 			return rstc;
 		}
 	}
@@ -302,18 +303,18 @@ static struct reset_control *__reset_control_get_internal(
 	rstc->rcdev = rcdev;
 	list_add(&rstc->list, &rcdev->reset_control_head);
 	rstc->id = index;
-	rstc->refcnt = 1;
+	kref_init(&rstc->refcnt);
 	rstc->shared = shared;
 
 	return rstc;
 }
 
-static void __reset_control_put_internal(struct reset_control *rstc)
+static void __reset_control_release(struct kref *kref)
 {
-	lockdep_assert_held(&reset_list_mutex);
+	struct reset_control *rstc = container_of(kref, struct reset_control,
+						  refcnt);
 
-	if (--rstc->refcnt)
-		return;
+	lockdep_assert_held(&reset_list_mutex);
 
 	module_put(rstc->rcdev->owner);
 
@@ -321,6 +322,13 @@ static void __reset_control_put_internal(struct reset_control *rstc)
 	kfree(rstc);
 }
 
+static void __reset_control_put_internal(struct reset_control *rstc)
+{
+	lockdep_assert_held(&reset_list_mutex);
+
+	kref_put(&rstc->refcnt, __reset_control_release);
+}
+
 struct reset_control *__of_reset_control_get(struct device_node *node,
 				     const char *id, int index, bool shared,
 				     bool optional)
@@ -400,7 +408,6 @@ EXPORT_SYMBOL_GPL(__reset_control_get);
  * reset_control_put - free the reset controller
  * @rstc: reset controller
  */
-
 void reset_control_put(struct reset_control *rstc)
 {
 	if (IS_ERR_OR_NULL(rstc))
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v5 1/6] reset: use kref for reference counting
@ 2017-06-01 16:51     ` Philipp Zabel
  0 siblings, 0 replies; 21+ messages in thread
From: Philipp Zabel @ 2017-06-01 16:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Vivek Gautam, Jon Hunter, Felipe Balbi, Greg Kroah-Hartman,
	Thierry Reding, linux-tegra, linux-usb, linux-arm-msm,
	Philipp Zabel

Use kref for reference counting and enjoy the advantages of refcount_t.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
 drivers/reset/core.c | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index cd739d2fa1603..0090784ff4105 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -13,6 +13,7 @@
 #include <linux/err.h>
 #include <linux/export.h>
 #include <linux/kernel.h>
+#include <linux/kref.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/reset.h>
@@ -40,7 +41,7 @@ struct reset_control {
 	struct reset_controller_dev *rcdev;
 	struct list_head list;
 	unsigned int id;
-	unsigned int refcnt;
+	struct kref refcnt;
 	bool shared;
 	atomic_t deassert_count;
 	atomic_t triggered_count;
@@ -288,7 +289,7 @@ static struct reset_control *__reset_control_get_internal(
 			if (WARN_ON(!rstc->shared || !shared))
 				return ERR_PTR(-EBUSY);
 
-			rstc->refcnt++;
+			kref_get(&rstc->refcnt);
 			return rstc;
 		}
 	}
@@ -302,18 +303,18 @@ static struct reset_control *__reset_control_get_internal(
 	rstc->rcdev = rcdev;
 	list_add(&rstc->list, &rcdev->reset_control_head);
 	rstc->id = index;
-	rstc->refcnt = 1;
+	kref_init(&rstc->refcnt);
 	rstc->shared = shared;
 
 	return rstc;
 }
 
-static void __reset_control_put_internal(struct reset_control *rstc)
+static void __reset_control_release(struct kref *kref)
 {
-	lockdep_assert_held(&reset_list_mutex);
+	struct reset_control *rstc = container_of(kref, struct reset_control,
+						  refcnt);
 
-	if (--rstc->refcnt)
-		return;
+	lockdep_assert_held(&reset_list_mutex);
 
 	module_put(rstc->rcdev->owner);
 
@@ -321,6 +322,13 @@ static void __reset_control_put_internal(struct reset_control *rstc)
 	kfree(rstc);
 }
 
+static void __reset_control_put_internal(struct reset_control *rstc)
+{
+	lockdep_assert_held(&reset_list_mutex);
+
+	kref_put(&rstc->refcnt, __reset_control_release);
+}
+
 struct reset_control *__of_reset_control_get(struct device_node *node,
 				     const char *id, int index, bool shared,
 				     bool optional)
@@ -400,7 +408,6 @@ EXPORT_SYMBOL_GPL(__reset_control_get);
  * reset_control_put - free the reset controller
  * @rstc: reset controller
  */
-
 void reset_control_put(struct reset_control *rstc)
 {
 	if (IS_ERR_OR_NULL(rstc))
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v5 2/6] reset: Add APIs to manage array of resets
  2017-06-01 16:51 [PATCH v5 0/6] reset: APIs to manage a list of resets Philipp Zabel
@ 2017-06-01 16:51 ` Philipp Zabel
       [not found] ` <20170601165203.15315-1-p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
  2017-06-01 16:52 ` [PATCH v5 4/6] usb: dwc3: of-simple: Re-order resource handling in remove Philipp Zabel
  2 siblings, 0 replies; 21+ messages in thread
From: Philipp Zabel @ 2017-06-01 16:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Vivek Gautam, Jon Hunter, Felipe Balbi, Greg Kroah-Hartman,
	Thierry Reding, linux-tegra, linux-usb, linux-arm-msm,
	Philipp Zabel

From: Vivek Gautam <vivek.gautam@codeaurora.org>

Many devices may want to request a bunch of resets
and control them. So it's better to manage them as an
array. Add APIs to _get(), _assert(), and _deassert()
an array of reset_control.
Note that, these APIs don't guarantee that the reset lines
managed in the array are handled in any particular order.

Cc: Felipe Balbi <balbi@kernel.org>
Signed-off-by: Vivek Gautam <vivek.gautam@codeaurora.org>
Acked-by: Jon Hunter <jonathanh@nvidia.com>
Tested-by: Jon Hunter <jonathanh@nvidia.com>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
 drivers/reset/core.c  | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/reset.h |  93 +++++++++++++++++++++++
 2 files changed, 295 insertions(+)

diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 0090784ff4105..1747000757211 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -472,3 +472,205 @@ int device_reset(struct device *dev)
 	return ret;
 }
 EXPORT_SYMBOL_GPL(device_reset);
+
+/**
+ * APIs to manage an array of reset controls.
+ */
+/**
+ * of_reset_control_get_count - Count number of resets available with a device
+ *
+ * @node: device node that contains 'resets'.
+ *
+ * Returns positive reset count on success, or error number on failure and
+ * on count being zero.
+ */
+static int of_reset_control_get_count(struct device_node *node)
+{
+	int count;
+
+	if (!node)
+		return -EINVAL;
+
+	count = of_count_phandle_with_args(node, "resets", "#reset-cells");
+	if (count == 0)
+		count = -ENOENT;
+
+	return count;
+}
+
+/**
+ * reset_control_array_assert: assert a list of resets
+ *
+ * @resets: reset control array holding info about the list of resets
+ *
+ * This API doesn't guarantee that the reset lines controlled by
+ * the reset array are asserted in any particular order.
+ *
+ * Returns 0 on success or error number on failure.
+ */
+int reset_control_array_assert(struct reset_control_array *resets)
+{
+	int ret, i;
+
+	if (!resets)
+		return 0;
+
+	if (IS_ERR(resets))
+		return -EINVAL;
+
+	for (i = 0; i < resets->num_rstcs; i++) {
+		ret = reset_control_assert(resets->rstc[i]);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	while (i--)
+		reset_control_deassert(resets->rstc[i]);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(reset_control_array_assert);
+
+/**
+ * reset_control_array_deassert: deassert a list of resets
+ *
+ * @resets: reset control array holding info about the list of resets
+ *
+ * This API doesn't guarantee that the reset lines controlled by
+ * the reset array are deasserted in any particular order.
+ *
+ * Returns 0 on success or error number on failure.
+ */
+int reset_control_array_deassert(struct reset_control_array *resets)
+{
+	int ret, i;
+
+	if (!resets)
+		return 0;
+
+	if (IS_ERR(resets))
+		return -EINVAL;
+
+	for (i = 0; i < resets->num_rstcs; i++) {
+		ret = reset_control_deassert(resets->rstc[i]);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	while (i--)
+		reset_control_assert(resets->rstc[i]);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(reset_control_array_deassert);
+
+static void devm_reset_control_array_release(struct device *dev, void *res)
+{
+	reset_control_array_put(*(struct reset_control_array **)res);
+}
+
+/**
+ * of_reset_control_array_get - Get a list of reset controls using
+ *				device node.
+ *
+ * @np: device node for the device that requests the reset controls array
+ * @shared: whether reset controls are shared or not
+ * @optional: whether it is optional to get the reset controls
+ *
+ * Returns pointer to allocated reset_control_array on success or
+ * error on failure
+ */
+struct reset_control_array *
+of_reset_control_array_get(struct device_node *np, bool shared, bool optional)
+{
+	struct reset_control_array *resets;
+	struct reset_control *rstc;
+	int num, i;
+	void *err;
+
+	num = of_reset_control_get_count(np);
+	if (num < 0)
+		return optional ? NULL : ERR_PTR(num);
+
+	resets = kzalloc(sizeof(*resets) + sizeof(resets->rstc[0]) * num,
+			 GFP_KERNEL);
+	if (!resets)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < num; i++) {
+		rstc = __of_reset_control_get(np, NULL, i, shared, optional);
+		if (IS_ERR(rstc)) {
+			err = ERR_CAST(rstc);
+			goto err_rst;
+		}
+		resets->rstc[i] = rstc;
+	}
+	resets->num_rstcs = num;
+
+	return resets;
+
+err_rst:
+	while (--i >= 0)
+		reset_control_put(resets->rstc[i]);
+
+	kfree(resets);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(of_reset_control_array_get);
+
+/**
+ * devm_reset_control_array_get - Resource managed reset control array get
+ *
+ * @dev: device that requests the list of reset controls
+ * @shared: whether reset controls are shared or not
+ * @optional: whether it is optional to get the reset controls
+ *
+ * The reset control array APIs are intended for a list of resets
+ * that just have to be asserted or deasserted, without any
+ * requirements on the order.
+ *
+ * Returns pointer to allocated reset_control_array on success or
+ * error on failure
+ */
+struct reset_control_array *
+devm_reset_control_array_get(struct device *dev, bool shared, bool optional)
+{
+	struct reset_control_array **devres;
+	struct reset_control_array *resets;
+
+	devres = devres_alloc(devm_reset_control_array_release,
+			      sizeof(*devres), GFP_KERNEL);
+	if (!devres)
+		return ERR_PTR(-ENOMEM);
+
+	resets = of_reset_control_array_get(dev->of_node, shared, optional);
+	if (IS_ERR(resets)) {
+		devres_free(resets);
+		return resets;
+	}
+
+	*devres = resets;
+	devres_add(dev, devres);
+
+	return resets;
+}
+EXPORT_SYMBOL_GPL(devm_reset_control_array_get);
+
+void reset_control_array_put(struct reset_control_array *resets)
+{
+	int i;
+
+	if (IS_ERR_OR_NULL(resets))
+		return;
+
+	for (i = 0; i < resets->num_rstcs; i++)
+		reset_control_put(resets->rstc[i]);
+
+	kfree(resets);
+}
+EXPORT_SYMBOL_GPL(reset_control_array_put);
diff --git a/include/linux/reset.h b/include/linux/reset.h
index 13d8681210d54..df75fe50f765d 100644
--- a/include/linux/reset.h
+++ b/include/linux/reset.h
@@ -5,6 +5,11 @@
 
 struct reset_control;
 
+struct reset_control_array {
+	unsigned int num_rstcs;
+	struct reset_control *rstc[];
+};
+
 #ifdef CONFIG_RESET_CONTROLLER
 
 int reset_control_reset(struct reset_control *rstc);
@@ -25,6 +30,14 @@ struct reset_control *__devm_reset_control_get(struct device *dev,
 
 int __must_check device_reset(struct device *dev);
 
+int reset_control_array_assert(struct reset_control_array *resets);
+int reset_control_array_deassert(struct reset_control_array *resets);
+struct reset_control_array *devm_reset_control_array_get(struct device *dev,
+						bool shared, bool optional);
+struct reset_control_array *of_reset_control_array_get(struct device_node *np,
+						bool shared, bool optional);
+void reset_control_array_put(struct reset_control_array *resets);
+
 static inline int device_reset_optional(struct device *dev)
 {
 	return device_reset(dev);
@@ -89,6 +102,35 @@ static inline struct reset_control *__devm_reset_control_get(
 	return optional ? NULL : ERR_PTR(-ENOTSUPP);
 }
 
+static inline
+int reset_control_array_assert(struct reset_control_array *resets)
+{
+	return 0;
+}
+
+static inline
+int reset_control_array_deassert(struct reset_control_array *resets)
+{
+	return 0;
+}
+
+static inline struct reset_control_array *
+devm_reset_control_array_get(struct device *dev, bool shared, bool optional)
+{
+	return optional ? NULL : ERR_PTR(-ENOTSUPP);
+}
+
+static inline struct reset_control_array *
+of_reset_control_array_get(struct device_node *np, bool shared, bool optional)
+{
+	return optional ? NULL : ERR_PTR(-ENOTSUPP);
+}
+
+static inline
+void reset_control_array_put(struct reset_control_array *resets)
+{
+}
+
 #endif /* CONFIG_RESET_CONTROLLER */
 
 /**
@@ -374,4 +416,55 @@ static inline struct reset_control *devm_reset_control_get_by_index(
 {
 	return devm_reset_control_get_exclusive_by_index(dev, index);
 }
+
+/*
+ * APIs to manage a list of reset controllers
+ */
+static inline struct reset_control_array *
+devm_reset_control_array_get_exclusive(struct device *dev)
+{
+	return devm_reset_control_array_get(dev, false, false);
+}
+
+static inline struct reset_control_array *
+devm_reset_control_array_get_shared(struct device *dev)
+{
+	return devm_reset_control_array_get(dev, true, false);
+}
+
+static inline struct reset_control_array *
+devm_reset_control_array_get_optional_exclusive(struct device *dev)
+{
+	return devm_reset_control_array_get(dev, false, true);
+}
+
+static inline struct reset_control_array *
+devm_reset_control_array_get_optional_shared(struct device *dev)
+{
+	return devm_reset_control_array_get(dev, true, true);
+}
+
+static inline struct reset_control_array *
+of_reset_control_array_get_exclusive(struct device_node *node)
+{
+	return of_reset_control_array_get(node, false, false);
+}
+
+static inline struct reset_control_array *
+of_reset_control_array_get_shared(struct device_node *node)
+{
+	return of_reset_control_array_get(node, true, false);
+}
+
+static inline struct reset_control_array *
+of_reset_control_array_get_optional_exclusive(struct device_node *node)
+{
+	return of_reset_control_array_get(node, false, true);
+}
+
+static inline struct reset_control_array *
+of_reset_control_array_get_optional_shared(struct device_node *node)
+{
+	return of_reset_control_array_get(node, true, true);
+}
 #endif
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v5 3/6] reset: hide reset control arrays behind struct reset_control
  2017-06-01 16:51 [PATCH v5 0/6] reset: APIs to manage a list of resets Philipp Zabel
@ 2017-06-01 16:52     ` Philipp Zabel
       [not found] ` <20170601165203.15315-1-p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
  2017-06-01 16:52 ` [PATCH v5 4/6] usb: dwc3: of-simple: Re-order resource handling in remove Philipp Zabel
  2 siblings, 0 replies; 21+ messages in thread
From: Philipp Zabel @ 2017-06-01 16:52 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Vivek Gautam, Jon Hunter, Felipe Balbi, Greg Kroah-Hartman,
	Thierry Reding, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, Philipp Zabel

Reset controls already may control multiple reset lines with a single
hardware bit. So from the user perspective, reset control arrays are not
at all different from single reset controls.
Therefore, hide reset control arrays behind struct reset_control to
avoid having to introduce new API functions for array (de)assert/reset.

Cc: Vivek Gautam <vivek.gautam-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Cc: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
 drivers/reset/core.c  | 225 ++++++++++++++++++++++++++------------------------
 include/linux/reset.h |  44 +++-------
 2 files changed, 128 insertions(+), 141 deletions(-)

diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 1747000757211..c8fb4426b218a 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -43,11 +43,24 @@ struct reset_control {
 	unsigned int id;
 	struct kref refcnt;
 	bool shared;
+	bool array;
 	atomic_t deassert_count;
 	atomic_t triggered_count;
 };
 
 /**
+ * struct reset_control_array - an array of reset controls
+ * @base: reset control for compatibility with reset control API functions
+ * @num_rstcs: number of reset controls
+ * @rstc: array of reset controls
+ */
+struct reset_control_array {
+	struct reset_control base;
+	unsigned int num_rstcs;
+	struct reset_control *rstc[];
+};
+
+/**
  * of_reset_simple_xlate - translate reset_spec to the reset line number
  * @rcdev: a pointer to the reset controller device
  * @reset_spec: reset line specifier as found in the device tree
@@ -135,6 +148,65 @@ int devm_reset_controller_register(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(devm_reset_controller_register);
 
+static inline struct reset_control_array *
+rstc_to_array(struct reset_control *rstc) {
+	return container_of(rstc, struct reset_control_array, base);
+}
+
+static int reset_control_array_reset(struct reset_control_array *resets)
+{
+	int ret, i;
+
+	for (i = 0; i < resets->num_rstcs; i++) {
+		ret = reset_control_reset(resets->rstc[i]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int reset_control_array_assert(struct reset_control_array *resets)
+{
+	int ret, i;
+
+	for (i = 0; i < resets->num_rstcs; i++) {
+		ret = reset_control_assert(resets->rstc[i]);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	while (i--)
+		reset_control_deassert(resets->rstc[i]);
+	return ret;
+}
+
+static int reset_control_array_deassert(struct reset_control_array *resets)
+{
+	int ret, i;
+
+	for (i = 0; i < resets->num_rstcs; i++) {
+		ret = reset_control_deassert(resets->rstc[i]);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	while (i--)
+		reset_control_assert(resets->rstc[i]);
+	return ret;
+}
+
+static inline bool reset_control_is_array(struct reset_control *rstc)
+{
+	return rstc->array;
+}
+
 /**
  * reset_control_reset - reset the controlled device
  * @rstc: reset controller
@@ -158,6 +230,9 @@ int reset_control_reset(struct reset_control *rstc)
 	if (WARN_ON(IS_ERR(rstc)))
 		return -EINVAL;
 
+	if (reset_control_is_array(rstc))
+		return reset_control_array_reset(rstc_to_array(rstc));
+
 	if (!rstc->rcdev->ops->reset)
 		return -ENOTSUPP;
 
@@ -202,6 +277,9 @@ int reset_control_assert(struct reset_control *rstc)
 	if (WARN_ON(IS_ERR(rstc)))
 		return -EINVAL;
 
+	if (reset_control_is_array(rstc))
+		return reset_control_array_assert(rstc_to_array(rstc));
+
 	if (!rstc->rcdev->ops->assert)
 		return -ENOTSUPP;
 
@@ -240,6 +318,9 @@ int reset_control_deassert(struct reset_control *rstc)
 	if (WARN_ON(IS_ERR(rstc)))
 		return -EINVAL;
 
+	if (reset_control_is_array(rstc))
+		return reset_control_array_deassert(rstc_to_array(rstc));
+
 	if (!rstc->rcdev->ops->deassert)
 		return -ENOTSUPP;
 
@@ -266,7 +347,7 @@ int reset_control_status(struct reset_control *rstc)
 	if (!rstc)
 		return 0;
 
-	if (WARN_ON(IS_ERR(rstc)))
+	if (WARN_ON(IS_ERR(rstc)) || reset_control_is_array(rstc))
 		return -EINVAL;
 
 	if (rstc->rcdev->ops->status)
@@ -404,6 +485,16 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id,
 }
 EXPORT_SYMBOL_GPL(__reset_control_get);
 
+static void reset_control_array_put(struct reset_control_array *resets)
+{
+	int i;
+
+	mutex_lock(&reset_list_mutex);
+	for (i = 0; i < resets->num_rstcs; i++)
+		__reset_control_put_internal(resets->rstc[i]);
+	mutex_unlock(&reset_list_mutex);
+}
+
 /**
  * reset_control_put - free the reset controller
  * @rstc: reset controller
@@ -413,6 +504,11 @@ void reset_control_put(struct reset_control *rstc)
 	if (IS_ERR_OR_NULL(rstc))
 		return;
 
+	if (reset_control_is_array(rstc)) {
+		reset_control_array_put(rstc_to_array(rstc));
+		return;
+	}
+
 	mutex_lock(&reset_list_mutex);
 	__reset_control_put_internal(rstc);
 	mutex_unlock(&reset_list_mutex);
@@ -499,81 +595,6 @@ static int of_reset_control_get_count(struct device_node *node)
 }
 
 /**
- * reset_control_array_assert: assert a list of resets
- *
- * @resets: reset control array holding info about the list of resets
- *
- * This API doesn't guarantee that the reset lines controlled by
- * the reset array are asserted in any particular order.
- *
- * Returns 0 on success or error number on failure.
- */
-int reset_control_array_assert(struct reset_control_array *resets)
-{
-	int ret, i;
-
-	if (!resets)
-		return 0;
-
-	if (IS_ERR(resets))
-		return -EINVAL;
-
-	for (i = 0; i < resets->num_rstcs; i++) {
-		ret = reset_control_assert(resets->rstc[i]);
-		if (ret)
-			goto err;
-	}
-
-	return 0;
-
-err:
-	while (i--)
-		reset_control_deassert(resets->rstc[i]);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(reset_control_array_assert);
-
-/**
- * reset_control_array_deassert: deassert a list of resets
- *
- * @resets: reset control array holding info about the list of resets
- *
- * This API doesn't guarantee that the reset lines controlled by
- * the reset array are deasserted in any particular order.
- *
- * Returns 0 on success or error number on failure.
- */
-int reset_control_array_deassert(struct reset_control_array *resets)
-{
-	int ret, i;
-
-	if (!resets)
-		return 0;
-
-	if (IS_ERR(resets))
-		return -EINVAL;
-
-	for (i = 0; i < resets->num_rstcs; i++) {
-		ret = reset_control_deassert(resets->rstc[i]);
-		if (ret)
-			goto err;
-	}
-
-	return 0;
-
-err:
-	while (i--)
-		reset_control_assert(resets->rstc[i]);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(reset_control_array_deassert);
-
-static void devm_reset_control_array_release(struct device *dev, void *res)
-{
-	reset_control_array_put(*(struct reset_control_array **)res);
-}
-
-/**
  * of_reset_control_array_get - Get a list of reset controls using
  *				device node.
  *
@@ -584,13 +605,12 @@ static void devm_reset_control_array_release(struct device *dev, void *res)
  * Returns pointer to allocated reset_control_array on success or
  * error on failure
  */
-struct reset_control_array *
+struct reset_control *
 of_reset_control_array_get(struct device_node *np, bool shared, bool optional)
 {
 	struct reset_control_array *resets;
 	struct reset_control *rstc;
 	int num, i;
-	void *err;
 
 	num = of_reset_control_get_count(np);
 	if (num < 0)
@@ -603,23 +623,24 @@ of_reset_control_array_get(struct device_node *np, bool shared, bool optional)
 
 	for (i = 0; i < num; i++) {
 		rstc = __of_reset_control_get(np, NULL, i, shared, optional);
-		if (IS_ERR(rstc)) {
-			err = ERR_CAST(rstc);
+		if (IS_ERR(rstc))
 			goto err_rst;
-		}
 		resets->rstc[i] = rstc;
 	}
 	resets->num_rstcs = num;
+	resets->base.array = true;
 
-	return resets;
+	return &resets->base;
 
 err_rst:
+	mutex_lock(&reset_list_mutex);
 	while (--i >= 0)
-		reset_control_put(resets->rstc[i]);
+		__reset_control_put_internal(resets->rstc[i]);
+	mutex_unlock(&reset_list_mutex);
 
 	kfree(resets);
 
-	return err;
+	return rstc;
 }
 EXPORT_SYMBOL_GPL(of_reset_control_array_get);
 
@@ -637,40 +658,26 @@ EXPORT_SYMBOL_GPL(of_reset_control_array_get);
  * Returns pointer to allocated reset_control_array on success or
  * error on failure
  */
-struct reset_control_array *
+struct reset_control *
 devm_reset_control_array_get(struct device *dev, bool shared, bool optional)
 {
-	struct reset_control_array **devres;
-	struct reset_control_array *resets;
+	struct reset_control **devres;
+	struct reset_control *rstc;
 
-	devres = devres_alloc(devm_reset_control_array_release,
-			      sizeof(*devres), GFP_KERNEL);
+	devres = devres_alloc(devm_reset_control_release, sizeof(*devres),
+			      GFP_KERNEL);
 	if (!devres)
 		return ERR_PTR(-ENOMEM);
 
-	resets = of_reset_control_array_get(dev->of_node, shared, optional);
-	if (IS_ERR(resets)) {
-		devres_free(resets);
-		return resets;
+	rstc = of_reset_control_array_get(dev->of_node, shared, optional);
+	if (IS_ERR(rstc)) {
+		devres_free(devres);
+		return rstc;
 	}
 
-	*devres = resets;
+	*devres = rstc;
 	devres_add(dev, devres);
 
-	return resets;
+	return rstc;
 }
 EXPORT_SYMBOL_GPL(devm_reset_control_array_get);
-
-void reset_control_array_put(struct reset_control_array *resets)
-{
-	int i;
-
-	if (IS_ERR_OR_NULL(resets))
-		return;
-
-	for (i = 0; i < resets->num_rstcs; i++)
-		reset_control_put(resets->rstc[i]);
-
-	kfree(resets);
-}
-EXPORT_SYMBOL_GPL(reset_control_array_put);
diff --git a/include/linux/reset.h b/include/linux/reset.h
index df75fe50f765d..0f1be13e66e46 100644
--- a/include/linux/reset.h
+++ b/include/linux/reset.h
@@ -5,11 +5,6 @@
 
 struct reset_control;
 
-struct reset_control_array {
-	unsigned int num_rstcs;
-	struct reset_control *rstc[];
-};
-
 #ifdef CONFIG_RESET_CONTROLLER
 
 int reset_control_reset(struct reset_control *rstc);
@@ -30,13 +25,10 @@ struct reset_control *__devm_reset_control_get(struct device *dev,
 
 int __must_check device_reset(struct device *dev);
 
-int reset_control_array_assert(struct reset_control_array *resets);
-int reset_control_array_deassert(struct reset_control_array *resets);
-struct reset_control_array *devm_reset_control_array_get(struct device *dev,
-						bool shared, bool optional);
-struct reset_control_array *of_reset_control_array_get(struct device_node *np,
-						bool shared, bool optional);
-void reset_control_array_put(struct reset_control_array *resets);
+struct reset_control *devm_reset_control_array_get(struct device *dev,
+						   bool shared, bool optional);
+struct reset_control *of_reset_control_array_get(struct device_node *np,
+						 bool shared, bool optional);
 
 static inline int device_reset_optional(struct device *dev)
 {
@@ -102,18 +94,6 @@ static inline struct reset_control *__devm_reset_control_get(
 	return optional ? NULL : ERR_PTR(-ENOTSUPP);
 }
 
-static inline
-int reset_control_array_assert(struct reset_control_array *resets)
-{
-	return 0;
-}
-
-static inline
-int reset_control_array_deassert(struct reset_control_array *resets)
-{
-	return 0;
-}
-
 static inline struct reset_control_array *
 devm_reset_control_array_get(struct device *dev, bool shared, bool optional)
 {
@@ -420,49 +400,49 @@ static inline struct reset_control *devm_reset_control_get_by_index(
 /*
  * APIs to manage a list of reset controllers
  */
-static inline struct reset_control_array *
+static inline struct reset_control *
 devm_reset_control_array_get_exclusive(struct device *dev)
 {
 	return devm_reset_control_array_get(dev, false, false);
 }
 
-static inline struct reset_control_array *
+static inline struct reset_control *
 devm_reset_control_array_get_shared(struct device *dev)
 {
 	return devm_reset_control_array_get(dev, true, false);
 }
 
-static inline struct reset_control_array *
+static inline struct reset_control *
 devm_reset_control_array_get_optional_exclusive(struct device *dev)
 {
 	return devm_reset_control_array_get(dev, false, true);
 }
 
-static inline struct reset_control_array *
+static inline struct reset_control *
 devm_reset_control_array_get_optional_shared(struct device *dev)
 {
 	return devm_reset_control_array_get(dev, true, true);
 }
 
-static inline struct reset_control_array *
+static inline struct reset_control *
 of_reset_control_array_get_exclusive(struct device_node *node)
 {
 	return of_reset_control_array_get(node, false, false);
 }
 
-static inline struct reset_control_array *
+static inline struct reset_control *
 of_reset_control_array_get_shared(struct device_node *node)
 {
 	return of_reset_control_array_get(node, true, false);
 }
 
-static inline struct reset_control_array *
+static inline struct reset_control *
 of_reset_control_array_get_optional_exclusive(struct device_node *node)
 {
 	return of_reset_control_array_get(node, false, true);
 }
 
-static inline struct reset_control_array *
+static inline struct reset_control *
 of_reset_control_array_get_optional_shared(struct device_node *node)
 {
 	return of_reset_control_array_get(node, true, true);
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v5 3/6] reset: hide reset control arrays behind struct reset_control
@ 2017-06-01 16:52     ` Philipp Zabel
  0 siblings, 0 replies; 21+ messages in thread
From: Philipp Zabel @ 2017-06-01 16:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Vivek Gautam, Jon Hunter, Felipe Balbi, Greg Kroah-Hartman,
	Thierry Reding, linux-tegra, linux-usb, linux-arm-msm,
	Philipp Zabel

Reset controls already may control multiple reset lines with a single
hardware bit. So from the user perspective, reset control arrays are not
at all different from single reset controls.
Therefore, hide reset control arrays behind struct reset_control to
avoid having to introduce new API functions for array (de)assert/reset.

Cc: Vivek Gautam <vivek.gautam@codeaurora.org>
Cc: Jon Hunter <jonathanh@nvidia.com>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
 drivers/reset/core.c  | 225 ++++++++++++++++++++++++++------------------------
 include/linux/reset.h |  44 +++-------
 2 files changed, 128 insertions(+), 141 deletions(-)

diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 1747000757211..c8fb4426b218a 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -43,11 +43,24 @@ struct reset_control {
 	unsigned int id;
 	struct kref refcnt;
 	bool shared;
+	bool array;
 	atomic_t deassert_count;
 	atomic_t triggered_count;
 };
 
 /**
+ * struct reset_control_array - an array of reset controls
+ * @base: reset control for compatibility with reset control API functions
+ * @num_rstcs: number of reset controls
+ * @rstc: array of reset controls
+ */
+struct reset_control_array {
+	struct reset_control base;
+	unsigned int num_rstcs;
+	struct reset_control *rstc[];
+};
+
+/**
  * of_reset_simple_xlate - translate reset_spec to the reset line number
  * @rcdev: a pointer to the reset controller device
  * @reset_spec: reset line specifier as found in the device tree
@@ -135,6 +148,65 @@ int devm_reset_controller_register(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(devm_reset_controller_register);
 
+static inline struct reset_control_array *
+rstc_to_array(struct reset_control *rstc) {
+	return container_of(rstc, struct reset_control_array, base);
+}
+
+static int reset_control_array_reset(struct reset_control_array *resets)
+{
+	int ret, i;
+
+	for (i = 0; i < resets->num_rstcs; i++) {
+		ret = reset_control_reset(resets->rstc[i]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int reset_control_array_assert(struct reset_control_array *resets)
+{
+	int ret, i;
+
+	for (i = 0; i < resets->num_rstcs; i++) {
+		ret = reset_control_assert(resets->rstc[i]);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	while (i--)
+		reset_control_deassert(resets->rstc[i]);
+	return ret;
+}
+
+static int reset_control_array_deassert(struct reset_control_array *resets)
+{
+	int ret, i;
+
+	for (i = 0; i < resets->num_rstcs; i++) {
+		ret = reset_control_deassert(resets->rstc[i]);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	while (i--)
+		reset_control_assert(resets->rstc[i]);
+	return ret;
+}
+
+static inline bool reset_control_is_array(struct reset_control *rstc)
+{
+	return rstc->array;
+}
+
 /**
  * reset_control_reset - reset the controlled device
  * @rstc: reset controller
@@ -158,6 +230,9 @@ int reset_control_reset(struct reset_control *rstc)
 	if (WARN_ON(IS_ERR(rstc)))
 		return -EINVAL;
 
+	if (reset_control_is_array(rstc))
+		return reset_control_array_reset(rstc_to_array(rstc));
+
 	if (!rstc->rcdev->ops->reset)
 		return -ENOTSUPP;
 
@@ -202,6 +277,9 @@ int reset_control_assert(struct reset_control *rstc)
 	if (WARN_ON(IS_ERR(rstc)))
 		return -EINVAL;
 
+	if (reset_control_is_array(rstc))
+		return reset_control_array_assert(rstc_to_array(rstc));
+
 	if (!rstc->rcdev->ops->assert)
 		return -ENOTSUPP;
 
@@ -240,6 +318,9 @@ int reset_control_deassert(struct reset_control *rstc)
 	if (WARN_ON(IS_ERR(rstc)))
 		return -EINVAL;
 
+	if (reset_control_is_array(rstc))
+		return reset_control_array_deassert(rstc_to_array(rstc));
+
 	if (!rstc->rcdev->ops->deassert)
 		return -ENOTSUPP;
 
@@ -266,7 +347,7 @@ int reset_control_status(struct reset_control *rstc)
 	if (!rstc)
 		return 0;
 
-	if (WARN_ON(IS_ERR(rstc)))
+	if (WARN_ON(IS_ERR(rstc)) || reset_control_is_array(rstc))
 		return -EINVAL;
 
 	if (rstc->rcdev->ops->status)
@@ -404,6 +485,16 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id,
 }
 EXPORT_SYMBOL_GPL(__reset_control_get);
 
+static void reset_control_array_put(struct reset_control_array *resets)
+{
+	int i;
+
+	mutex_lock(&reset_list_mutex);
+	for (i = 0; i < resets->num_rstcs; i++)
+		__reset_control_put_internal(resets->rstc[i]);
+	mutex_unlock(&reset_list_mutex);
+}
+
 /**
  * reset_control_put - free the reset controller
  * @rstc: reset controller
@@ -413,6 +504,11 @@ void reset_control_put(struct reset_control *rstc)
 	if (IS_ERR_OR_NULL(rstc))
 		return;
 
+	if (reset_control_is_array(rstc)) {
+		reset_control_array_put(rstc_to_array(rstc));
+		return;
+	}
+
 	mutex_lock(&reset_list_mutex);
 	__reset_control_put_internal(rstc);
 	mutex_unlock(&reset_list_mutex);
@@ -499,81 +595,6 @@ static int of_reset_control_get_count(struct device_node *node)
 }
 
 /**
- * reset_control_array_assert: assert a list of resets
- *
- * @resets: reset control array holding info about the list of resets
- *
- * This API doesn't guarantee that the reset lines controlled by
- * the reset array are asserted in any particular order.
- *
- * Returns 0 on success or error number on failure.
- */
-int reset_control_array_assert(struct reset_control_array *resets)
-{
-	int ret, i;
-
-	if (!resets)
-		return 0;
-
-	if (IS_ERR(resets))
-		return -EINVAL;
-
-	for (i = 0; i < resets->num_rstcs; i++) {
-		ret = reset_control_assert(resets->rstc[i]);
-		if (ret)
-			goto err;
-	}
-
-	return 0;
-
-err:
-	while (i--)
-		reset_control_deassert(resets->rstc[i]);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(reset_control_array_assert);
-
-/**
- * reset_control_array_deassert: deassert a list of resets
- *
- * @resets: reset control array holding info about the list of resets
- *
- * This API doesn't guarantee that the reset lines controlled by
- * the reset array are deasserted in any particular order.
- *
- * Returns 0 on success or error number on failure.
- */
-int reset_control_array_deassert(struct reset_control_array *resets)
-{
-	int ret, i;
-
-	if (!resets)
-		return 0;
-
-	if (IS_ERR(resets))
-		return -EINVAL;
-
-	for (i = 0; i < resets->num_rstcs; i++) {
-		ret = reset_control_deassert(resets->rstc[i]);
-		if (ret)
-			goto err;
-	}
-
-	return 0;
-
-err:
-	while (i--)
-		reset_control_assert(resets->rstc[i]);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(reset_control_array_deassert);
-
-static void devm_reset_control_array_release(struct device *dev, void *res)
-{
-	reset_control_array_put(*(struct reset_control_array **)res);
-}
-
-/**
  * of_reset_control_array_get - Get a list of reset controls using
  *				device node.
  *
@@ -584,13 +605,12 @@ static void devm_reset_control_array_release(struct device *dev, void *res)
  * Returns pointer to allocated reset_control_array on success or
  * error on failure
  */
-struct reset_control_array *
+struct reset_control *
 of_reset_control_array_get(struct device_node *np, bool shared, bool optional)
 {
 	struct reset_control_array *resets;
 	struct reset_control *rstc;
 	int num, i;
-	void *err;
 
 	num = of_reset_control_get_count(np);
 	if (num < 0)
@@ -603,23 +623,24 @@ of_reset_control_array_get(struct device_node *np, bool shared, bool optional)
 
 	for (i = 0; i < num; i++) {
 		rstc = __of_reset_control_get(np, NULL, i, shared, optional);
-		if (IS_ERR(rstc)) {
-			err = ERR_CAST(rstc);
+		if (IS_ERR(rstc))
 			goto err_rst;
-		}
 		resets->rstc[i] = rstc;
 	}
 	resets->num_rstcs = num;
+	resets->base.array = true;
 
-	return resets;
+	return &resets->base;
 
 err_rst:
+	mutex_lock(&reset_list_mutex);
 	while (--i >= 0)
-		reset_control_put(resets->rstc[i]);
+		__reset_control_put_internal(resets->rstc[i]);
+	mutex_unlock(&reset_list_mutex);
 
 	kfree(resets);
 
-	return err;
+	return rstc;
 }
 EXPORT_SYMBOL_GPL(of_reset_control_array_get);
 
@@ -637,40 +658,26 @@ EXPORT_SYMBOL_GPL(of_reset_control_array_get);
  * Returns pointer to allocated reset_control_array on success or
  * error on failure
  */
-struct reset_control_array *
+struct reset_control *
 devm_reset_control_array_get(struct device *dev, bool shared, bool optional)
 {
-	struct reset_control_array **devres;
-	struct reset_control_array *resets;
+	struct reset_control **devres;
+	struct reset_control *rstc;
 
-	devres = devres_alloc(devm_reset_control_array_release,
-			      sizeof(*devres), GFP_KERNEL);
+	devres = devres_alloc(devm_reset_control_release, sizeof(*devres),
+			      GFP_KERNEL);
 	if (!devres)
 		return ERR_PTR(-ENOMEM);
 
-	resets = of_reset_control_array_get(dev->of_node, shared, optional);
-	if (IS_ERR(resets)) {
-		devres_free(resets);
-		return resets;
+	rstc = of_reset_control_array_get(dev->of_node, shared, optional);
+	if (IS_ERR(rstc)) {
+		devres_free(devres);
+		return rstc;
 	}
 
-	*devres = resets;
+	*devres = rstc;
 	devres_add(dev, devres);
 
-	return resets;
+	return rstc;
 }
 EXPORT_SYMBOL_GPL(devm_reset_control_array_get);
-
-void reset_control_array_put(struct reset_control_array *resets)
-{
-	int i;
-
-	if (IS_ERR_OR_NULL(resets))
-		return;
-
-	for (i = 0; i < resets->num_rstcs; i++)
-		reset_control_put(resets->rstc[i]);
-
-	kfree(resets);
-}
-EXPORT_SYMBOL_GPL(reset_control_array_put);
diff --git a/include/linux/reset.h b/include/linux/reset.h
index df75fe50f765d..0f1be13e66e46 100644
--- a/include/linux/reset.h
+++ b/include/linux/reset.h
@@ -5,11 +5,6 @@
 
 struct reset_control;
 
-struct reset_control_array {
-	unsigned int num_rstcs;
-	struct reset_control *rstc[];
-};
-
 #ifdef CONFIG_RESET_CONTROLLER
 
 int reset_control_reset(struct reset_control *rstc);
@@ -30,13 +25,10 @@ struct reset_control *__devm_reset_control_get(struct device *dev,
 
 int __must_check device_reset(struct device *dev);
 
-int reset_control_array_assert(struct reset_control_array *resets);
-int reset_control_array_deassert(struct reset_control_array *resets);
-struct reset_control_array *devm_reset_control_array_get(struct device *dev,
-						bool shared, bool optional);
-struct reset_control_array *of_reset_control_array_get(struct device_node *np,
-						bool shared, bool optional);
-void reset_control_array_put(struct reset_control_array *resets);
+struct reset_control *devm_reset_control_array_get(struct device *dev,
+						   bool shared, bool optional);
+struct reset_control *of_reset_control_array_get(struct device_node *np,
+						 bool shared, bool optional);
 
 static inline int device_reset_optional(struct device *dev)
 {
@@ -102,18 +94,6 @@ static inline struct reset_control *__devm_reset_control_get(
 	return optional ? NULL : ERR_PTR(-ENOTSUPP);
 }
 
-static inline
-int reset_control_array_assert(struct reset_control_array *resets)
-{
-	return 0;
-}
-
-static inline
-int reset_control_array_deassert(struct reset_control_array *resets)
-{
-	return 0;
-}
-
 static inline struct reset_control_array *
 devm_reset_control_array_get(struct device *dev, bool shared, bool optional)
 {
@@ -420,49 +400,49 @@ static inline struct reset_control *devm_reset_control_get_by_index(
 /*
  * APIs to manage a list of reset controllers
  */
-static inline struct reset_control_array *
+static inline struct reset_control *
 devm_reset_control_array_get_exclusive(struct device *dev)
 {
 	return devm_reset_control_array_get(dev, false, false);
 }
 
-static inline struct reset_control_array *
+static inline struct reset_control *
 devm_reset_control_array_get_shared(struct device *dev)
 {
 	return devm_reset_control_array_get(dev, true, false);
 }
 
-static inline struct reset_control_array *
+static inline struct reset_control *
 devm_reset_control_array_get_optional_exclusive(struct device *dev)
 {
 	return devm_reset_control_array_get(dev, false, true);
 }
 
-static inline struct reset_control_array *
+static inline struct reset_control *
 devm_reset_control_array_get_optional_shared(struct device *dev)
 {
 	return devm_reset_control_array_get(dev, true, true);
 }
 
-static inline struct reset_control_array *
+static inline struct reset_control *
 of_reset_control_array_get_exclusive(struct device_node *node)
 {
 	return of_reset_control_array_get(node, false, false);
 }
 
-static inline struct reset_control_array *
+static inline struct reset_control *
 of_reset_control_array_get_shared(struct device_node *node)
 {
 	return of_reset_control_array_get(node, true, false);
 }
 
-static inline struct reset_control_array *
+static inline struct reset_control *
 of_reset_control_array_get_optional_exclusive(struct device_node *node)
 {
 	return of_reset_control_array_get(node, false, true);
 }
 
-static inline struct reset_control_array *
+static inline struct reset_control *
 of_reset_control_array_get_optional_shared(struct device_node *node)
 {
 	return of_reset_control_array_get(node, true, true);
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v5 4/6] usb: dwc3: of-simple: Re-order resource handling in remove
  2017-06-01 16:51 [PATCH v5 0/6] reset: APIs to manage a list of resets Philipp Zabel
  2017-06-01 16:51 ` [PATCH v5 2/6] reset: Add APIs to manage array " Philipp Zabel
       [not found] ` <20170601165203.15315-1-p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
@ 2017-06-01 16:52 ` Philipp Zabel
  2 siblings, 0 replies; 21+ messages in thread
From: Philipp Zabel @ 2017-06-01 16:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Vivek Gautam, Jon Hunter, Felipe Balbi, Greg Kroah-Hartman,
	Thierry Reding, linux-tegra, linux-usb, linux-arm-msm

From: Vivek Gautam <vivek.gautam@codeaurora.org>

Move clock handling after of_platform_depopulate to achieve
a sequence that is reverse of the probe sequence.

Cc: Felipe Balbi <balbi@kernel.org>
Signed-off-by: Vivek Gautam <vivek.gautam@codeaurora.org>
---
 drivers/usb/dwc3/dwc3-of-simple.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c
index fe414e7a9c78c..a9bac09d3750d 100644
--- a/drivers/usb/dwc3/dwc3-of-simple.c
+++ b/drivers/usb/dwc3/dwc3-of-simple.c
@@ -123,13 +123,13 @@ static int dwc3_of_simple_remove(struct platform_device *pdev)
 	struct device		*dev = &pdev->dev;
 	int			i;
 
+	of_platform_depopulate(dev);
+
 	for (i = 0; i < simple->num_clocks; i++) {
 		clk_disable_unprepare(simple->clks[i]);
 		clk_put(simple->clks[i]);
 	}
 
-	of_platform_depopulate(dev);
-
 	pm_runtime_put_sync(dev);
 	pm_runtime_disable(dev);
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v5 5/6] usb: dwc3: of-simple: Add support to get resets for the device
  2017-06-01 16:51 [PATCH v5 0/6] reset: APIs to manage a list of resets Philipp Zabel
@ 2017-06-01 16:52     ` Philipp Zabel
       [not found] ` <20170601165203.15315-1-p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
  2017-06-01 16:52 ` [PATCH v5 4/6] usb: dwc3: of-simple: Re-order resource handling in remove Philipp Zabel
  2 siblings, 0 replies; 21+ messages in thread
From: Philipp Zabel @ 2017-06-01 16:52 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Vivek Gautam, Jon Hunter, Felipe Balbi, Greg Kroah-Hartman,
	Thierry Reding, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, Philipp Zabel

From: Vivek Gautam <vivek.gautam-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>

Add support to get a list of resets available for the device.
These resets must be kept de-asserted until the device is
in use.

Cc: Felipe Balbi <balbi-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Signed-off-by: Vivek Gautam <vivek.gautam-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
[p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org: switch to hidden reset control array]
Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
 drivers/usb/dwc3/dwc3-of-simple.c | 27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c
index a9bac09d3750d..23d2221bde9df 100644
--- a/drivers/usb/dwc3/dwc3-of-simple.c
+++ b/drivers/usb/dwc3/dwc3-of-simple.c
@@ -29,11 +29,13 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/pm_runtime.h>
+#include <linux/reset.h>
 
 struct dwc3_of_simple {
 	struct device		*dev;
 	struct clk		**clks;
 	int			num_clocks;
+	struct reset_control	*resets;
 };
 
 static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count)
@@ -96,9 +98,20 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, simple);
 	simple->dev = dev;
 
+	simple->resets = of_reset_control_array_get_optional_exclusive(np);
+	if (IS_ERR(simple->resets)) {
+		ret = PTR_ERR(simple->resets);
+		dev_err(dev, "failed to get device resets, err=%d\n", ret);
+		return ret;
+	}
+
+	ret = reset_control_deassert(simple->resets);
+	if (ret)
+		goto err_resetc_put;
+
 	ret = dwc3_of_simple_clk_init(simple, of_clk_get_parent_count(np));
 	if (ret)
-		return ret;
+		goto err_resetc_assert;
 
 	ret = of_platform_populate(np, NULL, NULL, dev);
 	if (ret) {
@@ -107,7 +120,7 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
 			clk_put(simple->clks[i]);
 		}
 
-		return ret;
+		goto err_resetc_assert;
 	}
 
 	pm_runtime_set_active(dev);
@@ -115,6 +128,13 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
 	pm_runtime_get_sync(dev);
 
 	return 0;
+
+err_resetc_assert:
+	reset_control_assert(simple->resets);
+
+err_resetc_put:
+	reset_control_put(simple->resets);
+	return ret;
 }
 
 static int dwc3_of_simple_remove(struct platform_device *pdev)
@@ -130,6 +150,9 @@ static int dwc3_of_simple_remove(struct platform_device *pdev)
 		clk_put(simple->clks[i]);
 	}
 
+	reset_control_assert(simple->resets);
+	reset_control_put(simple->resets);
+
 	pm_runtime_put_sync(dev);
 	pm_runtime_disable(dev);
 
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v5 5/6] usb: dwc3: of-simple: Add support to get resets for the device
@ 2017-06-01 16:52     ` Philipp Zabel
  0 siblings, 0 replies; 21+ messages in thread
From: Philipp Zabel @ 2017-06-01 16:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Vivek Gautam, Jon Hunter, Felipe Balbi, Greg Kroah-Hartman,
	Thierry Reding, linux-tegra, linux-usb, linux-arm-msm,
	Philipp Zabel

From: Vivek Gautam <vivek.gautam@codeaurora.org>

Add support to get a list of resets available for the device.
These resets must be kept de-asserted until the device is
in use.

Cc: Felipe Balbi <balbi@kernel.org>
Signed-off-by: Vivek Gautam <vivek.gautam@codeaurora.org>
[p.zabel@pengutronix.de: switch to hidden reset control array]
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
 drivers/usb/dwc3/dwc3-of-simple.c | 27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c
index a9bac09d3750d..23d2221bde9df 100644
--- a/drivers/usb/dwc3/dwc3-of-simple.c
+++ b/drivers/usb/dwc3/dwc3-of-simple.c
@@ -29,11 +29,13 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/pm_runtime.h>
+#include <linux/reset.h>
 
 struct dwc3_of_simple {
 	struct device		*dev;
 	struct clk		**clks;
 	int			num_clocks;
+	struct reset_control	*resets;
 };
 
 static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count)
@@ -96,9 +98,20 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, simple);
 	simple->dev = dev;
 
+	simple->resets = of_reset_control_array_get_optional_exclusive(np);
+	if (IS_ERR(simple->resets)) {
+		ret = PTR_ERR(simple->resets);
+		dev_err(dev, "failed to get device resets, err=%d\n", ret);
+		return ret;
+	}
+
+	ret = reset_control_deassert(simple->resets);
+	if (ret)
+		goto err_resetc_put;
+
 	ret = dwc3_of_simple_clk_init(simple, of_clk_get_parent_count(np));
 	if (ret)
-		return ret;
+		goto err_resetc_assert;
 
 	ret = of_platform_populate(np, NULL, NULL, dev);
 	if (ret) {
@@ -107,7 +120,7 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
 			clk_put(simple->clks[i]);
 		}
 
-		return ret;
+		goto err_resetc_assert;
 	}
 
 	pm_runtime_set_active(dev);
@@ -115,6 +128,13 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
 	pm_runtime_get_sync(dev);
 
 	return 0;
+
+err_resetc_assert:
+	reset_control_assert(simple->resets);
+
+err_resetc_put:
+	reset_control_put(simple->resets);
+	return ret;
 }
 
 static int dwc3_of_simple_remove(struct platform_device *pdev)
@@ -130,6 +150,9 @@ static int dwc3_of_simple_remove(struct platform_device *pdev)
 		clk_put(simple->clks[i]);
 	}
 
+	reset_control_assert(simple->resets);
+	reset_control_put(simple->resets);
+
 	pm_runtime_put_sync(dev);
 	pm_runtime_disable(dev);
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v5 6/6] soc/tegra: pmc: Use the new reset APIs to manage reset controllers
  2017-06-01 16:51 [PATCH v5 0/6] reset: APIs to manage a list of resets Philipp Zabel
@ 2017-06-01 16:52     ` Philipp Zabel
       [not found] ` <20170601165203.15315-1-p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
  2017-06-01 16:52 ` [PATCH v5 4/6] usb: dwc3: of-simple: Re-order resource handling in remove Philipp Zabel
  2 siblings, 0 replies; 21+ messages in thread
From: Philipp Zabel @ 2017-06-01 16:52 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Vivek Gautam, Jon Hunter, Felipe Balbi, Greg Kroah-Hartman,
	Thierry Reding, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, Philipp Zabel

From: Vivek Gautam <vivek.gautam-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>

Make use of reset_control_array_*() set of APIs to manage
an array of reset controllers available with the device.

Cc: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Cc: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Cc: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Signed-off-by: Vivek Gautam <vivek.gautam-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
 drivers/soc/tegra/pmc.c | 82 ++++++++++++-------------------------------------
 1 file changed, 20 insertions(+), 62 deletions(-)

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index e233dd5dcab3d..749b218147a19 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -124,8 +124,7 @@ struct tegra_powergate {
 	unsigned int id;
 	struct clk **clks;
 	unsigned int num_clks;
-	struct reset_control **resets;
-	unsigned int num_resets;
+	struct reset_control *reset;
 };
 
 struct tegra_io_pad_soc {
@@ -348,32 +347,14 @@ static int tegra_powergate_enable_clocks(struct tegra_powergate *pg)
 	return err;
 }
 
-static int tegra_powergate_reset_assert(struct tegra_powergate *pg)
+static inline int tegra_powergate_reset_assert(struct tegra_powergate *pg)
 {
-	unsigned int i;
-	int err;
-
-	for (i = 0; i < pg->num_resets; i++) {
-		err = reset_control_assert(pg->resets[i]);
-		if (err)
-			return err;
-	}
-
-	return 0;
+	return reset_control_assert(pg->reset);
 }
 
-static int tegra_powergate_reset_deassert(struct tegra_powergate *pg)
+static inline int tegra_powergate_reset_deassert(struct tegra_powergate *pg)
 {
-	unsigned int i;
-	int err;
-
-	for (i = 0; i < pg->num_resets; i++) {
-		err = reset_control_deassert(pg->resets[i]);
-		if (err)
-			return err;
-	}
-
-	return 0;
+	return reset_control_deassert(pg->reset);
 }
 
 static int tegra_powergate_power_up(struct tegra_powergate *pg,
@@ -566,8 +547,7 @@ int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
 	pg.id = id;
 	pg.clks = &clk;
 	pg.num_clks = 1;
-	pg.resets = &rst;
-	pg.num_resets = 1;
+	pg.reset = IS_ERR(rst) ? NULL : rst;
 
 	err = tegra_powergate_power_up(&pg, false);
 	if (err)
@@ -755,45 +735,26 @@ static int tegra_powergate_of_get_clks(struct tegra_powergate *pg,
 static int tegra_powergate_of_get_resets(struct tegra_powergate *pg,
 					 struct device_node *np, bool off)
 {
-	struct reset_control *rst;
-	unsigned int i, count;
 	int err;
 
-	count = of_count_phandle_with_args(np, "resets", "#reset-cells");
-	if (count == 0)
-		return -ENODEV;
-
-	pg->resets = kcalloc(count, sizeof(rst), GFP_KERNEL);
-	if (!pg->resets)
-		return -ENOMEM;
-
-	for (i = 0; i < count; i++) {
-		pg->resets[i] = of_reset_control_get_by_index(np, i);
-		if (IS_ERR(pg->resets[i])) {
-			err = PTR_ERR(pg->resets[i]);
-			goto error;
-		}
-
-		if (off)
-			err = reset_control_assert(pg->resets[i]);
-		else
-			err = reset_control_deassert(pg->resets[i]);
-
-		if (err) {
-			reset_control_put(pg->resets[i]);
-			goto error;
-		}
+	pg->reset = of_reset_control_array_get_exclusive(np);
+	if (IS_ERR(pg->reset)) {
+		pr_err("failed to get device resets\n");
+		return PTR_ERR(pg->reset);
 	}
 
-	pg->num_resets = count;
+	if (off)
+		err = reset_control_assert(pg->reset);
+	else
+		err = reset_control_deassert(pg->reset);
 
-	return 0;
+	if (err)
+		goto put_reset;
 
-error:
-	while (i--)
-		reset_control_put(pg->resets[i]);
+	return 0;
 
-	kfree(pg->resets);
+put_reset:
+	reset_control_put(pg->reset);
 
 	return err;
 }
@@ -885,10 +846,7 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
 	pm_genpd_remove(&pg->genpd);
 
 remove_resets:
-	while (pg->num_resets--)
-		reset_control_put(pg->resets[pg->num_resets]);
-
-	kfree(pg->resets);
+	reset_control_put(pg->reset);
 
 remove_clks:
 	while (pg->num_clks--)
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v5 6/6] soc/tegra: pmc: Use the new reset APIs to manage reset controllers
@ 2017-06-01 16:52     ` Philipp Zabel
  0 siblings, 0 replies; 21+ messages in thread
From: Philipp Zabel @ 2017-06-01 16:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Vivek Gautam, Jon Hunter, Felipe Balbi, Greg Kroah-Hartman,
	Thierry Reding, linux-tegra, linux-usb, linux-arm-msm,
	Philipp Zabel

From: Vivek Gautam <vivek.gautam@codeaurora.org>

Make use of reset_control_array_*() set of APIs to manage
an array of reset controllers available with the device.

Cc: Jon Hunter <jonathanh@nvidia.com>
Cc: Thierry Reding <treding@nvidia.com>
Cc: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Vivek Gautam <vivek.gautam@codeaurora.org>
---
 drivers/soc/tegra/pmc.c | 82 ++++++++++++-------------------------------------
 1 file changed, 20 insertions(+), 62 deletions(-)

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index e233dd5dcab3d..749b218147a19 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -124,8 +124,7 @@ struct tegra_powergate {
 	unsigned int id;
 	struct clk **clks;
 	unsigned int num_clks;
-	struct reset_control **resets;
-	unsigned int num_resets;
+	struct reset_control *reset;
 };
 
 struct tegra_io_pad_soc {
@@ -348,32 +347,14 @@ static int tegra_powergate_enable_clocks(struct tegra_powergate *pg)
 	return err;
 }
 
-static int tegra_powergate_reset_assert(struct tegra_powergate *pg)
+static inline int tegra_powergate_reset_assert(struct tegra_powergate *pg)
 {
-	unsigned int i;
-	int err;
-
-	for (i = 0; i < pg->num_resets; i++) {
-		err = reset_control_assert(pg->resets[i]);
-		if (err)
-			return err;
-	}
-
-	return 0;
+	return reset_control_assert(pg->reset);
 }
 
-static int tegra_powergate_reset_deassert(struct tegra_powergate *pg)
+static inline int tegra_powergate_reset_deassert(struct tegra_powergate *pg)
 {
-	unsigned int i;
-	int err;
-
-	for (i = 0; i < pg->num_resets; i++) {
-		err = reset_control_deassert(pg->resets[i]);
-		if (err)
-			return err;
-	}
-
-	return 0;
+	return reset_control_deassert(pg->reset);
 }
 
 static int tegra_powergate_power_up(struct tegra_powergate *pg,
@@ -566,8 +547,7 @@ int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
 	pg.id = id;
 	pg.clks = &clk;
 	pg.num_clks = 1;
-	pg.resets = &rst;
-	pg.num_resets = 1;
+	pg.reset = IS_ERR(rst) ? NULL : rst;
 
 	err = tegra_powergate_power_up(&pg, false);
 	if (err)
@@ -755,45 +735,26 @@ static int tegra_powergate_of_get_clks(struct tegra_powergate *pg,
 static int tegra_powergate_of_get_resets(struct tegra_powergate *pg,
 					 struct device_node *np, bool off)
 {
-	struct reset_control *rst;
-	unsigned int i, count;
 	int err;
 
-	count = of_count_phandle_with_args(np, "resets", "#reset-cells");
-	if (count == 0)
-		return -ENODEV;
-
-	pg->resets = kcalloc(count, sizeof(rst), GFP_KERNEL);
-	if (!pg->resets)
-		return -ENOMEM;
-
-	for (i = 0; i < count; i++) {
-		pg->resets[i] = of_reset_control_get_by_index(np, i);
-		if (IS_ERR(pg->resets[i])) {
-			err = PTR_ERR(pg->resets[i]);
-			goto error;
-		}
-
-		if (off)
-			err = reset_control_assert(pg->resets[i]);
-		else
-			err = reset_control_deassert(pg->resets[i]);
-
-		if (err) {
-			reset_control_put(pg->resets[i]);
-			goto error;
-		}
+	pg->reset = of_reset_control_array_get_exclusive(np);
+	if (IS_ERR(pg->reset)) {
+		pr_err("failed to get device resets\n");
+		return PTR_ERR(pg->reset);
 	}
 
-	pg->num_resets = count;
+	if (off)
+		err = reset_control_assert(pg->reset);
+	else
+		err = reset_control_deassert(pg->reset);
 
-	return 0;
+	if (err)
+		goto put_reset;
 
-error:
-	while (i--)
-		reset_control_put(pg->resets[i]);
+	return 0;
 
-	kfree(pg->resets);
+put_reset:
+	reset_control_put(pg->reset);
 
 	return err;
 }
@@ -885,10 +846,7 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
 	pm_genpd_remove(&pg->genpd);
 
 remove_resets:
-	while (pg->num_resets--)
-		reset_control_put(pg->resets[pg->num_resets]);
-
-	kfree(pg->resets);
+	reset_control_put(pg->reset);
 
 remove_clks:
 	while (pg->num_clks--)
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH v5 3/6] reset: hide reset control arrays behind struct reset_control
  2017-06-01 16:52     ` Philipp Zabel
@ 2017-06-01 23:09         ` kbuild test robot
  -1 siblings, 0 replies; 21+ messages in thread
From: kbuild test robot @ 2017-06-01 23:09 UTC (permalink / raw)
  Cc: kbuild-all-JC7UmRfGjtg, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	Vivek Gautam, Jon Hunter, Felipe Balbi, Greg Kroah-Hartman,
	Thierry Reding, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, Philipp Zabel

[-- Attachment #1: Type: text/plain, Size: 4386 bytes --]

Hi Philipp,

[auto build test ERROR on pza/reset/next]
[also build test ERROR on v4.12-rc3 next-20170601]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Philipp-Zabel/reset-APIs-to-manage-a-list-of-resets/20170602-062536
base:   git://git.pengutronix.de/git/pza/linux reset/next
config: i386-randconfig-x074-06010927 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   In file included from drivers/usb/dwc2/platform.c:48:0:
   include/linux/reset.h: In function 'devm_reset_control_array_get_exclusive':
>> include/linux/reset.h:406:9: error: return from incompatible pointer type [-Werror=incompatible-pointer-types]
     return devm_reset_control_array_get(dev, false, false);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/reset.h: In function 'devm_reset_control_array_get_shared':
   include/linux/reset.h:412:9: error: return from incompatible pointer type [-Werror=incompatible-pointer-types]
     return devm_reset_control_array_get(dev, true, false);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/reset.h: In function 'devm_reset_control_array_get_optional_exclusive':
   include/linux/reset.h:418:9: error: return from incompatible pointer type [-Werror=incompatible-pointer-types]
     return devm_reset_control_array_get(dev, false, true);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/reset.h: In function 'devm_reset_control_array_get_optional_shared':
   include/linux/reset.h:424:9: error: return from incompatible pointer type [-Werror=incompatible-pointer-types]
     return devm_reset_control_array_get(dev, true, true);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/reset.h: In function 'of_reset_control_array_get_exclusive':
   include/linux/reset.h:430:9: error: return from incompatible pointer type [-Werror=incompatible-pointer-types]
     return of_reset_control_array_get(node, false, false);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/reset.h: In function 'of_reset_control_array_get_shared':
   include/linux/reset.h:436:9: error: return from incompatible pointer type [-Werror=incompatible-pointer-types]
     return of_reset_control_array_get(node, true, false);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/reset.h: In function 'of_reset_control_array_get_optional_exclusive':
   include/linux/reset.h:442:9: error: return from incompatible pointer type [-Werror=incompatible-pointer-types]
     return of_reset_control_array_get(node, false, true);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/reset.h: In function 'of_reset_control_array_get_optional_shared':
   include/linux/reset.h:448:9: error: return from incompatible pointer type [-Werror=incompatible-pointer-types]
     return of_reset_control_array_get(node, true, true);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors

vim +406 include/linux/reset.h

1b1b64c5 Vivek Gautam  2017-06-01  400  /*
1b1b64c5 Vivek Gautam  2017-06-01  401   * APIs to manage a list of reset controllers
1b1b64c5 Vivek Gautam  2017-06-01  402   */
1abcb861 Philipp Zabel 2017-06-01  403  static inline struct reset_control *
1b1b64c5 Vivek Gautam  2017-06-01  404  devm_reset_control_array_get_exclusive(struct device *dev)
1b1b64c5 Vivek Gautam  2017-06-01  405  {
1b1b64c5 Vivek Gautam  2017-06-01 @406  	return devm_reset_control_array_get(dev, false, false);
1b1b64c5 Vivek Gautam  2017-06-01  407  }
1b1b64c5 Vivek Gautam  2017-06-01  408  
1abcb861 Philipp Zabel 2017-06-01  409  static inline struct reset_control *

:::::: The code at line 406 was first introduced by commit
:::::: 1b1b64c55c5f63e050938df44e1ccee33cfeee94 reset: Add APIs to manage array of resets

:::::: TO: Vivek Gautam <vivek.gautam-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
:::::: CC: 0day robot <fengguang.wu-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 23844 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v5 3/6] reset: hide reset control arrays behind struct reset_control
@ 2017-06-01 23:09         ` kbuild test robot
  0 siblings, 0 replies; 21+ messages in thread
From: kbuild test robot @ 2017-06-01 23:09 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: kbuild-all, linux-kernel, Vivek Gautam, Jon Hunter, Felipe Balbi,
	Greg Kroah-Hartman, Thierry Reding, linux-tegra, linux-usb,
	linux-arm-msm, Philipp Zabel

[-- Attachment #1: Type: text/plain, Size: 4331 bytes --]

Hi Philipp,

[auto build test ERROR on pza/reset/next]
[also build test ERROR on v4.12-rc3 next-20170601]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Philipp-Zabel/reset-APIs-to-manage-a-list-of-resets/20170602-062536
base:   git://git.pengutronix.de/git/pza/linux reset/next
config: i386-randconfig-x074-06010927 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   In file included from drivers/usb/dwc2/platform.c:48:0:
   include/linux/reset.h: In function 'devm_reset_control_array_get_exclusive':
>> include/linux/reset.h:406:9: error: return from incompatible pointer type [-Werror=incompatible-pointer-types]
     return devm_reset_control_array_get(dev, false, false);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/reset.h: In function 'devm_reset_control_array_get_shared':
   include/linux/reset.h:412:9: error: return from incompatible pointer type [-Werror=incompatible-pointer-types]
     return devm_reset_control_array_get(dev, true, false);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/reset.h: In function 'devm_reset_control_array_get_optional_exclusive':
   include/linux/reset.h:418:9: error: return from incompatible pointer type [-Werror=incompatible-pointer-types]
     return devm_reset_control_array_get(dev, false, true);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/reset.h: In function 'devm_reset_control_array_get_optional_shared':
   include/linux/reset.h:424:9: error: return from incompatible pointer type [-Werror=incompatible-pointer-types]
     return devm_reset_control_array_get(dev, true, true);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/reset.h: In function 'of_reset_control_array_get_exclusive':
   include/linux/reset.h:430:9: error: return from incompatible pointer type [-Werror=incompatible-pointer-types]
     return of_reset_control_array_get(node, false, false);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/reset.h: In function 'of_reset_control_array_get_shared':
   include/linux/reset.h:436:9: error: return from incompatible pointer type [-Werror=incompatible-pointer-types]
     return of_reset_control_array_get(node, true, false);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/reset.h: In function 'of_reset_control_array_get_optional_exclusive':
   include/linux/reset.h:442:9: error: return from incompatible pointer type [-Werror=incompatible-pointer-types]
     return of_reset_control_array_get(node, false, true);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/reset.h: In function 'of_reset_control_array_get_optional_shared':
   include/linux/reset.h:448:9: error: return from incompatible pointer type [-Werror=incompatible-pointer-types]
     return of_reset_control_array_get(node, true, true);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors

vim +406 include/linux/reset.h

1b1b64c5 Vivek Gautam  2017-06-01  400  /*
1b1b64c5 Vivek Gautam  2017-06-01  401   * APIs to manage a list of reset controllers
1b1b64c5 Vivek Gautam  2017-06-01  402   */
1abcb861 Philipp Zabel 2017-06-01  403  static inline struct reset_control *
1b1b64c5 Vivek Gautam  2017-06-01  404  devm_reset_control_array_get_exclusive(struct device *dev)
1b1b64c5 Vivek Gautam  2017-06-01  405  {
1b1b64c5 Vivek Gautam  2017-06-01 @406  	return devm_reset_control_array_get(dev, false, false);
1b1b64c5 Vivek Gautam  2017-06-01  407  }
1b1b64c5 Vivek Gautam  2017-06-01  408  
1abcb861 Philipp Zabel 2017-06-01  409  static inline struct reset_control *

:::::: The code at line 406 was first introduced by commit
:::::: 1b1b64c55c5f63e050938df44e1ccee33cfeee94 reset: Add APIs to manage array of resets

:::::: TO: Vivek Gautam <vivek.gautam@codeaurora.org>
:::::: CC: 0day robot <fengguang.wu@intel.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 23844 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v5 3/6] reset: hide reset control arrays behind struct reset_control
  2017-06-01 16:52     ` Philipp Zabel
@ 2017-06-02  0:12         ` kbuild test robot
  -1 siblings, 0 replies; 21+ messages in thread
From: kbuild test robot @ 2017-06-02  0:12 UTC (permalink / raw)
  Cc: kbuild-all-JC7UmRfGjtg, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	Vivek Gautam, Jon Hunter, Felipe Balbi, Greg Kroah-Hartman,
	Thierry Reding, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, Philipp Zabel

[-- Attachment #1: Type: text/plain, Size: 4616 bytes --]

Hi Philipp,

[auto build test WARNING on pza/reset/next]
[also build test WARNING on v4.12-rc3 next-20170601]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Philipp-Zabel/reset-APIs-to-manage-a-list-of-resets/20170602-062536
base:   git://git.pengutronix.de/git/pza/linux reset/next
config: x86_64-randconfig-i0-201722 (attached as .config)
compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All warnings (new ones prefixed by >>):

   In file included from drivers/i2c/busses/i2c-designware-platdrv.c:41:0:
   include/linux/reset.h: In function 'devm_reset_control_array_get_exclusive':
>> include/linux/reset.h:406:2: warning: return from incompatible pointer type
     return devm_reset_control_array_get(dev, false, false);
     ^
   include/linux/reset.h: In function 'devm_reset_control_array_get_shared':
   include/linux/reset.h:412:2: warning: return from incompatible pointer type
     return devm_reset_control_array_get(dev, true, false);
     ^
   include/linux/reset.h: In function 'devm_reset_control_array_get_optional_exclusive':
   include/linux/reset.h:418:2: warning: return from incompatible pointer type
     return devm_reset_control_array_get(dev, false, true);
     ^
   include/linux/reset.h: In function 'devm_reset_control_array_get_optional_shared':
   include/linux/reset.h:424:2: warning: return from incompatible pointer type
     return devm_reset_control_array_get(dev, true, true);
     ^
   include/linux/reset.h: In function 'of_reset_control_array_get_exclusive':
   include/linux/reset.h:430:2: warning: return from incompatible pointer type
     return of_reset_control_array_get(node, false, false);
     ^
   include/linux/reset.h: In function 'of_reset_control_array_get_shared':
   include/linux/reset.h:436:2: warning: return from incompatible pointer type
     return of_reset_control_array_get(node, true, false);
     ^
   include/linux/reset.h: In function 'of_reset_control_array_get_optional_exclusive':
   include/linux/reset.h:442:2: warning: return from incompatible pointer type
     return of_reset_control_array_get(node, false, true);
     ^
   include/linux/reset.h: In function 'of_reset_control_array_get_optional_shared':
   include/linux/reset.h:448:2: warning: return from incompatible pointer type
     return of_reset_control_array_get(node, true, true);
     ^

vim +406 include/linux/reset.h

a53e35db Lee Jones     2016-06-06  390  	return devm_reset_control_get_optional_exclusive(dev, id);
a53e35db Lee Jones     2016-06-06  391  
a53e35db Lee Jones     2016-06-06  392  }
a53e35db Lee Jones     2016-06-06  393  
a53e35db Lee Jones     2016-06-06  394  static inline struct reset_control *devm_reset_control_get_by_index(
a53e35db Lee Jones     2016-06-06  395  				struct device *dev, int index)
a53e35db Lee Jones     2016-06-06  396  {
a53e35db Lee Jones     2016-06-06  397  	return devm_reset_control_get_exclusive_by_index(dev, index);
a53e35db Lee Jones     2016-06-06  398  }
1b1b64c5 Vivek Gautam  2017-06-01  399  
1b1b64c5 Vivek Gautam  2017-06-01  400  /*
1b1b64c5 Vivek Gautam  2017-06-01  401   * APIs to manage a list of reset controllers
1b1b64c5 Vivek Gautam  2017-06-01  402   */
1abcb861 Philipp Zabel 2017-06-01  403  static inline struct reset_control *
1b1b64c5 Vivek Gautam  2017-06-01  404  devm_reset_control_array_get_exclusive(struct device *dev)
1b1b64c5 Vivek Gautam  2017-06-01  405  {
1b1b64c5 Vivek Gautam  2017-06-01 @406  	return devm_reset_control_array_get(dev, false, false);
1b1b64c5 Vivek Gautam  2017-06-01  407  }
1b1b64c5 Vivek Gautam  2017-06-01  408  
1abcb861 Philipp Zabel 2017-06-01  409  static inline struct reset_control *
1b1b64c5 Vivek Gautam  2017-06-01  410  devm_reset_control_array_get_shared(struct device *dev)
1b1b64c5 Vivek Gautam  2017-06-01  411  {
1b1b64c5 Vivek Gautam  2017-06-01  412  	return devm_reset_control_array_get(dev, true, false);
1b1b64c5 Vivek Gautam  2017-06-01  413  }
1b1b64c5 Vivek Gautam  2017-06-01  414  

:::::: The code at line 406 was first introduced by commit
:::::: 1b1b64c55c5f63e050938df44e1ccee33cfeee94 reset: Add APIs to manage array of resets

:::::: TO: Vivek Gautam <vivek.gautam-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
:::::: CC: 0day robot <fengguang.wu-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 26533 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v5 3/6] reset: hide reset control arrays behind struct reset_control
@ 2017-06-02  0:12         ` kbuild test robot
  0 siblings, 0 replies; 21+ messages in thread
From: kbuild test robot @ 2017-06-02  0:12 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: kbuild-all, linux-kernel, Vivek Gautam, Jon Hunter, Felipe Balbi,
	Greg Kroah-Hartman, Thierry Reding, linux-tegra, linux-usb,
	linux-arm-msm, Philipp Zabel

[-- Attachment #1: Type: text/plain, Size: 4561 bytes --]

Hi Philipp,

[auto build test WARNING on pza/reset/next]
[also build test WARNING on v4.12-rc3 next-20170601]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Philipp-Zabel/reset-APIs-to-manage-a-list-of-resets/20170602-062536
base:   git://git.pengutronix.de/git/pza/linux reset/next
config: x86_64-randconfig-i0-201722 (attached as .config)
compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All warnings (new ones prefixed by >>):

   In file included from drivers/i2c/busses/i2c-designware-platdrv.c:41:0:
   include/linux/reset.h: In function 'devm_reset_control_array_get_exclusive':
>> include/linux/reset.h:406:2: warning: return from incompatible pointer type
     return devm_reset_control_array_get(dev, false, false);
     ^
   include/linux/reset.h: In function 'devm_reset_control_array_get_shared':
   include/linux/reset.h:412:2: warning: return from incompatible pointer type
     return devm_reset_control_array_get(dev, true, false);
     ^
   include/linux/reset.h: In function 'devm_reset_control_array_get_optional_exclusive':
   include/linux/reset.h:418:2: warning: return from incompatible pointer type
     return devm_reset_control_array_get(dev, false, true);
     ^
   include/linux/reset.h: In function 'devm_reset_control_array_get_optional_shared':
   include/linux/reset.h:424:2: warning: return from incompatible pointer type
     return devm_reset_control_array_get(dev, true, true);
     ^
   include/linux/reset.h: In function 'of_reset_control_array_get_exclusive':
   include/linux/reset.h:430:2: warning: return from incompatible pointer type
     return of_reset_control_array_get(node, false, false);
     ^
   include/linux/reset.h: In function 'of_reset_control_array_get_shared':
   include/linux/reset.h:436:2: warning: return from incompatible pointer type
     return of_reset_control_array_get(node, true, false);
     ^
   include/linux/reset.h: In function 'of_reset_control_array_get_optional_exclusive':
   include/linux/reset.h:442:2: warning: return from incompatible pointer type
     return of_reset_control_array_get(node, false, true);
     ^
   include/linux/reset.h: In function 'of_reset_control_array_get_optional_shared':
   include/linux/reset.h:448:2: warning: return from incompatible pointer type
     return of_reset_control_array_get(node, true, true);
     ^

vim +406 include/linux/reset.h

a53e35db Lee Jones     2016-06-06  390  	return devm_reset_control_get_optional_exclusive(dev, id);
a53e35db Lee Jones     2016-06-06  391  
a53e35db Lee Jones     2016-06-06  392  }
a53e35db Lee Jones     2016-06-06  393  
a53e35db Lee Jones     2016-06-06  394  static inline struct reset_control *devm_reset_control_get_by_index(
a53e35db Lee Jones     2016-06-06  395  				struct device *dev, int index)
a53e35db Lee Jones     2016-06-06  396  {
a53e35db Lee Jones     2016-06-06  397  	return devm_reset_control_get_exclusive_by_index(dev, index);
a53e35db Lee Jones     2016-06-06  398  }
1b1b64c5 Vivek Gautam  2017-06-01  399  
1b1b64c5 Vivek Gautam  2017-06-01  400  /*
1b1b64c5 Vivek Gautam  2017-06-01  401   * APIs to manage a list of reset controllers
1b1b64c5 Vivek Gautam  2017-06-01  402   */
1abcb861 Philipp Zabel 2017-06-01  403  static inline struct reset_control *
1b1b64c5 Vivek Gautam  2017-06-01  404  devm_reset_control_array_get_exclusive(struct device *dev)
1b1b64c5 Vivek Gautam  2017-06-01  405  {
1b1b64c5 Vivek Gautam  2017-06-01 @406  	return devm_reset_control_array_get(dev, false, false);
1b1b64c5 Vivek Gautam  2017-06-01  407  }
1b1b64c5 Vivek Gautam  2017-06-01  408  
1abcb861 Philipp Zabel 2017-06-01  409  static inline struct reset_control *
1b1b64c5 Vivek Gautam  2017-06-01  410  devm_reset_control_array_get_shared(struct device *dev)
1b1b64c5 Vivek Gautam  2017-06-01  411  {
1b1b64c5 Vivek Gautam  2017-06-01  412  	return devm_reset_control_array_get(dev, true, false);
1b1b64c5 Vivek Gautam  2017-06-01  413  }
1b1b64c5 Vivek Gautam  2017-06-01  414  

:::::: The code at line 406 was first introduced by commit
:::::: 1b1b64c55c5f63e050938df44e1ccee33cfeee94 reset: Add APIs to manage array of resets

:::::: TO: Vivek Gautam <vivek.gautam@codeaurora.org>
:::::: CC: 0day robot <fengguang.wu@intel.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 26533 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v5 3/6] reset: hide reset control arrays behind struct reset_control
  2017-06-01 16:52     ` Philipp Zabel
  (?)
  (?)
@ 2017-06-13  6:46     ` Vivek Gautam
  2017-06-19 12:18       ` Philipp Zabel
  -1 siblings, 1 reply; 21+ messages in thread
From: Vivek Gautam @ 2017-06-13  6:46 UTC (permalink / raw)
  To: Philipp Zabel, linux-kernel
  Cc: Jon Hunter, Felipe Balbi, Greg Kroah-Hartman, Thierry Reding,
	linux-tegra, linux-usb, linux-arm-msm

Hi Philipp,


On 06/01/2017 10:22 PM, Philipp Zabel wrote:
> Reset controls already may control multiple reset lines with a single
> hardware bit. So from the user perspective, reset control arrays are not
> at all different from single reset controls.
> Therefore, hide reset control arrays behind struct reset_control to
> avoid having to introduce new API functions for array (de)assert/reset.
>
> Cc: Vivek Gautam <vivek.gautam@codeaurora.org>
> Cc: Jon Hunter <jonathanh@nvidia.com>
> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> ---
>   drivers/reset/core.c  | 225 ++++++++++++++++++++++++++------------------------
>   include/linux/reset.h |  44 +++-------
>   2 files changed, 128 insertions(+), 141 deletions(-)
>
> diff --git a/drivers/reset/core.c b/drivers/reset/core.c
> index 1747000757211..c8fb4426b218a 100644
> --- a/drivers/reset/core.c
> +++ b/drivers/reset/core.c
> @@ -43,11 +43,24 @@ struct reset_control {
>   	unsigned int id;
>   	struct kref refcnt;
>   	bool shared;
> +	bool array;
>   	atomic_t deassert_count;
>   	atomic_t triggered_count;
>   };
>   
>   /**
> + * struct reset_control_array - an array of reset controls
> + * @base: reset control for compatibility with reset control API functions
> + * @num_rstcs: number of reset controls
> + * @rstc: array of reset controls
> + */
> +struct reset_control_array {
> +	struct reset_control base;
> +	unsigned int num_rstcs;
> +	struct reset_control *rstc[];
> +};
> +
> +/**
>    * of_reset_simple_xlate - translate reset_spec to the reset line number
>    * @rcdev: a pointer to the reset controller device
>    * @reset_spec: reset line specifier as found in the device tree
> @@ -135,6 +148,65 @@ int devm_reset_controller_register(struct device *dev,
>   }
>   EXPORT_SYMBOL_GPL(devm_reset_controller_register);
>   
> +static inline struct reset_control_array *
> +rstc_to_array(struct reset_control *rstc) {
> +	return container_of(rstc, struct reset_control_array, base);
> +}
> +
> +static int reset_control_array_reset(struct reset_control_array *resets)
> +{
> +	int ret, i;
> +
> +	for (i = 0; i < resets->num_rstcs; i++) {
> +		ret = reset_control_reset(resets->rstc[i]);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int reset_control_array_assert(struct reset_control_array *resets)
> +{
> +	int ret, i;
> +
> +	for (i = 0; i < resets->num_rstcs; i++) {
> +		ret = reset_control_assert(resets->rstc[i]);
> +		if (ret)
> +			goto err;
> +	}
> +
> +	return 0;
> +
> +err:
> +	while (i--)
> +		reset_control_deassert(resets->rstc[i]);
> +	return ret;
> +}
> +
> +static int reset_control_array_deassert(struct reset_control_array *resets)
> +{
> +	int ret, i;
> +
> +	for (i = 0; i < resets->num_rstcs; i++) {
> +		ret = reset_control_deassert(resets->rstc[i]);
> +		if (ret)
> +			goto err;
> +	}
> +
> +	return 0;
> +
> +err:
> +	while (i--)
> +		reset_control_assert(resets->rstc[i]);
> +	return ret;
> +}
> +
> +static inline bool reset_control_is_array(struct reset_control *rstc)
> +{
> +	return rstc->array;
> +}
> +
>   /**
>    * reset_control_reset - reset the controlled device
>    * @rstc: reset controller
> @@ -158,6 +230,9 @@ int reset_control_reset(struct reset_control *rstc)
>   	if (WARN_ON(IS_ERR(rstc)))
>   		return -EINVAL;
>   
> +	if (reset_control_is_array(rstc))
> +		return reset_control_array_reset(rstc_to_array(rstc));
> +
>   	if (!rstc->rcdev->ops->reset)
>   		return -ENOTSUPP;
>   
> @@ -202,6 +277,9 @@ int reset_control_assert(struct reset_control *rstc)
>   	if (WARN_ON(IS_ERR(rstc)))
>   		return -EINVAL;
>   
> +	if (reset_control_is_array(rstc))
> +		return reset_control_array_assert(rstc_to_array(rstc));
> +
>   	if (!rstc->rcdev->ops->assert)
>   		return -ENOTSUPP;
>   
> @@ -240,6 +318,9 @@ int reset_control_deassert(struct reset_control *rstc)
>   	if (WARN_ON(IS_ERR(rstc)))
>   		return -EINVAL;
>   
> +	if (reset_control_is_array(rstc))
> +		return reset_control_array_deassert(rstc_to_array(rstc));
> +
>   	if (!rstc->rcdev->ops->deassert)
>   		return -ENOTSUPP;
>   
> @@ -266,7 +347,7 @@ int reset_control_status(struct reset_control *rstc)
>   	if (!rstc)
>   		return 0;
>   
> -	if (WARN_ON(IS_ERR(rstc)))
> +	if (WARN_ON(IS_ERR(rstc)) || reset_control_is_array(rstc))
>   		return -EINVAL;
>   
>   	if (rstc->rcdev->ops->status)
> @@ -404,6 +485,16 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id,
>   }
>   EXPORT_SYMBOL_GPL(__reset_control_get);
>   
> +static void reset_control_array_put(struct reset_control_array *resets)
> +{
> +	int i;
> +
> +	mutex_lock(&reset_list_mutex);
> +	for (i = 0; i < resets->num_rstcs; i++)
> +		__reset_control_put_internal(resets->rstc[i]);
> +	mutex_unlock(&reset_list_mutex);
> +}
> +
>   /**
>    * reset_control_put - free the reset controller
>    * @rstc: reset controller
> @@ -413,6 +504,11 @@ void reset_control_put(struct reset_control *rstc)
>   	if (IS_ERR_OR_NULL(rstc))
>   		return;
>   
> +	if (reset_control_is_array(rstc)) {
> +		reset_control_array_put(rstc_to_array(rstc));
> +		return;
> +	}
> +
>   	mutex_lock(&reset_list_mutex);
>   	__reset_control_put_internal(rstc);
>   	mutex_unlock(&reset_list_mutex);
> @@ -499,81 +595,6 @@ static int of_reset_control_get_count(struct device_node *node)
>   }
>   
>   /**
> - * reset_control_array_assert: assert a list of resets
> - *
> - * @resets: reset control array holding info about the list of resets
> - *
> - * This API doesn't guarantee that the reset lines controlled by
> - * the reset array are asserted in any particular order.
> - *
> - * Returns 0 on success or error number on failure.
> - */
> -int reset_control_array_assert(struct reset_control_array *resets)
> -{
> -	int ret, i;
> -
> -	if (!resets)
> -		return 0;
> -
> -	if (IS_ERR(resets))
> -		return -EINVAL;
> -
> -	for (i = 0; i < resets->num_rstcs; i++) {
> -		ret = reset_control_assert(resets->rstc[i]);
> -		if (ret)
> -			goto err;
> -	}
> -
> -	return 0;
> -
> -err:
> -	while (i--)
> -		reset_control_deassert(resets->rstc[i]);
> -	return ret;
> -}
> -EXPORT_SYMBOL_GPL(reset_control_array_assert);
> -
> -/**
> - * reset_control_array_deassert: deassert a list of resets
> - *
> - * @resets: reset control array holding info about the list of resets
> - *
> - * This API doesn't guarantee that the reset lines controlled by
> - * the reset array are deasserted in any particular order.
> - *
> - * Returns 0 on success or error number on failure.
> - */
> -int reset_control_array_deassert(struct reset_control_array *resets)
> -{
> -	int ret, i;
> -
> -	if (!resets)
> -		return 0;
> -
> -	if (IS_ERR(resets))
> -		return -EINVAL;
> -
> -	for (i = 0; i < resets->num_rstcs; i++) {
> -		ret = reset_control_deassert(resets->rstc[i]);
> -		if (ret)
> -			goto err;
> -	}
> -
> -	return 0;
> -
> -err:
> -	while (i--)
> -		reset_control_assert(resets->rstc[i]);
> -	return ret;
> -}
> -EXPORT_SYMBOL_GPL(reset_control_array_deassert);
> -
> -static void devm_reset_control_array_release(struct device *dev, void *res)
> -{
> -	reset_control_array_put(*(struct reset_control_array **)res);
> -}
> -
> -/**
>    * of_reset_control_array_get - Get a list of reset controls using
>    *				device node.
>    *
> @@ -584,13 +605,12 @@ static void devm_reset_control_array_release(struct device *dev, void *res)
>    * Returns pointer to allocated reset_control_array on success or
>    * error on failure
>    */
> -struct reset_control_array *
> +struct reset_control *
>   of_reset_control_array_get(struct device_node *np, bool shared, bool optional)
>   {
>   	struct reset_control_array *resets;
>   	struct reset_control *rstc;
>   	int num, i;
> -	void *err;
>   
>   	num = of_reset_control_get_count(np);
>   	if (num < 0)
> @@ -603,23 +623,24 @@ of_reset_control_array_get(struct device_node *np, bool shared, bool optional)
>   
>   	for (i = 0; i < num; i++) {
>   		rstc = __of_reset_control_get(np, NULL, i, shared, optional);
> -		if (IS_ERR(rstc)) {
> -			err = ERR_CAST(rstc);
> +		if (IS_ERR(rstc))
>   			goto err_rst;
> -		}
>   		resets->rstc[i] = rstc;
>   	}
>   	resets->num_rstcs = num;
> +	resets->base.array = true;
>   
> -	return resets;
> +	return &resets->base;
>   
>   err_rst:
> +	mutex_lock(&reset_list_mutex);
>   	while (--i >= 0)
> -		reset_control_put(resets->rstc[i]);
> +		__reset_control_put_internal(resets->rstc[i]);
> +	mutex_unlock(&reset_list_mutex);
>   
>   	kfree(resets);
>   
> -	return err;
> +	return rstc;
>   }
>   EXPORT_SYMBOL_GPL(of_reset_control_array_get);
>   
> @@ -637,40 +658,26 @@ EXPORT_SYMBOL_GPL(of_reset_control_array_get);
>    * Returns pointer to allocated reset_control_array on success or
>    * error on failure
>    */
> -struct reset_control_array *
> +struct reset_control *
>   devm_reset_control_array_get(struct device *dev, bool shared, bool optional)
>   {
> -	struct reset_control_array **devres;
> -	struct reset_control_array *resets;
> +	struct reset_control **devres;
> +	struct reset_control *rstc;
>   
> -	devres = devres_alloc(devm_reset_control_array_release,
> -			      sizeof(*devres), GFP_KERNEL);
> +	devres = devres_alloc(devm_reset_control_release, sizeof(*devres),
> +			      GFP_KERNEL);
>   	if (!devres)
>   		return ERR_PTR(-ENOMEM);
>   
> -	resets = of_reset_control_array_get(dev->of_node, shared, optional);
> -	if (IS_ERR(resets)) {
> -		devres_free(resets);
> -		return resets;
> +	rstc = of_reset_control_array_get(dev->of_node, shared, optional);
> +	if (IS_ERR(rstc)) {
> +		devres_free(devres);
> +		return rstc;
>   	}
>   
> -	*devres = resets;
> +	*devres = rstc;
>   	devres_add(dev, devres);
>   
> -	return resets;
> +	return rstc;
>   }
>   EXPORT_SYMBOL_GPL(devm_reset_control_array_get);
> -
> -void reset_control_array_put(struct reset_control_array *resets)
> -{
> -	int i;
> -
> -	if (IS_ERR_OR_NULL(resets))
> -		return;
> -
> -	for (i = 0; i < resets->num_rstcs; i++)
> -		reset_control_put(resets->rstc[i]);
> -
> -	kfree(resets);
> -}
> -EXPORT_SYMBOL_GPL(reset_control_array_put);
> diff --git a/include/linux/reset.h b/include/linux/reset.h
> index df75fe50f765d..0f1be13e66e46 100644
> --- a/include/linux/reset.h
> +++ b/include/linux/reset.h
> @@ -5,11 +5,6 @@
>   
>   struct reset_control;
>   
> -struct reset_control_array {
> -	unsigned int num_rstcs;
> -	struct reset_control *rstc[];
> -};
> -
>   #ifdef CONFIG_RESET_CONTROLLER
>   
>   int reset_control_reset(struct reset_control *rstc);
> @@ -30,13 +25,10 @@ struct reset_control *__devm_reset_control_get(struct device *dev,
>   
>   int __must_check device_reset(struct device *dev);
>   
> -int reset_control_array_assert(struct reset_control_array *resets);
> -int reset_control_array_deassert(struct reset_control_array *resets);
> -struct reset_control_array *devm_reset_control_array_get(struct device *dev,
> -						bool shared, bool optional);
> -struct reset_control_array *of_reset_control_array_get(struct device_node *np,
> -						bool shared, bool optional);
> -void reset_control_array_put(struct reset_control_array *resets);
> +struct reset_control *devm_reset_control_array_get(struct device *dev,
> +						   bool shared, bool optional);
> +struct reset_control *of_reset_control_array_get(struct device_node *np,
> +						 bool shared, bool optional);
>   
>   static inline int device_reset_optional(struct device *dev)
>   {
> @@ -102,18 +94,6 @@ static inline struct reset_control *__devm_reset_control_get(
>   	return optional ? NULL : ERR_PTR(-ENOTSUPP);
>   }
>   
> -static inline
> -int reset_control_array_assert(struct reset_control_array *resets)
> -{
> -	return 0;
> -}
> -
> -static inline
> -int reset_control_array_deassert(struct reset_control_array *resets)
> -{
> -	return 0;
> -}
> -
>   static inline struct reset_control_array *

This has to return just 'struct reset_control *'.
That should resolve kbuild errors.

Rest looks good to me.
Reviewed-by: Vivek Gautam <vivek.gautam@codeaurora.org>

BRs
Vivek

>   devm_reset_control_array_get(struct device *dev, bool shared, bool optional)
>   {
> @@ -420,49 +400,49 @@ static inline struct reset_control *devm_reset_control_get_by_index(
>   /*
>    * APIs to manage a list of reset controllers
>    */
> -static inline struct reset_control_array *
> +static inline struct reset_control *
>   devm_reset_control_array_get_exclusive(struct device *dev)
>   {
>   	return devm_reset_control_array_get(dev, false, false);
>   }
>   
> -static inline struct reset_control_array *
> +static inline struct reset_control *
>   devm_reset_control_array_get_shared(struct device *dev)
>   {
>   	return devm_reset_control_array_get(dev, true, false);
>   }
>   
> -static inline struct reset_control_array *
> +static inline struct reset_control *
>   devm_reset_control_array_get_optional_exclusive(struct device *dev)
>   {
>   	return devm_reset_control_array_get(dev, false, true);
>   }
>   
> -static inline struct reset_control_array *
> +static inline struct reset_control *
>   devm_reset_control_array_get_optional_shared(struct device *dev)
>   {
>   	return devm_reset_control_array_get(dev, true, true);
>   }
>   
> -static inline struct reset_control_array *
> +static inline struct reset_control *
>   of_reset_control_array_get_exclusive(struct device_node *node)
>   {
>   	return of_reset_control_array_get(node, false, false);
>   }
>   
> -static inline struct reset_control_array *
> +static inline struct reset_control *
>   of_reset_control_array_get_shared(struct device_node *node)
>   {
>   	return of_reset_control_array_get(node, true, false);
>   }
>   
> -static inline struct reset_control_array *
> +static inline struct reset_control *
>   of_reset_control_array_get_optional_exclusive(struct device_node *node)
>   {
>   	return of_reset_control_array_get(node, false, true);
>   }
>   
> -static inline struct reset_control_array *
> +static inline struct reset_control *
>   of_reset_control_array_get_optional_shared(struct device_node *node)
>   {
>   	return of_reset_control_array_get(node, true, true);

-- 
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v5 0/6] reset: APIs to manage a list of resets
  2017-06-01 16:51 [PATCH v5 0/6] reset: APIs to manage a list of resets Philipp Zabel
@ 2017-06-13  7:05     ` Vivek Gautam
       [not found] ` <20170601165203.15315-1-p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
  2017-06-01 16:52 ` [PATCH v5 4/6] usb: dwc3: of-simple: Re-order resource handling in remove Philipp Zabel
  2 siblings, 0 replies; 21+ messages in thread
From: Vivek Gautam @ 2017-06-13  7:05 UTC (permalink / raw)
  To: Philipp Zabel, linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Jon Hunter, Felipe Balbi, Greg Kroah-Hartman, Thierry Reding,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA



On 06/01/2017 10:21 PM, Philipp Zabel wrote:
> A set of patches to allow consumers to get and de/assert or trigger
> a number of resets at the same time. A patch on top of Vivek's original
> API extension is added to hide the reset_control_array behind a struct
> reset_control so that the consumer doesn't have care about the difference
> between a singular reset control and reset control controlling an array
> of resets, except when requesting the control.
>
> This series also contains reset controls patches for dwc3-of-simple
> and tegra pmc drivers.
> A small patch is added in this series to correctly re-order the
> resource handling in dwc3_of_simple_remove().
>
> The series is tested on torvald's master branch the device tree
> patches to enable usb on db820c.
>
> Changes since v4:
>   - Added a patch to hide reset control arrays behind struct reset_control
>     and adapted the consumer patches. This could be merged with the reset
>     array API patch if we think this is a good idea.

Hi Philipp,

I tested this series again on my db820c setup. Things work fine.
We can merge this series after fixing the 3/6 patch in this series.

Thanks

Hi Felipe,
If you are okay with changes in dwc3, can you kindly consider Ack'ing this
series. May be Philipp can pull the entire series after fixing.

Thanks
Vivek

>
> Changes since v3:
>   - Squashed of_reset_control_get_count() patch in the second patch that
>     adds the reset control array APIs.
>   - The error path after getting count through of_reset_control_get_count()
>     now returns NULL pointer in case when 'optional' flag is true.
>   - Added code in reset_control_array_assert() to deassert the
>     already asserted resets in the error case.
>   - Using of_reset_control_array_get_optional_exclusive() in dwc3 patch
>     to request the reset control array.
>   - Added a patch to fix the order in which resources are handled in
>     dwc3_of_simple_remove() path.
>   - Added tegra_powergate->reset to take care of single reset control
>     passed from the client drivers.
>
> Changes since v2:
>   - Addressed comments to make APIs inline with gpiod API.
>   - Moved number of reset controls in 'struct reset_control_array'
>     so that the footprint is reduced.
>   - of_reset_control_array_get() and devm_reset_control_array_get()
>     now return pointer to the newly created reset control array.
>   - Added comments to mention that the reset control array APIs don't
>     guarantee any particular order when handling the reset controls.
>   - Dropped 'name' from reset_control_array' since the interface is meant
>     for a bunch of anonymous resets that can all be asserted or deasserted
>     in arbitrary order.
>   - Fixed returns for APIs reported by kbuild.
>   - Fixed 'for' clause guards reported by kbuild.
>
> Changes since v1:
>   - Addressed comment for error handling in of_reset_control_get_count()
>   - Added patch to manage reset controller array.
>   - Rebased dwc3-of-simple changes based on the new set of APIs
>     for reset control array.
>   - Added a patch for soc/tegra/pmc driver to use the new set of
>     reset control array APIs.
>
> Philipp Zabel (2):
>    reset: use kref for reference counting
>    reset: hide reset control arrays behind struct reset_control
>
> Vivek Gautam (4):
>    reset: Add APIs to manage array of resets
>    usb: dwc3: of-simple: Re-order resource handling in remove
>    usb: dwc3: of-simple: Add support to get resets for the device
>    soc/tegra: pmc: Use the new reset APIs to manage reset controllers
>
>   drivers/reset/core.c              | 234 ++++++++++++++++++++++++++++++++++++--
>   drivers/soc/tegra/pmc.c           |  82 ++++---------
>   drivers/usb/dwc3/dwc3-of-simple.c |  29 ++++-
>   include/linux/reset.h             |  73 ++++++++++++
>   4 files changed, 344 insertions(+), 74 deletions(-)
>

-- 
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v5 0/6] reset: APIs to manage a list of resets
@ 2017-06-13  7:05     ` Vivek Gautam
  0 siblings, 0 replies; 21+ messages in thread
From: Vivek Gautam @ 2017-06-13  7:05 UTC (permalink / raw)
  To: Philipp Zabel, linux-kernel
  Cc: Jon Hunter, Felipe Balbi, Greg Kroah-Hartman, Thierry Reding,
	linux-tegra, linux-usb, linux-arm-msm



On 06/01/2017 10:21 PM, Philipp Zabel wrote:
> A set of patches to allow consumers to get and de/assert or trigger
> a number of resets at the same time. A patch on top of Vivek's original
> API extension is added to hide the reset_control_array behind a struct
> reset_control so that the consumer doesn't have care about the difference
> between a singular reset control and reset control controlling an array
> of resets, except when requesting the control.
>
> This series also contains reset controls patches for dwc3-of-simple
> and tegra pmc drivers.
> A small patch is added in this series to correctly re-order the
> resource handling in dwc3_of_simple_remove().
>
> The series is tested on torvald's master branch the device tree
> patches to enable usb on db820c.
>
> Changes since v4:
>   - Added a patch to hide reset control arrays behind struct reset_control
>     and adapted the consumer patches. This could be merged with the reset
>     array API patch if we think this is a good idea.

Hi Philipp,

I tested this series again on my db820c setup. Things work fine.
We can merge this series after fixing the 3/6 patch in this series.

Thanks

Hi Felipe,
If you are okay with changes in dwc3, can you kindly consider Ack'ing this
series. May be Philipp can pull the entire series after fixing.

Thanks
Vivek

>
> Changes since v3:
>   - Squashed of_reset_control_get_count() patch in the second patch that
>     adds the reset control array APIs.
>   - The error path after getting count through of_reset_control_get_count()
>     now returns NULL pointer in case when 'optional' flag is true.
>   - Added code in reset_control_array_assert() to deassert the
>     already asserted resets in the error case.
>   - Using of_reset_control_array_get_optional_exclusive() in dwc3 patch
>     to request the reset control array.
>   - Added a patch to fix the order in which resources are handled in
>     dwc3_of_simple_remove() path.
>   - Added tegra_powergate->reset to take care of single reset control
>     passed from the client drivers.
>
> Changes since v2:
>   - Addressed comments to make APIs inline with gpiod API.
>   - Moved number of reset controls in 'struct reset_control_array'
>     so that the footprint is reduced.
>   - of_reset_control_array_get() and devm_reset_control_array_get()
>     now return pointer to the newly created reset control array.
>   - Added comments to mention that the reset control array APIs don't
>     guarantee any particular order when handling the reset controls.
>   - Dropped 'name' from reset_control_array' since the interface is meant
>     for a bunch of anonymous resets that can all be asserted or deasserted
>     in arbitrary order.
>   - Fixed returns for APIs reported by kbuild.
>   - Fixed 'for' clause guards reported by kbuild.
>
> Changes since v1:
>   - Addressed comment for error handling in of_reset_control_get_count()
>   - Added patch to manage reset controller array.
>   - Rebased dwc3-of-simple changes based on the new set of APIs
>     for reset control array.
>   - Added a patch for soc/tegra/pmc driver to use the new set of
>     reset control array APIs.
>
> Philipp Zabel (2):
>    reset: use kref for reference counting
>    reset: hide reset control arrays behind struct reset_control
>
> Vivek Gautam (4):
>    reset: Add APIs to manage array of resets
>    usb: dwc3: of-simple: Re-order resource handling in remove
>    usb: dwc3: of-simple: Add support to get resets for the device
>    soc/tegra: pmc: Use the new reset APIs to manage reset controllers
>
>   drivers/reset/core.c              | 234 ++++++++++++++++++++++++++++++++++++--
>   drivers/soc/tegra/pmc.c           |  82 ++++---------
>   drivers/usb/dwc3/dwc3-of-simple.c |  29 ++++-
>   include/linux/reset.h             |  73 ++++++++++++
>   4 files changed, 344 insertions(+), 74 deletions(-)
>

-- 
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v5 3/6] reset: hide reset control arrays behind struct reset_control
  2017-06-13  6:46     ` Vivek Gautam
@ 2017-06-19 12:18       ` Philipp Zabel
  2017-06-19 13:06         ` Vivek Gautam
  0 siblings, 1 reply; 21+ messages in thread
From: Philipp Zabel @ 2017-06-19 12:18 UTC (permalink / raw)
  To: Vivek Gautam
  Cc: linux-kernel, Jon Hunter, Felipe Balbi, Greg Kroah-Hartman,
	Thierry Reding, linux-tegra, linux-usb, linux-arm-msm

Hi Vivek,

On Tue, 2017-06-13 at 12:16 +0530, Vivek Gautam wrote:
[...]
> > @@ -102,18 +94,6 @@ static inline struct reset_control *__devm_reset_control_get(
> >   	return optional ? NULL : ERR_PTR(-ENOTSUPP);
> >   }
> >   
> > -static inline
> > -int reset_control_array_assert(struct reset_control_array *resets)
> > -{
> > -	return 0;
> > -}
> > -
> > -static inline
> > -int reset_control_array_deassert(struct reset_control_array *resets)
> > -{
> > -	return 0;
> > -}
> > -
> >   static inline struct reset_control_array *
> 
> This has to return just 'struct reset_control *'.
> That should resolve kbuild errors.
>
> Rest looks good to me.
> Reviewed-by: Vivek Gautam <vivek.gautam@codeaurora.org>

Thanks, I had already fixed this locally, prompted by the kbuild test
robot. I'll send a v6. I would like to merge this patch into the first
"reset: Add APIs to manage array of resets" patch, if that's ok with
you.

regards
Philipp

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v5 6/6] soc/tegra: pmc: Use the new reset APIs to manage reset controllers
  2017-06-01 16:52     ` Philipp Zabel
  (?)
@ 2017-06-19 12:37     ` Philipp Zabel
  -1 siblings, 0 replies; 21+ messages in thread
From: Philipp Zabel @ 2017-06-19 12:37 UTC (permalink / raw)
  To: linux-kernel
  Cc: Vivek Gautam, Jon Hunter, Felipe Balbi, Greg Kroah-Hartman,
	Thierry Reding, linux-tegra, linux-usb, linux-arm-msm

On Thu, 2017-06-01 at 18:52 +0200, Philipp Zabel wrote:
> From: Vivek Gautam <vivek.gautam@codeaurora.org>
> 
> Make use of reset_control_array_*() set of APIs to manage
> an array of reset controllers available with the device.
> 
> Cc: Jon Hunter <jonathanh@nvidia.com>
> Cc: Thierry Reding <treding@nvidia.com>
> Cc: Philipp Zabel <p.zabel@pengutronix.de>
> Signed-off-by: Vivek Gautam <vivek.gautam@codeaurora.org>
> ---
>  drivers/soc/tegra/pmc.c | 82 ++++++++++++-------------------------------------
>  1 file changed, 20 insertions(+), 62 deletions(-)
> 
> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
> index e233dd5dcab3d..749b218147a19 100644
> --- a/drivers/soc/tegra/pmc.c
> +++ b/drivers/soc/tegra/pmc.c
> @@ -124,8 +124,7 @@ struct tegra_powergate {
>  	unsigned int id;
>  	struct clk **clks;
>  	unsigned int num_clks;
> -	struct reset_control **resets;
> -	unsigned int num_resets;
> +	struct reset_control *reset;

Jon, do you think this changed API is a better fit for the tegra/pmc use
case? The reset control array is now handled behind the scenes. Except
for the initial of_reset_control_array_get_exclusive() call, there is no
difference to the user between single reset controls and reset control
arrays anymore.

regards
Philipp

>  };
>  
>  struct tegra_io_pad_soc {
> @@ -348,32 +347,14 @@ static int tegra_powergate_enable_clocks(struct tegra_powergate *pg)
>  	return err;
>  }
>  
> -static int tegra_powergate_reset_assert(struct tegra_powergate *pg)
> +static inline int tegra_powergate_reset_assert(struct tegra_powergate *pg)
>  {
> -	unsigned int i;
> -	int err;
> -
> -	for (i = 0; i < pg->num_resets; i++) {
> -		err = reset_control_assert(pg->resets[i]);
> -		if (err)
> -			return err;
> -	}
> -
> -	return 0;
> +	return reset_control_assert(pg->reset);
>  }
>  
> -static int tegra_powergate_reset_deassert(struct tegra_powergate *pg)
> +static inline int tegra_powergate_reset_deassert(struct tegra_powergate *pg)
>  {
> -	unsigned int i;
> -	int err;
> -
> -	for (i = 0; i < pg->num_resets; i++) {
> -		err = reset_control_deassert(pg->resets[i]);
> -		if (err)
> -			return err;
> -	}
> -
> -	return 0;
> +	return reset_control_deassert(pg->reset);
>  }
>  
>  static int tegra_powergate_power_up(struct tegra_powergate *pg,
> @@ -566,8 +547,7 @@ int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
>  	pg.id = id;
>  	pg.clks = &clk;
>  	pg.num_clks = 1;
> -	pg.resets = &rst;
> -	pg.num_resets = 1;
> +	pg.reset = IS_ERR(rst) ? NULL : rst;
>  
>  	err = tegra_powergate_power_up(&pg, false);
>  	if (err)
> @@ -755,45 +735,26 @@ static int tegra_powergate_of_get_clks(struct tegra_powergate *pg,
>  static int tegra_powergate_of_get_resets(struct tegra_powergate *pg,
>  					 struct device_node *np, bool off)
>  {
> -	struct reset_control *rst;
> -	unsigned int i, count;
>  	int err;
>  
> -	count = of_count_phandle_with_args(np, "resets", "#reset-cells");
> -	if (count == 0)
> -		return -ENODEV;
> -
> -	pg->resets = kcalloc(count, sizeof(rst), GFP_KERNEL);
> -	if (!pg->resets)
> -		return -ENOMEM;
> -
> -	for (i = 0; i < count; i++) {
> -		pg->resets[i] = of_reset_control_get_by_index(np, i);
> -		if (IS_ERR(pg->resets[i])) {
> -			err = PTR_ERR(pg->resets[i]);
> -			goto error;
> -		}
> -
> -		if (off)
> -			err = reset_control_assert(pg->resets[i]);
> -		else
> -			err = reset_control_deassert(pg->resets[i]);
> -
> -		if (err) {
> -			reset_control_put(pg->resets[i]);
> -			goto error;
> -		}
> +	pg->reset = of_reset_control_array_get_exclusive(np);
> +	if (IS_ERR(pg->reset)) {
> +		pr_err("failed to get device resets\n");
> +		return PTR_ERR(pg->reset);
>  	}
>  
> -	pg->num_resets = count;
> +	if (off)
> +		err = reset_control_assert(pg->reset);
> +	else
> +		err = reset_control_deassert(pg->reset);
>  
> -	return 0;
> +	if (err)
> +		goto put_reset;
>  
> -error:
> -	while (i--)
> -		reset_control_put(pg->resets[i]);
> +	return 0;
>  
> -	kfree(pg->resets);
> +put_reset:
> +	reset_control_put(pg->reset);
>  
>  	return err;
>  }
> @@ -885,10 +846,7 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
>  	pm_genpd_remove(&pg->genpd);
>  
>  remove_resets:
> -	while (pg->num_resets--)
> -		reset_control_put(pg->resets[pg->num_resets]);
> -
> -	kfree(pg->resets);
> +	reset_control_put(pg->reset);
>  
>  remove_clks:
>  	while (pg->num_clks--)

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v5 3/6] reset: hide reset control arrays behind struct reset_control
  2017-06-19 12:18       ` Philipp Zabel
@ 2017-06-19 13:06         ` Vivek Gautam
  0 siblings, 0 replies; 21+ messages in thread
From: Vivek Gautam @ 2017-06-19 13:06 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: linux-kernel, Jon Hunter, Felipe Balbi, Greg Kroah-Hartman,
	Thierry Reding, linux-tegra, linux-usb, linux-arm-msm

Hi Philipp,


On 06/19/2017 05:48 PM, Philipp Zabel wrote:
> Hi Vivek,
>
> On Tue, 2017-06-13 at 12:16 +0530, Vivek Gautam wrote:
> [...]
>>> @@ -102,18 +94,6 @@ static inline struct reset_control *__devm_reset_control_get(
>>>    	return optional ? NULL : ERR_PTR(-ENOTSUPP);
>>>    }
>>>    
>>> -static inline
>>> -int reset_control_array_assert(struct reset_control_array *resets)
>>> -{
>>> -	return 0;
>>> -}
>>> -
>>> -static inline
>>> -int reset_control_array_deassert(struct reset_control_array *resets)
>>> -{
>>> -	return 0;
>>> -}
>>> -
>>>    static inline struct reset_control_array *
>> This has to return just 'struct reset_control *'.
>> That should resolve kbuild errors.
>>
>> Rest looks good to me.
>> Reviewed-by: Vivek Gautam <vivek.gautam@codeaurora.org>
> Thanks, I had already fixed this locally, prompted by the kbuild test
> robot. I'll send a v6. I would like to merge this patch into the first
> "reset: Add APIs to manage array of resets" patch, if that's ok with
> you.

Thanks.
You are right. It makes more sense to merge these two patches
if Jon finds it okay to put reset_control_array behind reset_control.

I am cool with squashing this patch.


Best regards
Vivek

>
> regards
> Philipp
>

-- 
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2017-06-19 13:06 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-01 16:51 [PATCH v5 0/6] reset: APIs to manage a list of resets Philipp Zabel
2017-06-01 16:51 ` [PATCH v5 2/6] reset: Add APIs to manage array " Philipp Zabel
     [not found] ` <20170601165203.15315-1-p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2017-06-01 16:51   ` [PATCH v5 1/6] reset: use kref for reference counting Philipp Zabel
2017-06-01 16:51     ` Philipp Zabel
2017-06-01 16:52   ` [PATCH v5 3/6] reset: hide reset control arrays behind struct reset_control Philipp Zabel
2017-06-01 16:52     ` Philipp Zabel
     [not found]     ` <20170601165203.15315-4-p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2017-06-01 23:09       ` kbuild test robot
2017-06-01 23:09         ` kbuild test robot
2017-06-02  0:12       ` kbuild test robot
2017-06-02  0:12         ` kbuild test robot
2017-06-13  6:46     ` Vivek Gautam
2017-06-19 12:18       ` Philipp Zabel
2017-06-19 13:06         ` Vivek Gautam
2017-06-01 16:52   ` [PATCH v5 5/6] usb: dwc3: of-simple: Add support to get resets for the device Philipp Zabel
2017-06-01 16:52     ` Philipp Zabel
2017-06-01 16:52   ` [PATCH v5 6/6] soc/tegra: pmc: Use the new reset APIs to manage reset controllers Philipp Zabel
2017-06-01 16:52     ` Philipp Zabel
2017-06-19 12:37     ` Philipp Zabel
2017-06-13  7:05   ` [PATCH v5 0/6] reset: APIs to manage a list of resets Vivek Gautam
2017-06-13  7:05     ` Vivek Gautam
2017-06-01 16:52 ` [PATCH v5 4/6] usb: dwc3: of-simple: Re-order resource handling in remove Philipp Zabel

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.