mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									25d4d341d3
								
							
						
					
					
						commit
						afe76c8fd0
					
				
					 2 changed files with 15 additions and 5 deletions
				
			
		| 
						 | 
					@ -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,
 | 
					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)
 | 
						if (flags & CLK_DIVIDER_ONE_BASED)
 | 
				
			||||||
		return val;
 | 
							return val;
 | 
				
			||||||
	if (flags & CLK_DIVIDER_POWER_OF_TWO)
 | 
						if (flags & CLK_DIVIDER_POWER_OF_TWO)
 | 
				
			||||||
		return 1 << val;
 | 
							return 1 << val;
 | 
				
			||||||
 | 
						if (flags & CLK_DIVIDER_MAX_AT_ZERO)
 | 
				
			||||||
 | 
							return val ? val : div_mask(width) + 1;
 | 
				
			||||||
	if (table)
 | 
						if (table)
 | 
				
			||||||
		return _get_table_div(table, val);
 | 
							return _get_table_div(table, val);
 | 
				
			||||||
	return val + 1;
 | 
						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,
 | 
					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)
 | 
						if (flags & CLK_DIVIDER_ONE_BASED)
 | 
				
			||||||
		return div;
 | 
							return div;
 | 
				
			||||||
	if (flags & CLK_DIVIDER_POWER_OF_TWO)
 | 
						if (flags & CLK_DIVIDER_POWER_OF_TWO)
 | 
				
			||||||
		return __ffs(div);
 | 
							return __ffs(div);
 | 
				
			||||||
 | 
						if (flags & CLK_DIVIDER_MAX_AT_ZERO)
 | 
				
			||||||
 | 
							return (div == div_mask(width) + 1) ? 0 : div;
 | 
				
			||||||
	if (table)
 | 
						if (table)
 | 
				
			||||||
		return  _get_table_val(table, div);
 | 
							return  _get_table_val(table, div);
 | 
				
			||||||
	return div - 1;
 | 
						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,
 | 
									  const struct clk_div_table *table,
 | 
				
			||||||
				  unsigned long flags)
 | 
									  unsigned long flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct clk_divider *divider = to_clk_divider(hw);
 | 
				
			||||||
	unsigned int div;
 | 
						unsigned int div;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	div = _get_div(table, val, flags);
 | 
						div = _get_div(table, val, flags, divider->width);
 | 
				
			||||||
	if (!div) {
 | 
						if (!div) {
 | 
				
			||||||
		WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO),
 | 
							WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO),
 | 
				
			||||||
			"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
 | 
								"%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) {
 | 
						if (divider->flags & CLK_DIVIDER_READ_ONLY) {
 | 
				
			||||||
		bestdiv = readl(divider->reg) >> divider->shift;
 | 
							bestdiv = readl(divider->reg) >> divider->shift;
 | 
				
			||||||
		bestdiv &= div_mask(divider->width);
 | 
							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);
 | 
							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))
 | 
						if (!_is_valid_div(table, div, flags))
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	value = _get_val(table, div, flags);
 | 
						value = _get_val(table, div, flags, width);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return min_t(unsigned int, value, div_mask(width));
 | 
						return min_t(unsigned int, value, div_mask(width));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -361,6 +361,9 @@ struct clk_div_table {
 | 
				
			||||||
 *	to the closest integer instead of the up one.
 | 
					 *	to the closest integer instead of the up one.
 | 
				
			||||||
 * CLK_DIVIDER_READ_ONLY - The divider settings are preconfigured and should
 | 
					 * CLK_DIVIDER_READ_ONLY - The divider settings are preconfigured and should
 | 
				
			||||||
 *	not be changed by the clock framework.
 | 
					 *	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_divider {
 | 
				
			||||||
	struct clk_hw	hw;
 | 
						struct clk_hw	hw;
 | 
				
			||||||
| 
						 | 
					@ -378,6 +381,7 @@ struct clk_divider {
 | 
				
			||||||
#define CLK_DIVIDER_HIWORD_MASK		BIT(3)
 | 
					#define CLK_DIVIDER_HIWORD_MASK		BIT(3)
 | 
				
			||||||
#define CLK_DIVIDER_ROUND_CLOSEST	BIT(4)
 | 
					#define CLK_DIVIDER_ROUND_CLOSEST	BIT(4)
 | 
				
			||||||
#define CLK_DIVIDER_READ_ONLY		BIT(5)
 | 
					#define CLK_DIVIDER_READ_ONLY		BIT(5)
 | 
				
			||||||
 | 
					#define CLK_DIVIDER_MAX_AT_ZERO		BIT(6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern const struct clk_ops clk_divider_ops;
 | 
					extern const struct clk_ops clk_divider_ops;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue