Merge branch 'upstream' of git://git.infradead.org/users/pcmoore/audit
[cascardo/linux.git] / drivers / clk / clk-divider.c
index 706b578..f24d0a1 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,13 +121,14 @@ 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;
        }
 
@@ -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,7 +316,7 @@ 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);
                if (_is_best_div(rate, now, best, flags)) {
@@ -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;
@@ -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));
 }
@@ -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;
 }