These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / clk / clk-divider.c
index 25006a8..3ace102 100644 (file)
@@ -24,7 +24,7 @@
  * Traits of this clock:
  * prepare - clk_prepare only ensures that parents are prepared
  * enable - clk_enable only ensures that parents are enabled
- * rate - rate is adjustable.  clk->rate = DIV_ROUND_UP(parent->rate / divisor)
+ * rate - rate is adjustable.  clk->rate = ceiling(parent->rate / divisor)
  * parent - fixed parent.  No clk_set_parent support
  */
 
@@ -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,17 +121,18 @@ 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",
-                       __clk_get_name(hw->clk));
+                       clk_hw_get_name(hw));
                return parent_rate;
        }
 
-       return DIV_ROUND_UP(parent_rate, div);
+       return DIV_ROUND_UP_ULL((u64)parent_rate, div);
 }
 EXPORT_SYMBOL_GPL(divider_recalc_rate);
 
@@ -205,7 +210,7 @@ static int _div_round_up(const struct clk_div_table *table,
                         unsigned long parent_rate, unsigned long rate,
                         unsigned long flags)
 {
-       int div = DIV_ROUND_UP(parent_rate, rate);
+       int div = DIV_ROUND_UP_ULL((u64)parent_rate, rate);
 
        if (flags & CLK_DIVIDER_POWER_OF_TWO)
                div = __roundup_pow_of_two(div);
@@ -222,7 +227,7 @@ static int _div_round_closest(const struct clk_div_table *table,
        int up, down;
        unsigned long up_rate, down_rate;
 
-       up = DIV_ROUND_UP(parent_rate, rate);
+       up = DIV_ROUND_UP_ULL((u64)parent_rate, rate);
        down = parent_rate / rate;
 
        if (flags & CLK_DIVIDER_POWER_OF_TWO) {
@@ -233,8 +238,8 @@ static int _div_round_closest(const struct clk_div_table *table,
                down = _round_down_table(table, down);
        }
 
-       up_rate = DIV_ROUND_UP(parent_rate, up);
-       down_rate = DIV_ROUND_UP(parent_rate, down);
+       up_rate = DIV_ROUND_UP_ULL((u64)parent_rate, up);
+       down_rate = DIV_ROUND_UP_ULL((u64)parent_rate, down);
 
        return (rate - up_rate) <= (down_rate - rate) ? up : down;
 }
@@ -285,7 +290,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
 
        maxdiv = _get_maxdiv(table, width, flags);
 
-       if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
+       if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
                parent_rate = *best_parent_rate;
                bestdiv = _div_round(table, parent_rate, rate, flags);
                bestdiv = bestdiv == 0 ? 1 : bestdiv;
@@ -311,9 +316,9 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
                        *best_parent_rate = parent_rate_saved;
                        return i;
                }
-               parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
+               parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
                                               rate * i);
-               now = DIV_ROUND_UP(parent_rate, i);
+               now = DIV_ROUND_UP_ULL((u64)parent_rate, i);
                if (_is_best_div(rate, now, best, flags)) {
                        bestdiv = i;
                        best = now;
@@ -323,7 +328,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
 
        if (!bestdiv) {
                bestdiv = _get_maxdiv(table, width, flags);
-               *best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
+               *best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), 1);
        }
 
        return bestdiv;
@@ -337,7 +342,7 @@ long divider_round_rate(struct clk_hw *hw, unsigned long rate,
 
        div = clk_divider_bestdiv(hw, rate, prate, table, width, flags);
 
-       return DIV_ROUND_UP(*prate, div);
+       return DIV_ROUND_UP_ULL((u64)*prate, div);
 }
 EXPORT_SYMBOL_GPL(divider_round_rate);
 
@@ -351,8 +356,9 @@ 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);
-               return DIV_ROUND_UP(*prate, bestdiv);
+               bestdiv = _get_div(divider->table, bestdiv, divider->flags,
+                       divider->width);
+               return DIV_ROUND_UP_ULL((u64)*prate, bestdiv);
        }
 
        return divider_round_rate(hw, rate, prate, divider->table,
@@ -365,12 +371,12 @@ int divider_get_val(unsigned long rate, unsigned long parent_rate,
 {
        unsigned int div, value;
 
-       div = DIV_ROUND_UP(parent_rate, rate);
+       div = DIV_ROUND_UP_ULL((u64)parent_rate, 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));
 }
@@ -389,6 +395,8 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
 
        if (divider->lock)
                spin_lock_irqsave(divider->lock, flags);
+       else
+               __acquire(divider->lock);
 
        if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
                val = div_mask(divider->width) << (divider->shift + 16);
@@ -401,6 +409,8 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
 
        if (divider->lock)
                spin_unlock_irqrestore(divider->lock, flags);
+       else
+               __release(divider->lock);
 
        return 0;
 }
@@ -430,11 +440,9 @@ static struct clk *_register_divider(struct device *dev, const char *name,
        }
 
        /* allocate the divider */
-       div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
-       if (!div) {
-               pr_err("%s: could not allocate divider clk\n", __func__);
+       div = kzalloc(sizeof(*div), GFP_KERNEL);
+       if (!div)
                return ERR_PTR(-ENOMEM);
-       }
 
        init.name = name;
        init.ops = &clk_divider_ops;