Commit ce4f3313 authored by Peter De Schrijver's avatar Peter De Schrijver Committed by Mike Turquette

clk: add table lookup to mux

Add a table lookup feature to the mux clock. Also allow arbitrary masks
instead of the width. This will be used by some clocks on Tegra114. Also
adapt the tegra periph clk because it uses struct clk_mux directly.
Signed-off-by: default avatarPeter De Schrijver <pdeschrijver@nvidia.com>
Tested-by: default avatarStephen Warren <swarren@nvidia.com>
Signed-off-by: default avatarMike Turquette <mturquette@linaro.org>
parent 5fda6858
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
static u8 clk_mux_get_parent(struct clk_hw *hw) static u8 clk_mux_get_parent(struct clk_hw *hw)
{ {
struct clk_mux *mux = to_clk_mux(hw); struct clk_mux *mux = to_clk_mux(hw);
int num_parents = __clk_get_num_parents(hw->clk);
u32 val; u32 val;
/* /*
...@@ -42,7 +43,16 @@ static u8 clk_mux_get_parent(struct clk_hw *hw) ...@@ -42,7 +43,16 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
* val = 0x4 really means "bit 2, index starts at bit 0" * val = 0x4 really means "bit 2, index starts at bit 0"
*/ */
val = readl(mux->reg) >> mux->shift; val = readl(mux->reg) >> mux->shift;
val &= (1 << mux->width) - 1; val &= mux->mask;
if (mux->table) {
int i;
for (i = 0; i < num_parents; i++)
if (mux->table[i] == val)
return i;
return -EINVAL;
}
if (val && (mux->flags & CLK_MUX_INDEX_BIT)) if (val && (mux->flags & CLK_MUX_INDEX_BIT))
val = ffs(val) - 1; val = ffs(val) - 1;
...@@ -50,7 +60,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw) ...@@ -50,7 +60,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
if (val && (mux->flags & CLK_MUX_INDEX_ONE)) if (val && (mux->flags & CLK_MUX_INDEX_ONE))
val--; val--;
if (val >= __clk_get_num_parents(hw->clk)) if (val >= num_parents)
return -EINVAL; return -EINVAL;
return val; return val;
...@@ -62,17 +72,22 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index) ...@@ -62,17 +72,22 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
u32 val; u32 val;
unsigned long flags = 0; unsigned long flags = 0;
if (mux->flags & CLK_MUX_INDEX_BIT) if (mux->table)
index = (1 << ffs(index)); index = mux->table[index];
if (mux->flags & CLK_MUX_INDEX_ONE) else {
index++; if (mux->flags & CLK_MUX_INDEX_BIT)
index = (1 << ffs(index));
if (mux->flags & CLK_MUX_INDEX_ONE)
index++;
}
if (mux->lock) if (mux->lock)
spin_lock_irqsave(mux->lock, flags); spin_lock_irqsave(mux->lock, flags);
val = readl(mux->reg); val = readl(mux->reg);
val &= ~(((1 << mux->width) - 1) << mux->shift); val &= ~(mux->mask << mux->shift);
val |= index << mux->shift; val |= index << mux->shift;
writel(val, mux->reg); writel(val, mux->reg);
...@@ -88,10 +103,10 @@ const struct clk_ops clk_mux_ops = { ...@@ -88,10 +103,10 @@ const struct clk_ops clk_mux_ops = {
}; };
EXPORT_SYMBOL_GPL(clk_mux_ops); EXPORT_SYMBOL_GPL(clk_mux_ops);
struct clk *clk_register_mux(struct device *dev, const char *name, struct clk *clk_register_mux_table(struct device *dev, const char *name,
const char **parent_names, u8 num_parents, unsigned long flags, const char **parent_names, u8 num_parents, unsigned long flags,
void __iomem *reg, u8 shift, u8 width, void __iomem *reg, u8 shift, u32 mask,
u8 clk_mux_flags, spinlock_t *lock) u8 clk_mux_flags, u32 *table, spinlock_t *lock)
{ {
struct clk_mux *mux; struct clk_mux *mux;
struct clk *clk; struct clk *clk;
...@@ -113,9 +128,10 @@ struct clk *clk_register_mux(struct device *dev, const char *name, ...@@ -113,9 +128,10 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
/* struct clk_mux assignments */ /* struct clk_mux assignments */
mux->reg = reg; mux->reg = reg;
mux->shift = shift; mux->shift = shift;
mux->width = width; mux->mask = mask;
mux->flags = clk_mux_flags; mux->flags = clk_mux_flags;
mux->lock = lock; mux->lock = lock;
mux->table = table;
mux->hw.init = &init; mux->hw.init = &init;
clk = clk_register(dev, &mux->hw); clk = clk_register(dev, &mux->hw);
...@@ -125,3 +141,15 @@ struct clk *clk_register_mux(struct device *dev, const char *name, ...@@ -125,3 +141,15 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
return clk; return clk;
} }
struct clk *clk_register_mux(struct device *dev, const char *name,
const char **parent_names, u8 num_parents, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_mux_flags, spinlock_t *lock)
{
u32 mask = BIT(width) - 1;
return clk_register_mux_table(dev, name, parent_names, num_parents,
flags, reg, shift, mask, clk_mux_flags,
NULL, lock);
}
...@@ -355,15 +355,16 @@ struct clk *tegra_clk_register_periph_nodiv(const char *name, ...@@ -355,15 +355,16 @@ struct clk *tegra_clk_register_periph_nodiv(const char *name,
struct tegra_clk_periph *periph, void __iomem *clk_base, struct tegra_clk_periph *periph, void __iomem *clk_base,
u32 offset); u32 offset);
#define TEGRA_CLK_PERIPH(_mux_shift, _mux_width, _mux_flags, \ #define TEGRA_CLK_PERIPH(_mux_shift, _mux_mask, _mux_flags, \
_div_shift, _div_width, _div_frac_width, \ _div_shift, _div_width, _div_frac_width, \
_div_flags, _clk_num, _enb_refcnt, _regs, \ _div_flags, _clk_num, _enb_refcnt, _regs, \
_gate_flags) \ _gate_flags, _table) \
{ \ { \
.mux = { \ .mux = { \
.flags = _mux_flags, \ .flags = _mux_flags, \
.shift = _mux_shift, \ .shift = _mux_shift, \
.width = _mux_width, \ .mask = _mux_mask, \
.table = _table, \
}, \ }, \
.divider = { \ .divider = { \
.flags = _div_flags, \ .flags = _div_flags, \
...@@ -393,26 +394,36 @@ struct tegra_periph_init_data { ...@@ -393,26 +394,36 @@ struct tegra_periph_init_data {
const char *dev_id; const char *dev_id;
}; };
#define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset, \ #define TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parent_names, _offset,\
_mux_shift, _mux_width, _mux_flags, _div_shift, \ _mux_shift, _mux_mask, _mux_flags, _div_shift, \
_div_width, _div_frac_width, _div_flags, _regs, \ _div_width, _div_frac_width, _div_flags, _regs, \
_clk_num, _enb_refcnt, _gate_flags, _clk_id) \ _clk_num, _enb_refcnt, _gate_flags, _clk_id, _table) \
{ \ { \
.name = _name, \ .name = _name, \
.clk_id = _clk_id, \ .clk_id = _clk_id, \
.parent_names = _parent_names, \ .parent_names = _parent_names, \
.num_parents = ARRAY_SIZE(_parent_names), \ .num_parents = ARRAY_SIZE(_parent_names), \
.periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_width, \ .periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_mask, \
_mux_flags, _div_shift, \ _mux_flags, _div_shift, \
_div_width, _div_frac_width, \ _div_width, _div_frac_width, \
_div_flags, _clk_num, \ _div_flags, _clk_num, \
_enb_refcnt, _regs, \ _enb_refcnt, _regs, \
_gate_flags), \ _gate_flags, _table), \
.offset = _offset, \ .offset = _offset, \
.con_id = _con_id, \ .con_id = _con_id, \
.dev_id = _dev_id, \ .dev_id = _dev_id, \
} }
#define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset,\
_mux_shift, _mux_width, _mux_flags, _div_shift, \
_div_width, _div_frac_width, _div_flags, _regs, \
_clk_num, _enb_refcnt, _gate_flags, _clk_id) \
TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parent_names, _offset,\
_mux_shift, BIT(_mux_width) - 1, _mux_flags, \
_div_shift, _div_width, _div_frac_width, _div_flags, \
_regs, _clk_num, _enb_refcnt, _gate_flags, _clk_id,\
NULL)
/** /**
* struct clk_super_mux - super clock * struct clk_super_mux - super clock
* *
......
...@@ -152,7 +152,7 @@ struct clk { ...@@ -152,7 +152,7 @@ struct clk {
}, \ }, \
.reg = _reg, \ .reg = _reg, \
.shift = _shift, \ .shift = _shift, \
.width = _width, \ .mask = BIT(_width) - 1, \
.flags = _mux_flags, \ .flags = _mux_flags, \
.lock = _lock, \ .lock = _lock, \
}; \ }; \
......
...@@ -297,8 +297,9 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name, ...@@ -297,8 +297,9 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
struct clk_mux { struct clk_mux {
struct clk_hw hw; struct clk_hw hw;
void __iomem *reg; void __iomem *reg;
u32 *table;
u32 mask;
u8 shift; u8 shift;
u8 width;
u8 flags; u8 flags;
spinlock_t *lock; spinlock_t *lock;
}; };
...@@ -307,11 +308,17 @@ struct clk_mux { ...@@ -307,11 +308,17 @@ struct clk_mux {
#define CLK_MUX_INDEX_BIT BIT(1) #define CLK_MUX_INDEX_BIT BIT(1)
extern const struct clk_ops clk_mux_ops; extern const struct clk_ops clk_mux_ops;
struct clk *clk_register_mux(struct device *dev, const char *name, struct clk *clk_register_mux(struct device *dev, const char *name,
const char **parent_names, u8 num_parents, unsigned long flags, const char **parent_names, u8 num_parents, unsigned long flags,
void __iomem *reg, u8 shift, u8 width, void __iomem *reg, u8 shift, u8 width,
u8 clk_mux_flags, spinlock_t *lock); u8 clk_mux_flags, spinlock_t *lock);
struct clk *clk_register_mux_table(struct device *dev, const char *name,
const char **parent_names, u8 num_parents, unsigned long flags,
void __iomem *reg, u8 shift, u32 mask,
u8 clk_mux_flags, u32 *table, spinlock_t *lock);
/** /**
* struct clk_fixed_factor - fixed multiplier and divider clock * struct clk_fixed_factor - fixed multiplier and divider clock
* *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment