Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 316604
b: refs/heads/master
c: 357c3f0
h: refs/heads/master
v: v3
  • Loading branch information
Rajendra Nayak authored and Mike Turquette committed Jul 11, 2012
1 parent 10c7a41 commit 8e9beba
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 19 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 6d9252bd9a4bb1dadc1f199fd276e3464a251085
refs/heads/master: 357c3f0a6c7613f7230fcaf1eb16190ed2a4b0af
125 changes: 109 additions & 16 deletions trunk/drivers/clk/clk-divider.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,30 +32,69 @@
#define div_mask(d) ((1 << (d->width)) - 1)
#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)
{
if (divider->flags & CLK_DIVIDER_ONE_BASED)
return div_mask(divider);
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
return 1 << div_mask(divider);
if (divider->table)
return _get_table_maxdiv(divider->table);
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)
{
if (divider->flags & CLK_DIVIDER_ONE_BASED)
return val;
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
return 1 << val;
if (divider->table)
return _get_table_div(divider->table, val);
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)
{
if (divider->flags & CLK_DIVIDER_ONE_BASED)
return div;
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
return __ffs(div);
if (divider->table)
return _get_table_val(divider->table, div);
return div - 1;
}

Expand Down Expand Up @@ -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)

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,
unsigned long *best_parent_rate)
{
Expand Down Expand Up @@ -111,8 +170,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
maxdiv = min(ULONG_MAX / rate, maxdiv);

for (i = 1; i <= maxdiv; i++) {
if ((divider->flags & CLK_DIVIDER_POWER_OF_TWO)
&& (!is_power_of_two(i)))
if (!_is_valid_div(divider, i))
continue;
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
MULT_ROUND_UP(rate, i));
Expand Down Expand Up @@ -176,22 +234,11 @@ const struct clk_ops clk_divider_ops = {
};
EXPORT_SYMBOL_GPL(clk_divider_ops);

/**
* 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,
static struct 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)
u8 clk_divider_flags, const struct clk_div_table *table,
spinlock_t *lock)
{
struct clk_divider *div;
struct clk *clk;
Expand All @@ -217,6 +264,7 @@ struct clk *clk_register_divider(struct device *dev, const char *name,
div->flags = clk_divider_flags;
div->lock = lock;
div->hw.init = &init;
div->table = table;

/* register the clock */
clk = clk_register(dev, &div->hw);
Expand All @@ -226,3 +274,48 @@ struct clk *clk_register_divider(struct device *dev, const char *name,

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);
}
20 changes: 18 additions & 2 deletions trunk/include/linux/clk-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ struct clk {
DEFINE_CLK(_name, clk_gate_ops, _flags, \
_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, \
_divider_flags, _lock) \
_divider_flags, _table, _lock) \
static struct clk _name; \
static const char *_name##_parent_names[] = { \
_parent_name, \
Expand All @@ -121,11 +121,27 @@ struct clk {
.shift = _shift, \
.width = _width, \
.flags = _divider_flags, \
.table = _table, \
.lock = _lock, \
}; \
DEFINE_CLK(_name, clk_divider_ops, _flags, \
_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, \
_reg, _shift, _width, \
_mux_flags, _lock) \
Expand Down
12 changes: 12 additions & 0 deletions trunk/include/linux/clk-provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,13 +203,19 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
void __iomem *reg, u8 bit_idx,
u8 clk_gate_flags, spinlock_t *lock);

struct clk_div_table {
unsigned int val;
unsigned int div;
};

/**
* struct clk_divider - adjustable divider clock
*
* @hw: handle between common and hardware-specific interfaces
* @reg: register containing the divider
* @shift: shift to 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
*
* Clock with an adjustable divider affecting its output frequency. Implements
Expand All @@ -229,6 +235,7 @@ struct clk_divider {
u8 shift;
u8 width;
u8 flags;
const struct clk_div_table *table;
spinlock_t *lock;
};

Expand All @@ -240,6 +247,11 @@ 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);
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
Expand Down

0 comments on commit 8e9beba

Please sign in to comment.