提交 357c3f0a 编写于 作者: R Rajendra Nayak 提交者: Mike Turquette

clk: Add support for rate table based dividers

Some divider clks do not have any obvious relationship
between the divider and the value programmed in the
register. For instance, say a value of 1 could signify divide
by 6 and a value of 2 could signify divide by 4 etc.
Also there are dividers where not all values possible
based on the bitfield width are valid. For instance
a 3 bit wide bitfield can be used to program a value
from 0 to 7. However its possible that only 0 to 4
are valid values.

All these cases need the platform code to pass a simple
table of divider/value tuple, so the framework knows
the exact value to be written based on the divider
calculation and can also do better error checking.

This patch adds support for such rate table based
dividers and as part of the support adds a new
registration function 'clk_register_divider_table()'
and a new macro for static definition
'DEFINE_CLK_DIVIDER_TABLE'.
Signed-off-by: NRajendra Nayak <rnayak@ti.com>
Signed-off-by: NMike Turquette <mturquette@linaro.org>
上级 6d9252bd
...@@ -32,30 +32,69 @@ ...@@ -32,30 +32,69 @@
#define div_mask(d) ((1 << (d->width)) - 1) #define div_mask(d) ((1 << (d->width)) - 1)
#define is_power_of_two(i) !(i & ~i) #define is_power_of_two(i) !(i & ~i)
static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
{
unsigned int maxdiv = 0;
const struct clk_div_table *clkt;
for (clkt = table; clkt->div; clkt++)
if (clkt->div > maxdiv)
maxdiv = clkt->div;
return maxdiv;
}
static unsigned int _get_maxdiv(struct clk_divider *divider) static unsigned int _get_maxdiv(struct clk_divider *divider)
{ {
if (divider->flags & CLK_DIVIDER_ONE_BASED) if (divider->flags & CLK_DIVIDER_ONE_BASED)
return div_mask(divider); return div_mask(divider);
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
return 1 << div_mask(divider); return 1 << div_mask(divider);
if (divider->table)
return _get_table_maxdiv(divider->table);
return div_mask(divider) + 1; return div_mask(divider) + 1;
} }
static unsigned int _get_table_div(const struct clk_div_table *table,
unsigned int val)
{
const struct clk_div_table *clkt;
for (clkt = table; clkt->div; clkt++)
if (clkt->val == val)
return clkt->div;
return 0;
}
static unsigned int _get_div(struct clk_divider *divider, unsigned int val) static unsigned int _get_div(struct clk_divider *divider, unsigned int val)
{ {
if (divider->flags & CLK_DIVIDER_ONE_BASED) if (divider->flags & CLK_DIVIDER_ONE_BASED)
return val; return val;
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
return 1 << val; return 1 << val;
if (divider->table)
return _get_table_div(divider->table, val);
return val + 1; return val + 1;
} }
static unsigned int _get_table_val(const struct clk_div_table *table,
unsigned int div)
{
const struct clk_div_table *clkt;
for (clkt = table; clkt->div; clkt++)
if (clkt->div == div)
return clkt->val;
return 0;
}
static unsigned int _get_val(struct clk_divider *divider, u8 div) static unsigned int _get_val(struct clk_divider *divider, u8 div)
{ {
if (divider->flags & CLK_DIVIDER_ONE_BASED) if (divider->flags & CLK_DIVIDER_ONE_BASED)
return div; return div;
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
return __ffs(div); return __ffs(div);
if (divider->table)
return _get_table_val(divider->table, div);
return div - 1; return div - 1;
} }
...@@ -84,6 +123,26 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, ...@@ -84,6 +123,26 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
*/ */
#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1) #define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
static bool _is_valid_table_div(const struct clk_div_table *table,
unsigned int div)
{
const struct clk_div_table *clkt;
for (clkt = table; clkt->div; clkt++)
if (clkt->div == div)
return true;
return false;
}
static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
{
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
return is_power_of_two(div);
if (divider->table)
return _is_valid_table_div(divider->table, div);
return true;
}
static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate) unsigned long *best_parent_rate)
{ {
...@@ -111,8 +170,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, ...@@ -111,8 +170,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
maxdiv = min(ULONG_MAX / rate, maxdiv); maxdiv = min(ULONG_MAX / rate, maxdiv);
for (i = 1; i <= maxdiv; i++) { for (i = 1; i <= maxdiv; i++) {
if ((divider->flags & CLK_DIVIDER_POWER_OF_TWO) if (!_is_valid_div(divider, i))
&& (!is_power_of_two(i)))
continue; continue;
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
MULT_ROUND_UP(rate, i)); MULT_ROUND_UP(rate, i));
...@@ -176,22 +234,11 @@ const struct clk_ops clk_divider_ops = { ...@@ -176,22 +234,11 @@ const struct clk_ops clk_divider_ops = {
}; };
EXPORT_SYMBOL_GPL(clk_divider_ops); EXPORT_SYMBOL_GPL(clk_divider_ops);
/** static struct clk *_register_divider(struct device *dev, const char *name,
* clk_register_divider - register a divider clock with the clock framework
* @dev: device registering this clock
* @name: name of this clock
* @parent_name: name of clock's parent
* @flags: framework-specific flags
* @reg: register address to adjust divider
* @shift: number of bits to shift the bitfield
* @width: width of the bitfield
* @clk_divider_flags: divider-specific flags for this clock
* @lock: shared register lock for this clock
*/
struct clk *clk_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags, const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width, void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, spinlock_t *lock) u8 clk_divider_flags, const struct clk_div_table *table,
spinlock_t *lock)
{ {
struct clk_divider *div; struct clk_divider *div;
struct clk *clk; struct clk *clk;
...@@ -217,6 +264,7 @@ struct clk *clk_register_divider(struct device *dev, const char *name, ...@@ -217,6 +264,7 @@ struct clk *clk_register_divider(struct device *dev, const char *name,
div->flags = clk_divider_flags; div->flags = clk_divider_flags;
div->lock = lock; div->lock = lock;
div->hw.init = &init; div->hw.init = &init;
div->table = table;
/* register the clock */ /* register the clock */
clk = clk_register(dev, &div->hw); clk = clk_register(dev, &div->hw);
...@@ -226,3 +274,48 @@ struct clk *clk_register_divider(struct device *dev, const char *name, ...@@ -226,3 +274,48 @@ struct clk *clk_register_divider(struct device *dev, const char *name,
return clk; return clk;
} }
/**
* clk_register_divider - register a divider clock with the clock framework
* @dev: device registering this clock
* @name: name of this clock
* @parent_name: name of clock's parent
* @flags: framework-specific flags
* @reg: register address to adjust divider
* @shift: number of bits to shift the bitfield
* @width: width of the bitfield
* @clk_divider_flags: divider-specific flags for this clock
* @lock: shared register lock for this clock
*/
struct clk *clk_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, spinlock_t *lock)
{
return _register_divider(dev, name, parent_name, flags, reg, shift,
width, clk_divider_flags, NULL, lock);
}
/**
* clk_register_divider_table - register a table based divider clock with
* the clock framework
* @dev: device registering this clock
* @name: name of this clock
* @parent_name: name of clock's parent
* @flags: framework-specific flags
* @reg: register address to adjust divider
* @shift: number of bits to shift the bitfield
* @width: width of the bitfield
* @clk_divider_flags: divider-specific flags for this clock
* @table: array of divider/value pairs ending with a div set to 0
* @lock: shared register lock for this clock
*/
struct clk *clk_register_divider_table(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, const struct clk_div_table *table,
spinlock_t *lock)
{
return _register_divider(dev, name, parent_name, flags, reg, shift,
width, clk_divider_flags, table, lock);
}
...@@ -103,9 +103,9 @@ struct clk { ...@@ -103,9 +103,9 @@ struct clk {
DEFINE_CLK(_name, clk_gate_ops, _flags, \ DEFINE_CLK(_name, clk_gate_ops, _flags, \
_name##_parent_names, _name##_parents); _name##_parent_names, _name##_parents);
#define DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \ #define _DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \
_flags, _reg, _shift, _width, \ _flags, _reg, _shift, _width, \
_divider_flags, _lock) \ _divider_flags, _table, _lock) \
static struct clk _name; \ static struct clk _name; \
static const char *_name##_parent_names[] = { \ static const char *_name##_parent_names[] = { \
_parent_name, \ _parent_name, \
...@@ -121,11 +121,27 @@ struct clk { ...@@ -121,11 +121,27 @@ struct clk {
.shift = _shift, \ .shift = _shift, \
.width = _width, \ .width = _width, \
.flags = _divider_flags, \ .flags = _divider_flags, \
.table = _table, \
.lock = _lock, \ .lock = _lock, \
}; \ }; \
DEFINE_CLK(_name, clk_divider_ops, _flags, \ DEFINE_CLK(_name, clk_divider_ops, _flags, \
_name##_parent_names, _name##_parents); _name##_parent_names, _name##_parents);
#define DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \
_flags, _reg, _shift, _width, \
_divider_flags, _lock) \
_DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \
_flags, _reg, _shift, _width, \
_divider_flags, NULL, _lock)
#define DEFINE_CLK_DIVIDER_TABLE(_name, _parent_name, \
_parent_ptr, _flags, _reg, \
_shift, _width, _divider_flags, \
_table, _lock) \
_DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \
_flags, _reg, _shift, _width, \
_divider_flags, _table, _lock) \
#define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags, \ #define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags, \
_reg, _shift, _width, \ _reg, _shift, _width, \
_mux_flags, _lock) \ _mux_flags, _lock) \
......
...@@ -203,6 +203,11 @@ struct clk *clk_register_gate(struct device *dev, const char *name, ...@@ -203,6 +203,11 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
void __iomem *reg, u8 bit_idx, void __iomem *reg, u8 bit_idx,
u8 clk_gate_flags, spinlock_t *lock); u8 clk_gate_flags, spinlock_t *lock);
struct clk_div_table {
unsigned int val;
unsigned int div;
};
/** /**
* struct clk_divider - adjustable divider clock * struct clk_divider - adjustable divider clock
* *
...@@ -210,6 +215,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name, ...@@ -210,6 +215,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
* @reg: register containing the divider * @reg: register containing the divider
* @shift: shift to the divider bit field * @shift: shift to the divider bit field
* @width: width of the divider bit field * @width: width of the divider bit field
* @table: array of value/divider pairs, last entry should have div = 0
* @lock: register lock * @lock: register lock
* *
* Clock with an adjustable divider affecting its output frequency. Implements * Clock with an adjustable divider affecting its output frequency. Implements
...@@ -229,6 +235,7 @@ struct clk_divider { ...@@ -229,6 +235,7 @@ struct clk_divider {
u8 shift; u8 shift;
u8 width; u8 width;
u8 flags; u8 flags;
const struct clk_div_table *table;
spinlock_t *lock; spinlock_t *lock;
}; };
...@@ -240,6 +247,11 @@ struct clk *clk_register_divider(struct device *dev, const char *name, ...@@ -240,6 +247,11 @@ struct clk *clk_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags, const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width, void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, spinlock_t *lock); u8 clk_divider_flags, spinlock_t *lock);
struct clk *clk_register_divider_table(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, const struct clk_div_table *table,
spinlock_t *lock);
/** /**
* struct clk_mux - multiplexer clock * struct clk_mux - multiplexer clock
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册