diff mbox

[V3,4/4] soc/tegra: pmc: Use the new reset APIs to manage reset controllers

Message ID 1492514488-27385-5-git-send-email-vivek.gautam@codeaurora.org
State Superseded
Headers show

Commit Message

Vivek Gautam April 18, 2017, 11:21 a.m. UTC
Make use of reset_control_array_*() set of APIs to manage
an array of reset controllers available with the device.

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 | 99 ++++++++++++++++++-------------------------------
 1 file changed, 36 insertions(+), 63 deletions(-)

Comments

Philipp Zabel April 19, 2017, 10:40 a.m. UTC | #1
On Tue, 2017-04-18 at 16:51 +0530, Vivek Gautam wrote:
> Make use of reset_control_array_*() set of APIs to manage
> an array of reset controllers available with the device.
> 
> 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 | 99 ++++++++++++++++++-------------------------------
>  1 file changed, 36 insertions(+), 63 deletions(-)
> 
> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
> index e233dd5dcab3..4d039fa3db1b 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_array *resets;
>  };
>  
>  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_array_assert(pg->resets);
>  }
>  
> -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_array_deassert(pg->resets);
>  }
>  
>  static int tegra_powergate_power_up(struct tegra_powergate *pg,
> @@ -558,6 +539,7 @@ int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
>  				      struct reset_control *rst)
>  {
>  	struct tegra_powergate pg;
> +	struct reset_control_array *resets;
>  	int err;
>  
>  	if (!tegra_powergate_is_available(id))
> @@ -566,12 +548,25 @@ 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;

Oh, I didn't notice that the resets array is often used for a single
reset. I think in this case instead of wrapping a reset_control_array
around the passed reset, you could store it as an additional pointer in
tegra_powergate->reset and add
	if (pg->reset)
		return reset_control_(de)assert(pg->resets);
to the tegra_powergate_reset_(de)assert functions ...

> +
> +	resets = kzalloc(sizeof(*resets) + sizeof(resets->rstc[0]) * 1,
> +			 GFP_KERNEL);
> +	if (!resets)
> +		return -ENOMEM;
> +
> +	resets->rstc[0] = rst;
> +	pg.resets = resets;
>  
>  	err = tegra_powergate_power_up(&pg, false);
> -	if (err)
> +	if (err) {
>  		pr_err("failed to turn on partition %d: %d\n", id, err);
> +		goto free_reset;
> +	}
> +
> +	return 0;
> +
> +free_reset:
> +	kfree(resets);
>  

... as having to open code this handling of struct reset_control_array
internals completely negates its convenience.

>  	return err;
>  }
> @@ -755,45 +750,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->resets = of_reset_control_array_get_exclusive(np);
> +	if (IS_ERR(pg->resets)) {
> +		pr_err("failed to get device resets\n");
> +		return PTR_ERR(pg->resets);
>  	}
>  
> -	pg->num_resets = count;
> +	if (off)
> +		err = reset_control_array_assert(pg->resets);
> +	else
> +		err = reset_control_array_deassert(pg->resets);
>  
> -	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_array_put(pg->resets);
>  
>  	return err;
>  }
> @@ -885,10 +861,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_array_put(pg->resets);
>  
>  remove_clks:
>  	while (pg->num_clks--)

regards
Philipp

--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jon Hunter April 24, 2017, 12:45 p.m. UTC | #2
On 18/04/17 12:21, Vivek Gautam wrote:
> Make use of reset_control_array_*() set of APIs to manage
> an array of reset controllers available with the device.

Before we apply this patch, I need to check to see if the order of the
resets managed by the PMC driver matter. Today the order of the resets
is determined by the order they appear in the DT node and although the
new APIs work in the same way they do not guarantee this. So let me
check to see if we can any concerns about ordering here. Otherwise would
be nice to use these APIs.

Cheers
Jon
Vivek Gautam April 25, 2017, 4:15 a.m. UTC | #3
On 04/24/2017 06:15 PM, Jon Hunter wrote:
> On 18/04/17 12:21, Vivek Gautam wrote:
>> Make use of reset_control_array_*() set of APIs to manage
>> an array of reset controllers available with the device.
> Before we apply this patch, I need to check to see if the order of the
> resets managed by the PMC driver matter. Today the order of the resets
> is determined by the order they appear in the DT node and although the
> new APIs work in the same way they do not guarantee this. So let me
> check to see if we can any concerns about ordering here. Otherwise would
> be nice to use these APIs.

Right, that will be perfect.

Best regards
Vivek

>
> Cheers
> Jon
>
Jon Hunter April 25, 2017, 10:05 a.m. UTC | #4
On 25/04/17 05:15, Vivek Gautam wrote:
> On 04/24/2017 06:15 PM, Jon Hunter wrote:
>> On 18/04/17 12:21, Vivek Gautam wrote:
>>> Make use of reset_control_array_*() set of APIs to manage
>>> an array of reset controllers available with the device.
>> Before we apply this patch, I need to check to see if the order of the
>> resets managed by the PMC driver matter. Today the order of the resets
>> is determined by the order they appear in the DT node and although the
>> new APIs work in the same way they do not guarantee this. So let me
>> check to see if we can any concerns about ordering here. Otherwise would
>> be nice to use these APIs.
> 
> Right, that will be perfect.

So I don't see any restrictions here and so I think this change is fine.

BTW, for the DT case, is there any reason why we don't just say the
order will be determine by the order the resets are list in the DT node?

Cheers
Jon
Philipp Zabel April 25, 2017, 10:33 a.m. UTC | #5
On Tue, 2017-04-25 at 11:05 +0100, Jon Hunter wrote:
> On 25/04/17 05:15, Vivek Gautam wrote:
> > On 04/24/2017 06:15 PM, Jon Hunter wrote:
> >> On 18/04/17 12:21, Vivek Gautam wrote:
> >>> Make use of reset_control_array_*() set of APIs to manage
> >>> an array of reset controllers available with the device.
> >> Before we apply this patch, I need to check to see if the order of the
> >> resets managed by the PMC driver matter. Today the order of the resets
> >> is determined by the order they appear in the DT node and although the
> >> new APIs work in the same way they do not guarantee this. So let me
> >> check to see if we can any concerns about ordering here. Otherwise would
> >> be nice to use these APIs.
> > 
> > Right, that will be perfect.
> 
> So I don't see any restrictions here and so I think this change is fine.

Thank you for checking.

> BTW, for the DT case, is there any reason why we don't just say the
> order will be determine by the order the resets are list in the DT node?

I'd rather not make any promises, so I don't have to care about keeping
them. This makes it easier to think about and allows for more freedom in
changing the core code if needed.

What if in the future there is a use case for enabling a bunch of resets
by flipping a number of bits in a single register at the same time? Or
if people accidentally depend on the ordering when in reality there is a
small delay necessary between assertions that just happens to be hidden
by the framework overhead?

If there is a use case for an array of reset controls that must be
(de)asserted in a fixed order and doesn't need any delay between the
steps and is not suitable to be described by named resets for some
reason, we can discuss this. Until then, I'm happy that tegra pmc can
handle arrays without any particular ordering.

regards
Philipp


--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jon Hunter April 25, 2017, 10:54 a.m. UTC | #6
On 25/04/17 11:33, Philipp Zabel wrote:
> On Tue, 2017-04-25 at 11:05 +0100, Jon Hunter wrote:
>> On 25/04/17 05:15, Vivek Gautam wrote:
>>> On 04/24/2017 06:15 PM, Jon Hunter wrote:
>>>> On 18/04/17 12:21, Vivek Gautam wrote:
>>>>> Make use of reset_control_array_*() set of APIs to manage
>>>>> an array of reset controllers available with the device.
>>>> Before we apply this patch, I need to check to see if the order of the
>>>> resets managed by the PMC driver matter. Today the order of the resets
>>>> is determined by the order they appear in the DT node and although the
>>>> new APIs work in the same way they do not guarantee this. So let me
>>>> check to see if we can any concerns about ordering here. Otherwise would
>>>> be nice to use these APIs.
>>>
>>> Right, that will be perfect.
>>
>> So I don't see any restrictions here and so I think this change is fine.
> 
> Thank you for checking.
> 
>> BTW, for the DT case, is there any reason why we don't just say the
>> order will be determine by the order the resets are list in the DT node?
> 
> I'd rather not make any promises, so I don't have to care about keeping
> them. This makes it easier to think about and allows for more freedom in
> changing the core code if needed.
> 
> What if in the future there is a use case for enabling a bunch of resets
> by flipping a number of bits in a single register at the same time? Or
> if people accidentally depend on the ordering when in reality there is a
> small delay necessary between assertions that just happens to be hidden
> by the framework overhead?
> 
> If there is a use case for an array of reset controls that must be
> (de)asserted in a fixed order and doesn't need any delay between the
> steps and is not suitable to be described by named resets for some
> reason, we can discuss this. Until then, I'm happy that tegra pmc can
> handle arrays without any particular ordering.

OK, makes sense.

Thanks
Jon
Vivek Gautam April 25, 2017, 11:06 a.m. UTC | #7
On 04/25/2017 04:24 PM, Jon Hunter wrote:
> On 25/04/17 11:33, Philipp Zabel wrote:
>> On Tue, 2017-04-25 at 11:05 +0100, Jon Hunter wrote:
>>> On 25/04/17 05:15, Vivek Gautam wrote:
>>>> On 04/24/2017 06:15 PM, Jon Hunter wrote:
>>>>> On 18/04/17 12:21, Vivek Gautam wrote:
>>>>>> Make use of reset_control_array_*() set of APIs to manage
>>>>>> an array of reset controllers available with the device.
>>>>> Before we apply this patch, I need to check to see if the order of the
>>>>> resets managed by the PMC driver matter. Today the order of the resets
>>>>> is determined by the order they appear in the DT node and although the
>>>>> new APIs work in the same way they do not guarantee this. So let me
>>>>> check to see if we can any concerns about ordering here. Otherwise would
>>>>> be nice to use these APIs.
>>>> Right, that will be perfect.
>>> So I don't see any restrictions here and so I think this change is fine.
>> Thank you for checking.
>>
>>> BTW, for the DT case, is there any reason why we don't just say the
>>> order will be determine by the order the resets are list in the DT node?
>> I'd rather not make any promises, so I don't have to care about keeping
>> them. This makes it easier to think about and allows for more freedom in
>> changing the core code if needed.
>>
>> What if in the future there is a use case for enabling a bunch of resets
>> by flipping a number of bits in a single register at the same time? Or
>> if people accidentally depend on the ordering when in reality there is a
>> small delay necessary between assertions that just happens to be hidden
>> by the framework overhead?
>>
>> If there is a use case for an array of reset controls that must be
>> (de)asserted in a fixed order and doesn't need any delay between the
>> steps and is not suitable to be described by named resets for some
>> reason, we can discuss this. Until then, I'm happy that tegra pmc can
>> handle arrays without any particular ordering.
> OK, makes sense.

Thanks Jon for testing this.

Best Regards
Vivek
>
> Thanks
> Jon
>
Jon Hunter April 25, 2017, 11:11 a.m. UTC | #8
On 25/04/17 12:06, Vivek Gautam wrote:
> On 04/25/2017 04:24 PM, Jon Hunter wrote:
>> On 25/04/17 11:33, Philipp Zabel wrote:
>>> On Tue, 2017-04-25 at 11:05 +0100, Jon Hunter wrote:
>>>> On 25/04/17 05:15, Vivek Gautam wrote:
>>>>> On 04/24/2017 06:15 PM, Jon Hunter wrote:
>>>>>> On 18/04/17 12:21, Vivek Gautam wrote:
>>>>>>> Make use of reset_control_array_*() set of APIs to manage
>>>>>>> an array of reset controllers available with the device.
>>>>>> Before we apply this patch, I need to check to see if the order of
>>>>>> the
>>>>>> resets managed by the PMC driver matter. Today the order of the
>>>>>> resets
>>>>>> is determined by the order they appear in the DT node and although
>>>>>> the
>>>>>> new APIs work in the same way they do not guarantee this. So let me
>>>>>> check to see if we can any concerns about ordering here. Otherwise
>>>>>> would
>>>>>> be nice to use these APIs.
>>>>> Right, that will be perfect.
>>>> So I don't see any restrictions here and so I think this change is
>>>> fine.
>>> Thank you for checking.
>>>
>>>> BTW, for the DT case, is there any reason why we don't just say the
>>>> order will be determine by the order the resets are list in the DT
>>>> node?
>>> I'd rather not make any promises, so I don't have to care about keeping
>>> them. This makes it easier to think about and allows for more freedom in
>>> changing the core code if needed.
>>>
>>> What if in the future there is a use case for enabling a bunch of resets
>>> by flipping a number of bits in a single register at the same time? Or
>>> if people accidentally depend on the ordering when in reality there is a
>>> small delay necessary between assertions that just happens to be hidden
>>> by the framework overhead?
>>>
>>> If there is a use case for an array of reset controls that must be
>>> (de)asserted in a fixed order and doesn't need any delay between the
>>> steps and is not suitable to be described by named resets for some
>>> reason, we can discuss this. Until then, I'm happy that tegra pmc can
>>> handle arrays without any particular ordering.
>> OK, makes sense.
> 
> Thanks Jon for testing this.

Not tested yet :-)

However, I will test this just to confirm. Are you planning on sending
out a v4 soon?

Jon
Vivek Gautam April 25, 2017, 5:50 p.m. UTC | #9
On Tue, Apr 25, 2017 at 4:41 PM, Jon Hunter <jonathanh@nvidia.com> wrote:
>
> On 25/04/17 12:06, Vivek Gautam wrote:
>> On 04/25/2017 04:24 PM, Jon Hunter wrote:
>>> On 25/04/17 11:33, Philipp Zabel wrote:
>>>> On Tue, 2017-04-25 at 11:05 +0100, Jon Hunter wrote:
>>>>> On 25/04/17 05:15, Vivek Gautam wrote:
>>>>>> On 04/24/2017 06:15 PM, Jon Hunter wrote:
>>>>>>> On 18/04/17 12:21, Vivek Gautam wrote:
>>>>>>>> Make use of reset_control_array_*() set of APIs to manage
>>>>>>>> an array of reset controllers available with the device.
>>>>>>> Before we apply this patch, I need to check to see if the order of
>>>>>>> the
>>>>>>> resets managed by the PMC driver matter. Today the order of the
>>>>>>> resets
>>>>>>> is determined by the order they appear in the DT node and although
>>>>>>> the
>>>>>>> new APIs work in the same way they do not guarantee this. So let me
>>>>>>> check to see if we can any concerns about ordering here. Otherwise
>>>>>>> would
>>>>>>> be nice to use these APIs.
>>>>>> Right, that will be perfect.
>>>>> So I don't see any restrictions here and so I think this change is
>>>>> fine.
>>>> Thank you for checking.
>>>>
>>>>> BTW, for the DT case, is there any reason why we don't just say the
>>>>> order will be determine by the order the resets are list in the DT
>>>>> node?
>>>> I'd rather not make any promises, so I don't have to care about keeping
>>>> them. This makes it easier to think about and allows for more freedom in
>>>> changing the core code if needed.
>>>>
>>>> What if in the future there is a use case for enabling a bunch of resets
>>>> by flipping a number of bits in a single register at the same time? Or
>>>> if people accidentally depend on the ordering when in reality there is a
>>>> small delay necessary between assertions that just happens to be hidden
>>>> by the framework overhead?
>>>>
>>>> If there is a use case for an array of reset controls that must be
>>>> (de)asserted in a fixed order and doesn't need any delay between the
>>>> steps and is not suitable to be described by named resets for some
>>>> reason, we can discuss this. Until then, I'm happy that tegra pmc can
>>>> handle arrays without any particular ordering.
>>> OK, makes sense.
>>
>> Thanks Jon for testing this.
>
> Not tested yet :-)
>
> However, I will test this just to confirm. Are you planning on sending
> out a v4 soon?

Yes, I will send a v4 soon this week.

Thanks
Vivek
diff mbox

Patch

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index e233dd5dcab3..4d039fa3db1b 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_array *resets;
 };
 
 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_array_assert(pg->resets);
 }
 
-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_array_deassert(pg->resets);
 }
 
 static int tegra_powergate_power_up(struct tegra_powergate *pg,
@@ -558,6 +539,7 @@  int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
 				      struct reset_control *rst)
 {
 	struct tegra_powergate pg;
+	struct reset_control_array *resets;
 	int err;
 
 	if (!tegra_powergate_is_available(id))
@@ -566,12 +548,25 @@  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;
+
+	resets = kzalloc(sizeof(*resets) + sizeof(resets->rstc[0]) * 1,
+			 GFP_KERNEL);
+	if (!resets)
+		return -ENOMEM;
+
+	resets->rstc[0] = rst;
+	pg.resets = resets;
 
 	err = tegra_powergate_power_up(&pg, false);
-	if (err)
+	if (err) {
 		pr_err("failed to turn on partition %d: %d\n", id, err);
+		goto free_reset;
+	}
+
+	return 0;
+
+free_reset:
+	kfree(resets);
 
 	return err;
 }
@@ -755,45 +750,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->resets = of_reset_control_array_get_exclusive(np);
+	if (IS_ERR(pg->resets)) {
+		pr_err("failed to get device resets\n");
+		return PTR_ERR(pg->resets);
 	}
 
-	pg->num_resets = count;
+	if (off)
+		err = reset_control_array_assert(pg->resets);
+	else
+		err = reset_control_array_deassert(pg->resets);
 
-	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_array_put(pg->resets);
 
 	return err;
 }
@@ -885,10 +861,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_array_put(pg->resets);
 
 remove_clks:
 	while (pg->num_clks--)