summaryrefslogtreecommitdiffstats
path: root/drivers/clk/clk-divider.c
diff options
context:
space:
mode:
authorJim Quinlan <jim2101024@gmail.com>2015-05-15 21:45:47 +0200
committerStephen Boyd <sboyd@codeaurora.org>2015-07-28 20:59:19 +0200
commitafe76c8fd030dd6b75fa69f7af7b7eb1e212f248 (patch)
treefcf7c6f403d54380eeef1b549a7197cc8dfa756e /drivers/clk/clk-divider.c
parentclk: socfpga: switch to GENMASK() (diff)
downloadlinux-afe76c8fd030dd6b75fa69f7af7b7eb1e212f248.tar.xz
linux-afe76c8fd030dd6b75fa69f7af7b7eb1e212f248.zip
clk: allow a clk divider with max divisor when zero
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>
Diffstat (limited to 'drivers/clk/clk-divider.c')
-rw-r--r--drivers/clk/clk-divider.c16
1 files changed, 11 insertions, 5 deletions
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 706b5783c360..2cab88b9c1a8 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -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));
}