Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit afe76c8f authored by Jim Quinlan's avatar Jim Quinlan Committed by Stephen Boyd
Browse files

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: default avatarJim Quinlan <jim2101024@gmail.com>
Signed-off-by: default avatarMichael Turquette <mturquette@baylibre.com>
parent 25d4d341
Loading
Loading
Loading
Loading
+11 −5
Original line number Diff line number Diff line
@@ -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));
}
+4 −0
Original line number Diff line number Diff line
@@ -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;