--- zzzz-none-000/linux-3.10.107/drivers/clk/clk-mux.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/clk/clk-mux.c 2021-02-04 17:41:59.000000000 +0000 @@ -10,7 +10,6 @@ * Simple multiplexer clock implementation */ -#include #include #include #include @@ -29,35 +28,24 @@ #define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw) -static u8 clk_mux_get_parent(struct clk_hw *hw) +unsigned int clk_mux_get_parent(struct clk_hw *hw, unsigned int val, + unsigned int *table, unsigned long flags) { - struct clk_mux *mux = to_clk_mux(hw); - int num_parents = __clk_get_num_parents(hw->clk); - u32 val; - - /* - * FIXME need a mux-specific flag to determine if val is bitwise or numeric - * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1 - * to 0x7 (index starts at one) - * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so - * val = 0x4 really means "bit 2, index starts at bit 0" - */ - val = readl(mux->reg) >> mux->shift; - val &= mux->mask; + int num_parents = clk_hw_get_num_parents(hw); - if (mux->table) { + if (table) { int i; for (i = 0; i < num_parents; i++) - if (mux->table[i] == val) + if (table[i] == val) return i; return -EINVAL; } - if (val && (mux->flags & CLK_MUX_INDEX_BIT)) + if (val && (flags & CLK_MUX_INDEX_BIT)) val = ffs(val) - 1; - if (val && (mux->flags & CLK_MUX_INDEX_ONE)) + if (val && (flags & CLK_MUX_INDEX_ONE)) val--; if (val >= num_parents) @@ -65,6 +53,44 @@ return val; } +EXPORT_SYMBOL_GPL(clk_mux_get_parent); + +static u8 _clk_mux_get_parent(struct clk_hw *hw) + { + struct clk_mux *mux = to_clk_mux(hw); + u32 val; + + /* + * FIXME need a mux-specific flag to determine if val is bitwise or numeric + * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1 + * to 0x7 (index starts at one) + * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so + * val = 0x4 really means "bit 2, index starts at bit 0" ++ */ + val = clk_readl(mux->reg) >> mux->shift; + val &= mux->mask; + + return clk_mux_get_parent(hw, val, mux->table, mux->flags); +} + +unsigned int clk_mux_reindex(u8 index, unsigned int *table, + unsigned long flags) +{ + unsigned int val = index; + + if (table) { + val = table[val]; + } else { + if (flags & CLK_MUX_INDEX_BIT) + val = 1 << index; + + if (flags & CLK_MUX_INDEX_ONE) + val++; + } + + return val; +} +EXPORT_SYMBOL_GPL(clk_mux_reindex); static int clk_mux_set_parent(struct clk_hw *hw, u8 index) { @@ -72,45 +98,60 @@ u32 val; unsigned long flags = 0; - if (mux->table) - index = mux->table[index]; - - else { - if (mux->flags & CLK_MUX_INDEX_BIT) - index = (1 << ffs(index)); - - if (mux->flags & CLK_MUX_INDEX_ONE) - index++; - } + index = clk_mux_reindex(index, mux->table, mux->flags); if (mux->lock) spin_lock_irqsave(mux->lock, flags); + else + __acquire(mux->lock); - val = readl(mux->reg); - val &= ~(mux->mask << mux->shift); + if (mux->flags & CLK_MUX_HIWORD_MASK) { + val = mux->mask << (mux->shift + 16); + } else { + val = clk_readl(mux->reg); + val &= ~(mux->mask << mux->shift); + } val |= index << mux->shift; - writel(val, mux->reg); + clk_writel(val, mux->reg); if (mux->lock) spin_unlock_irqrestore(mux->lock, flags); + else + __release(mux->lock); return 0; } const struct clk_ops clk_mux_ops = { - .get_parent = clk_mux_get_parent, + .get_parent = _clk_mux_get_parent, .set_parent = clk_mux_set_parent, + .determine_rate = __clk_mux_determine_rate, }; EXPORT_SYMBOL_GPL(clk_mux_ops); +const struct clk_ops clk_mux_ro_ops = { + .get_parent = _clk_mux_get_parent, +}; +EXPORT_SYMBOL_GPL(clk_mux_ro_ops); + struct clk *clk_register_mux_table(struct device *dev, const char *name, - const char **parent_names, u8 num_parents, unsigned long flags, + const char * const *parent_names, u8 num_parents, + unsigned long flags, void __iomem *reg, u8 shift, u32 mask, - u8 clk_mux_flags, u32 *table, spinlock_t *lock) + u8 clk_mux_flags, unsigned int *table, spinlock_t *lock) { struct clk_mux *mux; struct clk *clk; struct clk_init_data init; + u8 width = 0; + + if (clk_mux_flags & CLK_MUX_HIWORD_MASK) { + width = fls(mask) - ffs(mask) + 1; + if (width + shift > 16) { + pr_err("mux value exceeds LOWORD field\n"); + return ERR_PTR(-EINVAL); + } + } /* allocate the mux */ mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); @@ -120,7 +161,10 @@ } init.name = name; - init.ops = &clk_mux_ops; + if (clk_mux_flags & CLK_MUX_READ_ONLY) + init.ops = &clk_mux_ro_ops; + else + init.ops = &clk_mux_ops; init.flags = flags | CLK_IS_BASIC; init.parent_names = parent_names; init.num_parents = num_parents; @@ -141,9 +185,11 @@ return clk; } +EXPORT_SYMBOL_GPL(clk_register_mux_table); struct clk *clk_register_mux(struct device *dev, const char *name, - const char **parent_names, u8 num_parents, unsigned long flags, + const char * const *parent_names, u8 num_parents, + unsigned long flags, void __iomem *reg, u8 shift, u8 width, u8 clk_mux_flags, spinlock_t *lock) { @@ -153,3 +199,20 @@ flags, reg, shift, mask, clk_mux_flags, NULL, lock); } +EXPORT_SYMBOL_GPL(clk_register_mux); + +void clk_unregister_mux(struct clk *clk) +{ + struct clk_mux *mux; + struct clk_hw *hw; + + hw = __clk_get_hw(clk); + if (!hw) + return; + + mux = to_clk_mux(hw); + + clk_unregister(clk); + kfree(mux); +} +EXPORT_SYMBOL_GPL(clk_unregister_mux);