clk: allow a clk divider with max divisor when zero
authorJim Quinlan <jim2101024@gmail.com>
Fri, 15 May 2015 19:45:47 +0000 (15:45 -0400)
committerStephen Boyd <sboyd@codeaurora.org>
Tue, 28 Jul 2015 18:59:19 +0000 (11:59 -0700)
This commit allows certain Broadcom STB clock dividers to be used with
clk-divider.c.  It allows for a clock whose field value is the equal
to the divisor, execpt when the field value is zero, in which case the
divisor is 2^width.  For example, consider a divisor clock with a two
bit field:

value divisor
0 4
1 1
2 2
3 3

Signed-off-by: Jim Quinlan <jim2101024@gmail.com>
Signed-off-by: Michael Turquette <mturquette@baylibre.com>
drivers/clk/clk-divider.c
include/linux/clk-provider.h

index 706b5783c360dfc5ba60c6f7054374f5f06ff4f8..2cab88b9c1a814b1f2d24e51d288f3f80a5e0c8b 100644 (file)
@@ -78,12 +78,14 @@ static unsigned int _get_table_div(const struct clk_div_table *table,
 }
 
 static unsigned int _get_div(const struct clk_div_table *table,
-                            unsigned int val, unsigned long flags)
+                            unsigned int val, unsigned long flags, u8 width)
 {
        if (flags & CLK_DIVIDER_ONE_BASED)
                return val;
        if (flags & CLK_DIVIDER_POWER_OF_TWO)
                return 1 << val;
+       if (flags & CLK_DIVIDER_MAX_AT_ZERO)
+               return val ? val : div_mask(width) + 1;
        if (table)
                return _get_table_div(table, val);
        return val + 1;
@@ -101,12 +103,14 @@ static unsigned int _get_table_val(const struct clk_div_table *table,
 }
 
 static unsigned int _get_val(const struct clk_div_table *table,
-                            unsigned int div, unsigned long flags)
+                            unsigned int div, unsigned long flags, u8 width)
 {
        if (flags & CLK_DIVIDER_ONE_BASED)
                return div;
        if (flags & CLK_DIVIDER_POWER_OF_TWO)
                return __ffs(div);
+       if (flags & CLK_DIVIDER_MAX_AT_ZERO)
+               return (div == div_mask(width) + 1) ? 0 : div;
        if (table)
                return  _get_table_val(table, div);
        return div - 1;
@@ -117,9 +121,10 @@ unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate,
                                  const struct clk_div_table *table,
                                  unsigned long flags)
 {
+       struct clk_divider *divider = to_clk_divider(hw);
        unsigned int div;
 
-       div = _get_div(table, val, flags);
+       div = _get_div(table, val, flags, divider->width);
        if (!div) {
                WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO),
                        "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
@@ -351,7 +356,8 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
        if (divider->flags & CLK_DIVIDER_READ_ONLY) {
                bestdiv = readl(divider->reg) >> divider->shift;
                bestdiv &= div_mask(divider->width);
-               bestdiv = _get_div(divider->table, bestdiv, divider->flags);
+               bestdiv = _get_div(divider->table, bestdiv, divider->flags,
+                       divider->width);
                return DIV_ROUND_UP(*prate, bestdiv);
        }
 
@@ -370,7 +376,7 @@ int divider_get_val(unsigned long rate, unsigned long parent_rate,
        if (!_is_valid_div(table, div, flags))
                return -EINVAL;
 
-       value = _get_val(table, div, flags);
+       value = _get_val(table, div, flags, width);
 
        return min_t(unsigned int, value, div_mask(width));
 }
index 402478ed9933aa85fba0a40f9450ab93b828c1da..699a2507517069f18ae2f88d18682a9d5a8df4f5 100644 (file)
@@ -361,6 +361,9 @@ struct clk_div_table {
  *     to the closest integer instead of the up one.
  * CLK_DIVIDER_READ_ONLY - The divider settings are preconfigured and should
  *     not be changed by the clock framework.
+ * CLK_DIVIDER_MAX_AT_ZERO - For dividers which are like CLK_DIVIDER_ONE_BASED
+ *     except when the value read from the register is zero, the divisor is
+ *     2^width of the field.
  */
 struct clk_divider {
        struct clk_hw   hw;
@@ -378,6 +381,7 @@ struct clk_divider {
 #define CLK_DIVIDER_HIWORD_MASK                BIT(3)
 #define CLK_DIVIDER_ROUND_CLOSEST      BIT(4)
 #define CLK_DIVIDER_READ_ONLY          BIT(5)
+#define CLK_DIVIDER_MAX_AT_ZERO                BIT(6)
 
 extern const struct clk_ops clk_divider_ops;