diff mbox

[07/12] hwrng: bcm2835-rng: Manage an optional clock

Message ID 20171102010408.27736-8-f.fainelli@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Florian Fainelli Nov. 2, 2017, 1:04 a.m. UTC
One of the last steps before bcm63xx-rng can be eliminated is to manage
a clock during hwrng::init and hwrng::cleanup, so fetch it in the probe
function, and manage it during these two steps when valid.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 drivers/char/hw_random/bcm2835-rng.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

Comments

Stefan Wahren Nov. 4, 2017, 1:50 p.m. UTC | #1
Hi Florian,

> Florian Fainelli <f.fainelli@gmail.com> hat am 2. November 2017 um 02:04 geschrieben:
> 
> 
> One of the last steps before bcm63xx-rng can be eliminated is to manage
> a clock during hwrng::init and hwrng::cleanup, so fetch it in the probe
> function, and manage it during these two steps when valid.
> 
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
> ---
>  drivers/char/hw_random/bcm2835-rng.c | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)
> 
> diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c
> index ed20e0b6b7ae..35928efb52e7 100644
> --- a/drivers/char/hw_random/bcm2835-rng.c
> +++ b/drivers/char/hw_random/bcm2835-rng.c
> @@ -15,6 +15,7 @@
>  #include <linux/of_platform.h>
>  #include <linux/platform_device.h>
>  #include <linux/printk.h>
> +#include <linux/clk.h>
>  
>  #define RNG_CTRL	0x0
>  #define RNG_STATUS	0x4
> @@ -33,6 +34,7 @@ struct bcm2835_rng_priv {
>  	struct hwrng rng;
>  	void __iomem *base;
>  	bool mask_interrupts;
> +	struct clk *clk;
>  };
>  
>  static inline struct bcm2835_rng_priv *to_rng_priv(struct hwrng *rng)
> @@ -67,6 +69,11 @@ static int bcm2835_rng_init(struct hwrng *rng)
>  {
>  	struct bcm2835_rng_priv *priv = to_rng_priv(rng);
>  	u32 val;
> +	int ret;
> +
> +	ret = clk_prepare_enable(priv->clk);
> +	if (ret)
> +		return ret;
>  
>  	if (priv->mask_interrupts) {
>  		/* mask the interrupt */
> @@ -88,6 +95,8 @@ static void bcm2835_rng_cleanup(struct hwrng *rng)
>  
>  	/* disable rng hardware */
>  	__raw_writel(0, priv->base + RNG_CTRL);
> +
> +	clk_disable_unprepare(priv->clk);
>  }
>  
>  struct bcm2835_rng_of_data {
> @@ -130,6 +139,11 @@ static int bcm2835_rng_probe(struct platform_device *pdev)
>  		return PTR_ERR(priv->base);
>  	}
>  
> +	/* Clock is optional on most platforms */
> +	priv->clk = devm_clk_get(dev, NULL);
> +	if (IS_ERR(priv->clk))
> +		priv->clk = NULL;

at least in case of EPROBE_DEFERED this isn't the expected behavior. Maybe we should better trigger on non-existing clock?

> +
>  	priv->rng.name = "bcm2835-rng";
>  	priv->rng.init = bcm2835_rng_init;
>  	priv->rng.read = bcm2835_rng_read;
> -- 
> 2.9.3
>
Florian Fainelli Nov. 4, 2017, 5:59 p.m. UTC | #2
Hi Stefan,

On 11/04/2017 06:50 AM, Stefan Wahren wrote:
> Hi Florian,
> 
>> Florian Fainelli <f.fainelli@gmail.com> hat am 2. November 2017 um 02:04 geschrieben:
>>
>>
>> One of the last steps before bcm63xx-rng can be eliminated is to manage
>> a clock during hwrng::init and hwrng::cleanup, so fetch it in the probe
>> function, and manage it during these two steps when valid.
>>
>> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
>> ---
>>  drivers/char/hw_random/bcm2835-rng.c | 14 ++++++++++++++
>>  1 file changed, 14 insertions(+)
>>
>> diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c
>> index ed20e0b6b7ae..35928efb52e7 100644
>> --- a/drivers/char/hw_random/bcm2835-rng.c
>> +++ b/drivers/char/hw_random/bcm2835-rng.c
>> @@ -15,6 +15,7 @@
>>  #include <linux/of_platform.h>
>>  #include <linux/platform_device.h>
>>  #include <linux/printk.h>
>> +#include <linux/clk.h>
>>  
>>  #define RNG_CTRL	0x0
>>  #define RNG_STATUS	0x4
>> @@ -33,6 +34,7 @@ struct bcm2835_rng_priv {
>>  	struct hwrng rng;
>>  	void __iomem *base;
>>  	bool mask_interrupts;
>> +	struct clk *clk;
>>  };
>>  
>>  static inline struct bcm2835_rng_priv *to_rng_priv(struct hwrng *rng)
>> @@ -67,6 +69,11 @@ static int bcm2835_rng_init(struct hwrng *rng)
>>  {
>>  	struct bcm2835_rng_priv *priv = to_rng_priv(rng);
>>  	u32 val;
>> +	int ret;
>> +
>> +	ret = clk_prepare_enable(priv->clk);
>> +	if (ret)
>> +		return ret;
>>  
>>  	if (priv->mask_interrupts) {
>>  		/* mask the interrupt */
>> @@ -88,6 +95,8 @@ static void bcm2835_rng_cleanup(struct hwrng *rng)
>>  
>>  	/* disable rng hardware */
>>  	__raw_writel(0, priv->base + RNG_CTRL);
>> +
>> +	clk_disable_unprepare(priv->clk);
>>  }
>>  
>>  struct bcm2835_rng_of_data {
>> @@ -130,6 +139,11 @@ static int bcm2835_rng_probe(struct platform_device *pdev)
>>  		return PTR_ERR(priv->base);
>>  	}
>>  
>> +	/* Clock is optional on most platforms */
>> +	priv->clk = devm_clk_get(dev, NULL);
>> +	if (IS_ERR(priv->clk))
>> +		priv->clk = NULL;
> 
> at least in case of EPROBE_DEFERED this isn't the expected behavior. Maybe we should better trigger on non-existing clock?

Good point, so more like:

if (IS_ERR(priv->clk) && PTR_ERR(priv->clk) == -ENODEV)?
Stefan Wahren Nov. 4, 2017, 6:22 p.m. UTC | #3
> Florian Fainelli <f.fainelli@gmail.com> hat am 4. November 2017 um 18:59 geschrieben:
> 
> 
> Hi Stefan,
> 
> On 11/04/2017 06:50 AM, Stefan Wahren wrote:
> > Hi Florian,
> > 
> >> Florian Fainelli <f.fainelli@gmail.com> hat am 2. November 2017 um 02:04 geschrieben:
> >>
> >>
> >> One of the last steps before bcm63xx-rng can be eliminated is to manage
> >> a clock during hwrng::init and hwrng::cleanup, so fetch it in the probe
> >> function, and manage it during these two steps when valid.
> >>
> >> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
> >> ---
> >>  drivers/char/hw_random/bcm2835-rng.c | 14 ++++++++++++++
> >>  1 file changed, 14 insertions(+)
> >>
> >> diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c
> >> index ed20e0b6b7ae..35928efb52e7 100644
> >> --- a/drivers/char/hw_random/bcm2835-rng.c
> >> +++ b/drivers/char/hw_random/bcm2835-rng.c
> >> @@ -15,6 +15,7 @@
> >>  #include <linux/of_platform.h>
> >>  #include <linux/platform_device.h>
> >>  #include <linux/printk.h>
> >> +#include <linux/clk.h>
> >>  
> >>  #define RNG_CTRL	0x0
> >>  #define RNG_STATUS	0x4
> >> @@ -33,6 +34,7 @@ struct bcm2835_rng_priv {
> >>  	struct hwrng rng;
> >>  	void __iomem *base;
> >>  	bool mask_interrupts;
> >> +	struct clk *clk;
> >>  };
> >>  
> >>  static inline struct bcm2835_rng_priv *to_rng_priv(struct hwrng *rng)
> >> @@ -67,6 +69,11 @@ static int bcm2835_rng_init(struct hwrng *rng)
> >>  {
> >>  	struct bcm2835_rng_priv *priv = to_rng_priv(rng);
> >>  	u32 val;
> >> +	int ret;
> >> +
> >> +	ret = clk_prepare_enable(priv->clk);
> >> +	if (ret)
> >> +		return ret;
> >>  
> >>  	if (priv->mask_interrupts) {
> >>  		/* mask the interrupt */
> >> @@ -88,6 +95,8 @@ static void bcm2835_rng_cleanup(struct hwrng *rng)
> >>  
> >>  	/* disable rng hardware */
> >>  	__raw_writel(0, priv->base + RNG_CTRL);
> >> +
> >> +	clk_disable_unprepare(priv->clk);
> >>  }
> >>  
> >>  struct bcm2835_rng_of_data {
> >> @@ -130,6 +139,11 @@ static int bcm2835_rng_probe(struct platform_device *pdev)
> >>  		return PTR_ERR(priv->base);
> >>  	}
> >>  
> >> +	/* Clock is optional on most platforms */
> >> +	priv->clk = devm_clk_get(dev, NULL);
> >> +	if (IS_ERR(priv->clk))
> >> +		priv->clk = NULL;
> > 
> > at least in case of EPROBE_DEFERED this isn't the expected behavior. Maybe we should better trigger on non-existing clock?
> 
> Good point, so more like:
> 
> if (IS_ERR(priv->clk) && PTR_ERR(priv->clk) == -ENODEV)?

Unfortunately we need to return the error in all other cases. Please take a look at devm_usb_get_phy in dwc2 [1]. AFAIK we don't need to take care of ENXIO in our case.

http://elixir.free-electrons.com/linux/latest/source/drivers/usb/dwc2/platform.c#L247

> 
> -- 
> Florian
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Andrew Lunn Nov. 4, 2017, 7:37 p.m. UTC | #4
Hi Florian

> > >> +	/* Clock is optional on most platforms */
> > >> +	priv->clk = devm_clk_get(dev, NULL);
> > >> +	if (IS_ERR(priv->clk))
> > >> +		priv->clk = NULL;
> > > 
> > > at least in case of EPROBE_DEFERED this isn't the expected behavior. Maybe we should better trigger on non-existing clock?
> > 
> > Good point, so more like:
> > 
> > if (IS_ERR(priv->clk) && PTR_ERR(priv->clk) == -ENODEV)?
> 

> Unfortunately we need to return the error in all other cases. Please
> take a look at devm_usb_get_phy in dwc2 [1]. AFAIK we don't need to
> take care of ENXIO in our case.

A few subsystems have a get_optional() call, e.g.
devm_phy_optional_get(). It does not return an error when the phy is
not supposed to exist, but in all other cases, it does.

Maybe consider adding devm_clk_get_optional()?

      Andrew
Russell King (Oracle) Nov. 4, 2017, 8:08 p.m. UTC | #5
On Sat, Nov 04, 2017 at 08:37:31PM +0100, Andrew Lunn wrote:
> Hi Florian
> 
> > > >> +	/* Clock is optional on most platforms */
> > > >> +	priv->clk = devm_clk_get(dev, NULL);
> > > >> +	if (IS_ERR(priv->clk))
> > > >> +		priv->clk = NULL;
> > > > 
> > > > at least in case of EPROBE_DEFERED this isn't the expected behavior. Maybe we should better trigger on non-existing clock?
> > > 
> > > Good point, so more like:
> > > 
> > > if (IS_ERR(priv->clk) && PTR_ERR(priv->clk) == -ENODEV)?
> > 
> 
> > Unfortunately we need to return the error in all other cases. Please
> > take a look at devm_usb_get_phy in dwc2 [1]. AFAIK we don't need to
> > take care of ENXIO in our case.
> 
> A few subsystems have a get_optional() call, e.g.
> devm_phy_optional_get(). It does not return an error when the phy is
> not supposed to exist, but in all other cases, it does.
> 
> Maybe consider adding devm_clk_get_optional()?

The clk API outside of DT doesn't have knowledge of when it's "complete"
to be able to determine whether the clock is not present or temporarily
missing.  I've already NAK'd this suggestion.
Andrew Lunn Nov. 4, 2017, 8:17 p.m. UTC | #6
> The clk API outside of DT doesn't have knowledge of when it's "complete"
> to be able to determine whether the clock is not present or temporarily
> missing.  I've already NAK'd this suggestion.

Hi Russell

O.K, yes, makes sense.

We do have of_clk_get_by_name() and of_clk_get(). Would optional
variants of these be acceptable?

	 Andrew
diff mbox

Patch

diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c
index ed20e0b6b7ae..35928efb52e7 100644
--- a/drivers/char/hw_random/bcm2835-rng.c
+++ b/drivers/char/hw_random/bcm2835-rng.c
@@ -15,6 +15,7 @@ 
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/printk.h>
+#include <linux/clk.h>
 
 #define RNG_CTRL	0x0
 #define RNG_STATUS	0x4
@@ -33,6 +34,7 @@  struct bcm2835_rng_priv {
 	struct hwrng rng;
 	void __iomem *base;
 	bool mask_interrupts;
+	struct clk *clk;
 };
 
 static inline struct bcm2835_rng_priv *to_rng_priv(struct hwrng *rng)
@@ -67,6 +69,11 @@  static int bcm2835_rng_init(struct hwrng *rng)
 {
 	struct bcm2835_rng_priv *priv = to_rng_priv(rng);
 	u32 val;
+	int ret;
+
+	ret = clk_prepare_enable(priv->clk);
+	if (ret)
+		return ret;
 
 	if (priv->mask_interrupts) {
 		/* mask the interrupt */
@@ -88,6 +95,8 @@  static void bcm2835_rng_cleanup(struct hwrng *rng)
 
 	/* disable rng hardware */
 	__raw_writel(0, priv->base + RNG_CTRL);
+
+	clk_disable_unprepare(priv->clk);
 }
 
 struct bcm2835_rng_of_data {
@@ -130,6 +139,11 @@  static int bcm2835_rng_probe(struct platform_device *pdev)
 		return PTR_ERR(priv->base);
 	}
 
+	/* Clock is optional on most platforms */
+	priv->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(priv->clk))
+		priv->clk = NULL;
+
 	priv->rng.name = "bcm2835-rng";
 	priv->rng.init = bcm2835_rng_init;
 	priv->rng.read = bcm2835_rng_read;