diff mbox

[v3,1/7] clk: divider: add flag to limit possible dividers to even numbers

Message ID 201306111329.32749.heiko@sntech.de (mailing list archive)
State New, archived
Headers show

Commit Message

Heiko Stuebner June 11, 2013, 11:29 a.m. UTC
SoCs like the Rockchip Cortex-A9 ones contain divider some clocks
that use the regular mechanisms for storage but allow only even
dividers and 1 to be used.

Therefore add a flag that lets _is_valid_div limit the valid dividers
to these values. _get_maxdiv is also adapted to return even values
for the CLK_DIVIDER_ONE_BASED case.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/clk/clk-divider.c    |   14 ++++++++++++--
 include/linux/clk-provider.h |    2 ++
 2 files changed, 14 insertions(+), 2 deletions(-)

Comments

Andy Shevchenko June 11, 2013, 11:51 a.m. UTC | #1
On Tue, Jun 11, 2013 at 2:29 PM, Heiko Stübner <heiko@sntech.de> wrote:
> SoCs like the Rockchip Cortex-A9 ones contain divider some clocks
> that use the regular mechanisms for storage but allow only even
> dividers and 1 to be used.
>
> Therefore add a flag that lets _is_valid_div limit the valid dividers
> to these values. _get_maxdiv is also adapted to return even values
> for the CLK_DIVIDER_ONE_BASED case.

Just one nitpick below (I'm okay with current implementation, but you
might find my proposal useful).

> --- a/drivers/clk/clk-divider.c
> +++ b/drivers/clk/clk-divider.c

> @@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
>                 return is_power_of_2(div);
>         if (divider->table)
>                 return _is_valid_table_div(divider->table, div);
> +       if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) != 0)
> +               return false;
>         return true;
>  }

What if rewrite like

 if (divider->flags & CLK_DIVIDER_EVEN == 0)
 return true;

return div < 2 || div % 2 == 0;


--
With Best Regards,
Andy Shevchenko
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Heiko Stuebner June 11, 2013, 12:06 p.m. UTC | #2
Am Dienstag, 11. Juni 2013, 13:51:56 schrieb Andy Shevchenko:
> On Tue, Jun 11, 2013 at 2:29 PM, Heiko Stübner <heiko@sntech.de> wrote:
> > SoCs like the Rockchip Cortex-A9 ones contain divider some clocks
> > that use the regular mechanisms for storage but allow only even
> > dividers and 1 to be used.
> > 
> > Therefore add a flag that lets _is_valid_div limit the valid dividers
> > to these values. _get_maxdiv is also adapted to return even values
> > for the CLK_DIVIDER_ONE_BASED case.
> 
> Just one nitpick below (I'm okay with current implementation, but you
> might find my proposal useful).
> 
> > --- a/drivers/clk/clk-divider.c
> > +++ b/drivers/clk/clk-divider.c
> > 
> > @@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider
> > *divider, unsigned int div)
> > 
> >                 return is_power_of_2(div);
> >         
> >         if (divider->table)
> >         
> >                 return _is_valid_table_div(divider->table, div);
> > 
> > +       if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) !=
> > 0) +               return false;
> > 
> >         return true;
> >  
> >  }
> 
> What if rewrite like
> 
>  if (divider->flags & CLK_DIVIDER_EVEN == 0)
>  return true;
> 
> return div < 2 || div % 2 == 0;

hmm, the current structure is of the form of testing for each feature and 
doing a applicable action if the flag is set. So it also is extensible for 
future flags and checking for the absence of an attribute while the rest of 
the conditionals check for the presence also might make the code harder to 
read.

So for me the current variant somehow looks more intuitive.

But I'll just let the majority decide ;-)


Heiko
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Andy Shevchenko June 11, 2013, 12:37 p.m. UTC | #3
On Tue, Jun 11, 2013 at 3:06 PM, Heiko Stübner <heiko@sntech.de> wrote:
> Am Dienstag, 11. Juni 2013, 13:51:56 schrieb Andy Shevchenko:
>> On Tue, Jun 11, 2013 at 2:29 PM, Heiko Stübner <heiko@sntech.de> wrote:

[]

>> > @@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider
>> > *divider, unsigned int div)
>> >
>> >                 return is_power_of_2(div);
>> >
>> >         if (divider->table)
>> >
>> >                 return _is_valid_table_div(divider->table, div);
>> >
>> > +       if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) !=
>> > 0) +               return false;
>> >
>> >         return true;
>> >
>> >  }
>>
>> What if rewrite like
>>
>>  if (divider->flags & CLK_DIVIDER_EVEN == 0)
>>  return true;
>>
>> return div < 2 || div % 2 == 0;
>
> hmm, the current structure is of the form of testing for each feature and
> doing a applicable action if the flag is set. So it also is extensible for
> future flags and checking for the absence of an attribute while the rest of
> the conditionals check for the presence also might make the code harder to
> read.
>
> So for me the current variant somehow looks more intuitive.

This variant I think fits:

if (!(divider->flags & CLK_DIVIDER_EVEN))
  return div < 2 || div % 2 == 0;

You check for feature and do accordingly.

--
With Best Regards,
Andy Shevchenko
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Andy Shevchenko June 11, 2013, 12:39 p.m. UTC | #4
On Tue, Jun 11, 2013 at 3:37 PM, Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
> On Tue, Jun 11, 2013 at 3:06 PM, Heiko Stübner <heiko@sntech.de> wrote:
>> Am Dienstag, 11. Juni 2013, 13:51:56 schrieb Andy Shevchenko:
>>> On Tue, Jun 11, 2013 at 2:29 PM, Heiko Stübner <heiko@sntech.de> wrote:

> This variant I think fits:
>
> if (!(divider->flags & CLK_DIVIDER_EVEN))

Oops, without "!()" of course.

>   return div < 2 || div % 2 == 0;
>
> You check for feature and do accordingly.


--
With Best Regards,
Andy Shevchenko
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mike Turquette June 11, 2013, 6:57 p.m. UTC | #5
Quoting Heiko Stübner (2013-06-11 04:29:32)
> SoCs like the Rockchip Cortex-A9 ones contain divider some clocks
> that use the regular mechanisms for storage but allow only even
> dividers and 1 to be used.
> 
> Therefore add a flag that lets _is_valid_div limit the valid dividers
> to these values. _get_maxdiv is also adapted to return even values
> for the CLK_DIVIDER_ONE_BASED case.
> 
> Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> ---
>  drivers/clk/clk-divider.c    |   14 ++++++++++++--
>  include/linux/clk-provider.h |    2 ++
>  2 files changed, 14 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
> index ce5cfe9..bdee7cf 100644
> --- a/drivers/clk/clk-divider.c
> +++ b/drivers/clk/clk-divider.c
> @@ -45,8 +45,16 @@ static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
>  
>  static unsigned int _get_maxdiv(struct clk_divider *divider)
>  {
> -       if (divider->flags & CLK_DIVIDER_ONE_BASED)
> -               return div_mask(divider);
> +       if (divider->flags & CLK_DIVIDER_ONE_BASED) {
> +               unsigned int div = div_mask(divider);
> +
> +               /* decrease to even number */
> +               if (divider->flags & CLK_DIVIDER_EVEN)
> +                       div--;
> +
> +               return div;
> +       }
> +
>         if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
>                 return 1 << div_mask(divider);
>         if (divider->table)
> @@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
>                 return is_power_of_2(div);
>         if (divider->table)
>                 return _is_valid_table_div(divider->table, div);
> +       if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) != 0)

Is it correct to check for 'div != 1' here?  Wouldn't that check only be
valid in the presence of CLK_DIVIDER_ONE_BASED?

Maybe something like this would be more correct:

	if (divider->flags & CLK_DIVIDER_EVEN && (div % 2) != 0) {
		if (divider->flags & CLK_DIVIDER_ONE_BASED && div == 1)
			return true;
		return false;
	}

Regards,
Mike

> +               return false;
>         return true;
>  }
>  
> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
> index 1ec14a7..bd52e52 100644
> --- a/include/linux/clk-provider.h
> +++ b/include/linux/clk-provider.h
> @@ -266,6 +266,7 @@ struct clk_div_table {
>   *   of this register, and mask of divider bits are in higher 16-bit of this
>   *   register.  While setting the divider bits, higher 16-bit should also be
>   *   updated to indicate changing divider bits.
> + * CLK_DIVIDER_EVEN - only allow even divider values
>   */
>  struct clk_divider {
>         struct clk_hw   hw;
> @@ -281,6 +282,7 @@ struct clk_divider {
>  #define CLK_DIVIDER_POWER_OF_TWO       BIT(1)
>  #define CLK_DIVIDER_ALLOW_ZERO         BIT(2)
>  #define CLK_DIVIDER_HIWORD_MASK                BIT(3)
> +#define CLK_DIVIDER_EVEN               BIT(4)
>  
>  extern const struct clk_ops clk_divider_ops;
>  struct clk *clk_register_divider(struct device *dev, const char *name,
> -- 
> 1.7.2.3
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Heiko Stuebner June 11, 2013, 7:23 p.m. UTC | #6
Am Dienstag, 11. Juni 2013, 20:57:50 schrieb Mike Turquette:
> Quoting Heiko Stübner (2013-06-11 04:29:32)
> 
> > SoCs like the Rockchip Cortex-A9 ones contain divider some clocks
> > that use the regular mechanisms for storage but allow only even
> > dividers and 1 to be used.
> > 
> > Therefore add a flag that lets _is_valid_div limit the valid dividers
> > to these values. _get_maxdiv is also adapted to return even values
> > for the CLK_DIVIDER_ONE_BASED case.
> > 
> > Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> > ---
> > 
> >  drivers/clk/clk-divider.c    |   14 ++++++++++++--
> >  include/linux/clk-provider.h |    2 ++
> >  2 files changed, 14 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
> > index ce5cfe9..bdee7cf 100644
> > --- a/drivers/clk/clk-divider.c
> > +++ b/drivers/clk/clk-divider.c
> > @@ -45,8 +45,16 @@ static unsigned int _get_table_maxdiv(const struct
> > clk_div_table *table)
> > 
> >  static unsigned int _get_maxdiv(struct clk_divider *divider)
> >  {
> > 
> > -       if (divider->flags & CLK_DIVIDER_ONE_BASED)
> > -               return div_mask(divider);
> > +       if (divider->flags & CLK_DIVIDER_ONE_BASED) {
> > +               unsigned int div = div_mask(divider);
> > +
> > +               /* decrease to even number */
> > +               if (divider->flags & CLK_DIVIDER_EVEN)
> > +                       div--;
> > +
> > +               return div;
> > +       }
> > +
> > 
> >         if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
> >         
> >                 return 1 << div_mask(divider);
> >         
> >         if (divider->table)
> > 
> > @@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider
> > *divider, unsigned int div)
> > 
> >                 return is_power_of_2(div);
> >         
> >         if (divider->table)
> >         
> >                 return _is_valid_table_div(divider->table, div);
> > 
> > +       if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) !=
> > 0)
> 
> Is it correct to check for 'div != 1' here?  Wouldn't that check only be
> valid in the presence of CLK_DIVIDER_ONE_BASED?
> 
> Maybe something like this would be more correct:
> 
> 	if (divider->flags & CLK_DIVIDER_EVEN && (div % 2) != 0) {
> 		if (divider->flags & CLK_DIVIDER_ONE_BASED && div == 1)
> 			return true;
> 		return false;
> 	}

hmm, not necessarily. As I understand the doc DIVIDER_ONE_BASED describes how 
the divider is stored in the register, i.e. if the register value is div-1 or 
div.

When div is 1, it of course means don't divide [rate/1], and CLK_DIVIDER_EVEN 
needs to just make sure that bigger dividers that really divide the rate are 
even values (so limiting the possible dividers to 1 2 4 ...), independent on 
how the divider value is stored in the register.


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

Patch

diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index ce5cfe9..bdee7cf 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -45,8 +45,16 @@  static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
 
 static unsigned int _get_maxdiv(struct clk_divider *divider)
 {
-	if (divider->flags & CLK_DIVIDER_ONE_BASED)
-		return div_mask(divider);
+	if (divider->flags & CLK_DIVIDER_ONE_BASED) {
+		unsigned int div = div_mask(divider);
+
+		/* decrease to even number */
+		if (divider->flags & CLK_DIVIDER_EVEN)
+			div--;
+
+		return div;
+	}
+
 	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
 		return 1 << div_mask(divider);
 	if (divider->table)
@@ -141,6 +149,8 @@  static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
 		return is_power_of_2(div);
 	if (divider->table)
 		return _is_valid_table_div(divider->table, div);
+	if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) != 0)
+		return false;
 	return true;
 }
 
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 1ec14a7..bd52e52 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -266,6 +266,7 @@  struct clk_div_table {
  *   of this register, and mask of divider bits are in higher 16-bit of this
  *   register.  While setting the divider bits, higher 16-bit should also be
  *   updated to indicate changing divider bits.
+ * CLK_DIVIDER_EVEN - only allow even divider values
  */
 struct clk_divider {
 	struct clk_hw	hw;
@@ -281,6 +282,7 @@  struct clk_divider {
 #define CLK_DIVIDER_POWER_OF_TWO	BIT(1)
 #define CLK_DIVIDER_ALLOW_ZERO		BIT(2)
 #define CLK_DIVIDER_HIWORD_MASK		BIT(3)
+#define CLK_DIVIDER_EVEN		BIT(4)
 
 extern const struct clk_ops clk_divider_ops;
 struct clk *clk_register_divider(struct device *dev, const char *name,