diff mbox series

[v4,1/2] clk: Provide managed helper to get and enable bulk clocks

Message ID 20240124103838.32478-2-shradha.t@samsung.com
State New
Headers show
Series Add helper function to get and enable all bulk clocks | expand

Commit Message

Shradha Todi Jan. 24, 2024, 10:38 a.m. UTC
Provide a managed devm_clk_bulk* wrapper to get and enable all
bulk clocks in order to simplify drivers that keeps all clocks
enabled for the time of driver operation.

Suggested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Shradha Todi <shradha.t@samsung.com>
---
 drivers/clk/clk-devres.c | 40 ++++++++++++++++++++++++++++++++++++++++
 include/linux/clk.h      | 24 ++++++++++++++++++++++++
 2 files changed, 64 insertions(+)

Comments

Manivannan Sadhasivam Jan. 29, 2024, 6:54 a.m. UTC | #1
On Wed, Jan 24, 2024 at 04:08:37PM +0530, Shradha Todi wrote:
> Provide a managed devm_clk_bulk* wrapper to get and enable all
> bulk clocks in order to simplify drivers that keeps all clocks
> enabled for the time of driver operation.
> 
> Suggested-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Signed-off-by: Shradha Todi <shradha.t@samsung.com>
> ---
>  drivers/clk/clk-devres.c | 40 ++++++++++++++++++++++++++++++++++++++++
>  include/linux/clk.h      | 24 ++++++++++++++++++++++++
>  2 files changed, 64 insertions(+)
> 
> diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c
> index 4fb4fd4b06bd..cbbd2cc339c3 100644
> --- a/drivers/clk/clk-devres.c
> +++ b/drivers/clk/clk-devres.c
> @@ -182,6 +182,46 @@ int __must_check devm_clk_bulk_get_all(struct device *dev,
>  }
>  EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all);
>  
> +static void devm_clk_bulk_release_all_enable(struct device *dev, void *res)
> +{
> +	struct clk_bulk_devres *devres = res;
> +
> +	clk_bulk_disable_unprepare(devres->num_clks, devres->clks);
> +	clk_bulk_put_all(devres->num_clks, devres->clks);
> +}
> +
> +int __must_check devm_clk_bulk_get_all_enable(struct device *dev,
> +					      struct clk_bulk_data **clks)
> +{
> +	struct clk_bulk_devres *devres;
> +	int ret;
> +
> +	devres = devres_alloc(devm_clk_bulk_release_all_enable,
> +			      sizeof(*devres), GFP_KERNEL);
> +	if (!devres)
> +		return -ENOMEM;
> +
> +	ret = clk_bulk_get_all(dev, &devres->clks);
> +	if (ret > 0) {
> +		*clks = devres->clks;
> +		devres->num_clks = ret;
> +	} else {
> +		devres_free(devres);
> +		return ret;
> +	}

How about:

	ret = clk_bulk_get_all(dev, &devres->clks);
	if (ret <= 0) {
		devres_free(devres);
		return ret;
	}

	*clks = devres->clks;
	devres->num_clks = ret;

Even though this patch follows the pattern used by the rest of the APIs in the
driver, IMO above makes it more readable.

> +
> +	ret = clk_bulk_prepare_enable(devres->num_clks, *clks);
> +	if (!ret) {
> +		devres_add(dev, devres);
> +	} else {
> +		clk_bulk_put_all(devres->num_clks, devres->clks);
> +		devres_free(devres);
> +	}
> +

Same as above:

	ret = clk_bulk_prepare_enable(devres->num_clks, *clks);
	if (ret) {
		clk_bulk_put_all(devres->num_clks, devres->clks);
		devres_free(devres);
		return ret;
	}

	devres_add(dev, devres);

> +	return ret;

	return 0;

> +}
> +EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all_enable);
> +
>  static int devm_clk_match(struct device *dev, void *res, void *data)
>  {
>  	struct clk **c = res;
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 1ef013324237..a005e709b7bd 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -438,6 +438,23 @@ int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks,
>  int __must_check devm_clk_bulk_get_all(struct device *dev,
>  				       struct clk_bulk_data **clks);
>  
> +/**
> + * devm_clk_bulk_get_all_enable - managed get multiple clk consumers and
> + *				  enable all clks

"Get and enable all clocks of the consumer (managed)"

> + * @dev: device for clock "consumer"
> + * @clks: pointer to the clk_bulk_data table of consumer
> + *
> + * Returns success (0) or negative errno.
> + *
> + * This helper function allows drivers to get several clk

"This helper function allows drivers to get all clocks of the consumer and
enables them..."

- Mani

> + * consumers and enable all of them in one operation with management.
> + * The clks will automatically be disabled and freed when the device
> + * is unbound.
> + */
> +
> +int __must_check devm_clk_bulk_get_all_enable(struct device *dev,
> +					      struct clk_bulk_data **clks);
> +
>  /**
>   * devm_clk_get - lookup and obtain a managed reference to a clock producer.
>   * @dev: device for clock "consumer"
> @@ -960,6 +977,13 @@ static inline int __must_check devm_clk_bulk_get_all(struct device *dev,
>  	return 0;
>  }
>  
> +static inline int __must_check devm_clk_bulk_get_all_enable(struct device *dev,
> +						struct clk_bulk_data **clks)
> +{
> +
> +	return 0;
> +}
> +
>  static inline struct clk *devm_get_clk_from_child(struct device *dev,
>  				struct device_node *np, const char *con_id)
>  {
> -- 
> 2.17.1
>
Alim Akhtar Jan. 31, 2024, 5:04 a.m. UTC | #2
Hi Shradha

> -----Original Message-----
> From: Shradha Todi <shradha.t@samsung.com>
> Sent: Wednesday, January 24, 2024 4:09 PM
> To: linux-clk@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
> pci@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-samsung-
> soc@vger.kernel.org
> Cc: mturquette@baylibre.com; sboyd@kernel.org; jingoohan1@gmail.com;
> lpieralisi@kernel.org; kw@linux.com; robh@kernel.org;
> bhelgaas@google.com; krzysztof.kozlowski@linaro.org;
> alim.akhtar@samsung.com; linux@armlinux.org.uk;
> m.szyprowski@samsung.com; manivannan.sadhasivam@linaro.org;
> pankaj.dubey@samsung.com; Shradha Todi <shradha.t@samsung.com>
> Subject: [PATCH v4 1/2] clk: Provide managed helper to get and enable bulk
> clocks
> 
> Provide a managed devm_clk_bulk* wrapper to get and enable all bulk clocks
> in order to simplify drivers that keeps all clocks enabled for the time of driver
> operation.
> 
> Suggested-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Signed-off-by: Shradha Todi <shradha.t@samsung.com>
> ---

Reviewed-by: Alim Akhtar <alim.akhtar@samsung.com>

>  drivers/clk/clk-devres.c | 40
> ++++++++++++++++++++++++++++++++++++++++
>  include/linux/clk.h      | 24 ++++++++++++++++++++++++
>  2 files changed, 64 insertions(+)
> 
> diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c index
> 4fb4fd4b06bd..cbbd2cc339c3 100644
> --- a/drivers/clk/clk-devres.c
> +++ b/drivers/clk/clk-devres.c
> @@ -182,6 +182,46 @@ int __must_check devm_clk_bulk_get_all(struct
> device *dev,  }  EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all);
> 
> +static void devm_clk_bulk_release_all_enable(struct device *dev, void
> +*res) {
> +	struct clk_bulk_devres *devres = res;
> +
> +	clk_bulk_disable_unprepare(devres->num_clks, devres->clks);
> +	clk_bulk_put_all(devres->num_clks, devres->clks); }
> +
> +int __must_check devm_clk_bulk_get_all_enable(struct device *dev,
> +					      struct clk_bulk_data **clks) {
> +	struct clk_bulk_devres *devres;
> +	int ret;
> +
> +	devres = devres_alloc(devm_clk_bulk_release_all_enable,
> +			      sizeof(*devres), GFP_KERNEL);
> +	if (!devres)
> +		return -ENOMEM;
> +
> +	ret = clk_bulk_get_all(dev, &devres->clks);
> +	if (ret > 0) {
> +		*clks = devres->clks;
> +		devres->num_clks = ret;
> +	} else {
> +		devres_free(devres);
> +		return ret;
> +	}
> +
> +	ret = clk_bulk_prepare_enable(devres->num_clks, *clks);
> +	if (!ret) {
> +		devres_add(dev, devres);
> +	} else {
> +		clk_bulk_put_all(devres->num_clks, devres->clks);
> +		devres_free(devres);
> +	}
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all_enable);
> +
>  static int devm_clk_match(struct device *dev, void *res, void *data)  {
>  	struct clk **c = res;
> diff --git a/include/linux/clk.h b/include/linux/clk.h index
> 1ef013324237..a005e709b7bd 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -438,6 +438,23 @@ int __must_check
> devm_clk_bulk_get_optional(struct device *dev, int num_clks,  int
> __must_check devm_clk_bulk_get_all(struct device *dev,
>  				       struct clk_bulk_data **clks);
> 
> +/**
> + * devm_clk_bulk_get_all_enable - managed get multiple clk consumers
> and
> + *				  enable all clks
> + * @dev: device for clock "consumer"
> + * @clks: pointer to the clk_bulk_data table of consumer
> + *
> + * Returns success (0) or negative errno.
> + *
> + * This helper function allows drivers to get several clk
> + * consumers and enable all of them in one operation with management.
> + * The clks will automatically be disabled and freed when the device
> + * is unbound.
> + */
> +
> +int __must_check devm_clk_bulk_get_all_enable(struct device *dev,
> +					      struct clk_bulk_data **clks);
> +
>  /**
>   * devm_clk_get - lookup and obtain a managed reference to a clock
> producer.
>   * @dev: device for clock "consumer"
> @@ -960,6 +977,13 @@ static inline int __must_check
> devm_clk_bulk_get_all(struct device *dev,
>  	return 0;
>  }
> 
> +static inline int __must_check devm_clk_bulk_get_all_enable(struct device
> *dev,
> +						struct clk_bulk_data **clks)
> +{
> +
> +	return 0;
> +}
> +
>  static inline struct clk *devm_get_clk_from_child(struct device *dev,
>  				struct device_node *np, const char *con_id)
> {
> --
> 2.17.1
Shradha Todi Feb. 2, 2024, 11:59 a.m. UTC | #3
> -----Original Message-----
> From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> Sent: 29 January 2024 12:25
> To: Shradha Todi <shradha.t@samsung.com>
> Cc: linux-clk@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
> pci@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-samsung-
> soc@vger.kernel.org; mturquette@baylibre.com; sboyd@kernel.org;
> jingoohan1@gmail.com; lpieralisi@kernel.org; kw@linux.com; robh@kernel.org;
> bhelgaas@google.com; krzysztof.kozlowski@linaro.org;
> alim.akhtar@samsung.com; linux@armlinux.org.uk;
> m.szyprowski@samsung.com; pankaj.dubey@samsung.com
> Subject: Re: [PATCH v4 1/2] clk: Provide managed helper to get and enable bulk
> clocks
> 
> On Wed, Jan 24, 2024 at 04:08:37PM +0530, Shradha Todi wrote:
> > Provide a managed devm_clk_bulk* wrapper to get and enable all bulk
> > clocks in order to simplify drivers that keeps all clocks enabled for
> > the time of driver operation.
> >
> > Suggested-by: Marek Szyprowski <m.szyprowski@samsung.com>
> > Signed-off-by: Shradha Todi <shradha.t@samsung.com>
> > ---
> >  drivers/clk/clk-devres.c | 40
> ++++++++++++++++++++++++++++++++++++++++
> >  include/linux/clk.h      | 24 ++++++++++++++++++++++++
> >  2 files changed, 64 insertions(+)
> >
> > diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c index
> > 4fb4fd4b06bd..cbbd2cc339c3 100644
> > --- a/drivers/clk/clk-devres.c
> > +++ b/drivers/clk/clk-devres.c
> > @@ -182,6 +182,46 @@ int __must_check devm_clk_bulk_get_all(struct
> > device *dev,  }  EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all);
> >
> > +static void devm_clk_bulk_release_all_enable(struct device *dev, void
> > +*res) {
> > +	struct clk_bulk_devres *devres = res;
> > +
> > +	clk_bulk_disable_unprepare(devres->num_clks, devres->clks);
> > +	clk_bulk_put_all(devres->num_clks, devres->clks); }
> > +
> > +int __must_check devm_clk_bulk_get_all_enable(struct device *dev,
> > +					      struct clk_bulk_data **clks) {
> > +	struct clk_bulk_devres *devres;
> > +	int ret;
> > +
> > +	devres = devres_alloc(devm_clk_bulk_release_all_enable,
> > +			      sizeof(*devres), GFP_KERNEL);
> > +	if (!devres)
> > +		return -ENOMEM;
> > +
> > +	ret = clk_bulk_get_all(dev, &devres->clks);
> > +	if (ret > 0) {
> > +		*clks = devres->clks;
> > +		devres->num_clks = ret;
> > +	} else {
> > +		devres_free(devres);
> > +		return ret;
> > +	}
> 
> How about:
> 
> 	ret = clk_bulk_get_all(dev, &devres->clks);
> 	if (ret <= 0) {
> 		devres_free(devres);
> 		return ret;
> 	}
> 
> 	*clks = devres->clks;
> 	devres->num_clks = ret;
> 
> Even though this patch follows the pattern used by the rest of the APIs in the
> driver, IMO above makes it more readable.
> 

Since I have usually seen that maintainers suggest to maintain the coding style of the file, I followed the same.
If you have a stronger reason to change this, please let me know
Marek, Michael, Stephen please let us know what do you think about this?

> > +
> > +	ret = clk_bulk_prepare_enable(devres->num_clks, *clks);
> > +	if (!ret) {
> > +		devres_add(dev, devres);
> > +	} else {
> > +		clk_bulk_put_all(devres->num_clks, devres->clks);
> > +		devres_free(devres);
> > +	}
> > +
> 
> Same as above:
> 
> 	ret = clk_bulk_prepare_enable(devres->num_clks, *clks);
> 	if (ret) {
> 		clk_bulk_put_all(devres->num_clks, devres->clks);
> 		devres_free(devres);
> 		return ret;
> 	}
> 
> 	devres_add(dev, devres);
> 
> > +	return ret;
> 
> 	return 0;
> 

Same as above

> > +}
> > +EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all_enable);
> > +
> >  static int devm_clk_match(struct device *dev, void *res, void *data)
> > {
> >  	struct clk **c = res;
> > diff --git a/include/linux/clk.h b/include/linux/clk.h index
> > 1ef013324237..a005e709b7bd 100644
> > --- a/include/linux/clk.h
> > +++ b/include/linux/clk.h
> > @@ -438,6 +438,23 @@ int __must_check
> > devm_clk_bulk_get_optional(struct device *dev, int num_clks,  int
> __must_check devm_clk_bulk_get_all(struct device *dev,
> >  				       struct clk_bulk_data **clks);
> >
> > +/**
> > + * devm_clk_bulk_get_all_enable - managed get multiple clk consumers and
> > + *				  enable all clks
> 
> "Get and enable all clocks of the consumer (managed)"
> 

Will take this up in the next patchset

> > + * @dev: device for clock "consumer"
> > + * @clks: pointer to the clk_bulk_data table of consumer
> > + *
> > + * Returns success (0) or negative errno.
> > + *
> > + * This helper function allows drivers to get several clk
> 
> "This helper function allows drivers to get all clocks of the consumer and enables
> them..."
> 
> - Mani
> 

Will take this up. Thanks for your review Mani!

> > + * consumers and enable all of them in one operation with management.
> > + * The clks will automatically be disabled and freed when the device
> > + * is unbound.
> > + */
> > +
> > +int __must_check devm_clk_bulk_get_all_enable(struct device *dev,
> > +					      struct clk_bulk_data **clks);
> > +
> >  /**
> >   * devm_clk_get - lookup and obtain a managed reference to a clock producer.
> >   * @dev: device for clock "consumer"
> > @@ -960,6 +977,13 @@ static inline int __must_check
> devm_clk_bulk_get_all(struct device *dev,
> >  	return 0;
> >  }
> >
> > +static inline int __must_check devm_clk_bulk_get_all_enable(struct device
> *dev,
> > +						struct clk_bulk_data **clks)
> > +{
> > +
> > +	return 0;
> > +}
> > +
> >  static inline struct clk *devm_get_clk_from_child(struct device *dev,
> >  				struct device_node *np, const char *con_id)  {
> > --
> > 2.17.1
> >
> 
> --
> மணிவண்ணன் சதாசிவம்
Marek Szyprowski Feb. 5, 2024, 9:19 a.m. UTC | #4
On 02.02.2024 12:59, Shradha Todi wrote:
>> -----Original Message-----
>> From: Manivannan Sadhasivam<manivannan.sadhasivam@linaro.org>
>> Sent: 29 January 2024 12:25
>> To: Shradha Todi<shradha.t@samsung.com>
>> Subject: Re: [PATCH v4 1/2] clk: Provide managed helper to get and enable bulk
>> clocks
>>
>> On Wed, Jan 24, 2024 at 04:08:37PM +0530, Shradha Todi wrote:
>>> Provide a managed devm_clk_bulk* wrapper to get and enable all bulk
>>> clocks in order to simplify drivers that keeps all clocks enabled for
>>> the time of driver operation.
>>>
>>> Suggested-by: Marek Szyprowski<m.szyprowski@samsung.com>
>>> Signed-off-by: Shradha Todi<shradha.t@samsung.com>
>>> ---
>>>   drivers/clk/clk-devres.c | 40
>> ++++++++++++++++++++++++++++++++++++++++
>>>   include/linux/clk.h      | 24 ++++++++++++++++++++++++
>>>   2 files changed, 64 insertions(+)
>>>
>>> diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c index
>>> 4fb4fd4b06bd..cbbd2cc339c3 100644
>>> --- a/drivers/clk/clk-devres.c
>>> +++ b/drivers/clk/clk-devres.c
>>> @@ -182,6 +182,46 @@ int __must_check devm_clk_bulk_get_all(struct
>>> device *dev,  }  EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all);
>>>
>>> +static void devm_clk_bulk_release_all_enable(struct device *dev, void
>>> +*res) {
>>> +	struct clk_bulk_devres *devres = res;
>>> +
>>> +	clk_bulk_disable_unprepare(devres->num_clks, devres->clks);
>>> +	clk_bulk_put_all(devres->num_clks, devres->clks); }
>>> +
>>> +int __must_check devm_clk_bulk_get_all_enable(struct device *dev,
>>> +					      struct clk_bulk_data **clks) {
>>> +	struct clk_bulk_devres *devres;
>>> +	int ret;
>>> +
>>> +	devres = devres_alloc(devm_clk_bulk_release_all_enable,
>>> +			      sizeof(*devres), GFP_KERNEL);
>>> +	if (!devres)
>>> +		return -ENOMEM;
>>> +
>>> +	ret = clk_bulk_get_all(dev, &devres->clks);
>>> +	if (ret > 0) {
>>> +		*clks = devres->clks;
>>> +		devres->num_clks = ret;
>>> +	} else {
>>> +		devres_free(devres);
>>> +		return ret;
>>> +	}
>> How about:
>>
>> 	ret = clk_bulk_get_all(dev, &devres->clks);
>> 	if (ret <= 0) {
>> 		devres_free(devres);
>> 		return ret;
>> 	}
>>
>> 	*clks = devres->clks;
>> 	devres->num_clks = ret;
>>
>> Even though this patch follows the pattern used by the rest of the APIs in the
>> driver, IMO above makes it more readable.
>>
> Since I have usually seen that maintainers suggest to maintain the coding style of the file, I followed the same.
> If you have a stronger reason to change this, please let me know
> Marek, Michael, Stephen please let us know what do you think about this?

I suggest to keep the same style as is used in the modified file (if it 
doesn't conflict with the rules enforced by checkpatch and kernel's 
coding style).

Best regards
diff mbox series

Patch

diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c
index 4fb4fd4b06bd..cbbd2cc339c3 100644
--- a/drivers/clk/clk-devres.c
+++ b/drivers/clk/clk-devres.c
@@ -182,6 +182,46 @@  int __must_check devm_clk_bulk_get_all(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all);
 
+static void devm_clk_bulk_release_all_enable(struct device *dev, void *res)
+{
+	struct clk_bulk_devres *devres = res;
+
+	clk_bulk_disable_unprepare(devres->num_clks, devres->clks);
+	clk_bulk_put_all(devres->num_clks, devres->clks);
+}
+
+int __must_check devm_clk_bulk_get_all_enable(struct device *dev,
+					      struct clk_bulk_data **clks)
+{
+	struct clk_bulk_devres *devres;
+	int ret;
+
+	devres = devres_alloc(devm_clk_bulk_release_all_enable,
+			      sizeof(*devres), GFP_KERNEL);
+	if (!devres)
+		return -ENOMEM;
+
+	ret = clk_bulk_get_all(dev, &devres->clks);
+	if (ret > 0) {
+		*clks = devres->clks;
+		devres->num_clks = ret;
+	} else {
+		devres_free(devres);
+		return ret;
+	}
+
+	ret = clk_bulk_prepare_enable(devres->num_clks, *clks);
+	if (!ret) {
+		devres_add(dev, devres);
+	} else {
+		clk_bulk_put_all(devres->num_clks, devres->clks);
+		devres_free(devres);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all_enable);
+
 static int devm_clk_match(struct device *dev, void *res, void *data)
 {
 	struct clk **c = res;
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1ef013324237..a005e709b7bd 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -438,6 +438,23 @@  int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks,
 int __must_check devm_clk_bulk_get_all(struct device *dev,
 				       struct clk_bulk_data **clks);
 
+/**
+ * devm_clk_bulk_get_all_enable - managed get multiple clk consumers and
+ *				  enable all clks
+ * @dev: device for clock "consumer"
+ * @clks: pointer to the clk_bulk_data table of consumer
+ *
+ * Returns success (0) or negative errno.
+ *
+ * This helper function allows drivers to get several clk
+ * consumers and enable all of them in one operation with management.
+ * The clks will automatically be disabled and freed when the device
+ * is unbound.
+ */
+
+int __must_check devm_clk_bulk_get_all_enable(struct device *dev,
+					      struct clk_bulk_data **clks);
+
 /**
  * devm_clk_get - lookup and obtain a managed reference to a clock producer.
  * @dev: device for clock "consumer"
@@ -960,6 +977,13 @@  static inline int __must_check devm_clk_bulk_get_all(struct device *dev,
 	return 0;
 }
 
+static inline int __must_check devm_clk_bulk_get_all_enable(struct device *dev,
+						struct clk_bulk_data **clks)
+{
+
+	return 0;
+}
+
 static inline struct clk *devm_get_clk_from_child(struct device *dev,
 				struct device_node *np, const char *con_id)
 {