From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: From: Jim Quinlan To: , CC: , Jim Quinlan Subject: [PATCH] clk: allow a clk divider with max divisor when zero Date: Fri, 15 May 2015 15:45:47 -0400 Message-ID: <1431719147-10153-1-git-send-email-jim2101024@gmail.com> MIME-Version: 1.0 Content-Type: text/plain Return-Path: jim2101024@gmail.com List-ID: 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 --- drivers/clk/clk-divider.c | 16 +++++++++++----- include/linux/clk-provider.h | 4 ++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 25006a8..fce0d8b 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)); } diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index df69531..a30c24c 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -342,6 +342,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; @@ -359,6 +362,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; -- 1.9.0.138.g2de3478