[PATCH RFC] clk: add table lookup to mux

From: Peter De Schrijver
Date: Wed May 16 2012 - 10:31:44 EST


This patch adds a table lookup mechanism to the mux clk. In Tegra many
peripheral clocks have muxes. In many cases not all possible mux selections
are valid. Hence there is a need to have mapping between parent index and
mux selection value. An alternative approach would be to have a
struct clk_parent which contains the name, clk pointer and index.

Signed-off-by: Peter De Schrijver <pdeschrijver@xxxxxxxxxx>
---
drivers/clk/clk-mux.c | 29 +++++++++++++++++++++++------
include/linux/clk-private.h | 3 ++-
include/linux/clk-provider.h | 3 ++-
3 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index fd36a8e..00547d4 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -32,6 +32,7 @@
static u8 clk_mux_get_parent(struct clk_hw *hw)
{
struct clk_mux *mux = to_clk_mux(hw);
+ int num_parents = __clk_get_num_parents(hw->clk);
u32 val;

/*
@@ -44,13 +45,23 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
val = readl(mux->reg) >> mux->shift;
val &= (1 << mux->width) - 1;

+ if (mux->table) {
+ int i;
+
+ for (i = 0; i < num_parents; i++)
+ if (mux->table[i] == val)
+ return i;
+ if (i == num_parents)
+ return -EINVAL;
+ }
+
if (val && (mux->flags & CLK_MUX_INDEX_BIT))
val = ffs(val) - 1;

if (val && (mux->flags & CLK_MUX_INDEX_ONE))
val--;

- if (val >= __clk_get_num_parents(hw->clk))
+ if (val >= num_parents)
return -EINVAL;

return val;
@@ -62,11 +73,16 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
u32 val;
unsigned long flags = 0;

- if (mux->flags & CLK_MUX_INDEX_BIT)
- index = (1 << ffs(index));
+ if (mux->table)
+ index = mux->table[index];

- if (mux->flags & CLK_MUX_INDEX_ONE)
- index++;
+ else {
+ if (mux->flags & CLK_MUX_INDEX_BIT)
+ index = (1 << ffs(index));
+
+ if (mux->flags & CLK_MUX_INDEX_ONE)
+ index++;
+ }

if (mux->lock)
spin_lock_irqsave(mux->lock, flags);
@@ -91,7 +107,7 @@ EXPORT_SYMBOL_GPL(clk_mux_ops);
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)
+ u8 clk_mux_flags, u32 *table, spinlock_t *lock)
{
struct clk_mux *mux;
struct clk *clk;
@@ -116,6 +132,7 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
mux->width = width;
mux->flags = clk_mux_flags;
mux->lock = lock;
+ mux->table = table;
mux->hw.init = &init;

clk = clk_register(dev, &mux->hw);
diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h
index eb3f84b..e9d2327 100644
--- a/include/linux/clk-private.h
+++ b/include/linux/clk-private.h
@@ -128,12 +128,13 @@ struct clk {

#define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags, \
_reg, _shift, _width, \
- _mux_flags, _lock) \
+ _mux_flags, _table, _lock) \
static struct clk _name; \
static struct clk_mux _name##_hw = { \
.hw = { \
.clk = &_name, \
}, \
+ .table = _table, \
.reg = _reg, \
.shift = _shift, \
.width = _width, \
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index c1c23b9..6803fb4 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -261,6 +261,7 @@ struct clk *clk_register_divider(struct device *dev, const char *name,
struct clk_mux {
struct clk_hw hw;
void __iomem *reg;
+ u32 *table;
u8 shift;
u8 width;
u8 flags;
@@ -274,7 +275,7 @@ extern const struct clk_ops clk_mux_ops;
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);
+ u8 clk_mux_flags, u32 *table, spinlock_t *lock);

/**
* struct clk_fixed_factor - fixed multiplier and divider clock
--
1.7.7.rc0.72.g4b5ea.dirty

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/