0001
0002
0003
0004
0005
0006 #include <linux/bits.h>
0007 #include <linux/clk-provider.h>
0008 #include <linux/err.h>
0009 #include <linux/io.h>
0010 #include <linux/slab.h>
0011 #include "clk.h"
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022 struct clk_fixup_mux {
0023 struct clk_mux mux;
0024 const struct clk_ops *ops;
0025 void (*fixup)(u32 *val);
0026 };
0027
0028 static inline struct clk_fixup_mux *to_clk_fixup_mux(struct clk_hw *hw)
0029 {
0030 struct clk_mux *mux = to_clk_mux(hw);
0031
0032 return container_of(mux, struct clk_fixup_mux, mux);
0033 }
0034
0035 static u8 clk_fixup_mux_get_parent(struct clk_hw *hw)
0036 {
0037 struct clk_fixup_mux *fixup_mux = to_clk_fixup_mux(hw);
0038
0039 return fixup_mux->ops->get_parent(&fixup_mux->mux.hw);
0040 }
0041
0042 static int clk_fixup_mux_set_parent(struct clk_hw *hw, u8 index)
0043 {
0044 struct clk_fixup_mux *fixup_mux = to_clk_fixup_mux(hw);
0045 struct clk_mux *mux = to_clk_mux(hw);
0046 unsigned long flags;
0047 u32 val;
0048
0049 spin_lock_irqsave(mux->lock, flags);
0050
0051 val = readl(mux->reg);
0052 val &= ~(mux->mask << mux->shift);
0053 val |= index << mux->shift;
0054 fixup_mux->fixup(&val);
0055 writel(val, mux->reg);
0056
0057 spin_unlock_irqrestore(mux->lock, flags);
0058
0059 return 0;
0060 }
0061
0062 static const struct clk_ops clk_fixup_mux_ops = {
0063 .get_parent = clk_fixup_mux_get_parent,
0064 .set_parent = clk_fixup_mux_set_parent,
0065 };
0066
0067 struct clk_hw *imx_clk_hw_fixup_mux(const char *name, void __iomem *reg,
0068 u8 shift, u8 width, const char * const *parents,
0069 int num_parents, void (*fixup)(u32 *val))
0070 {
0071 struct clk_fixup_mux *fixup_mux;
0072 struct clk_hw *hw;
0073 struct clk_init_data init;
0074 int ret;
0075
0076 if (!fixup)
0077 return ERR_PTR(-EINVAL);
0078
0079 fixup_mux = kzalloc(sizeof(*fixup_mux), GFP_KERNEL);
0080 if (!fixup_mux)
0081 return ERR_PTR(-ENOMEM);
0082
0083 init.name = name;
0084 init.ops = &clk_fixup_mux_ops;
0085 init.parent_names = parents;
0086 init.num_parents = num_parents;
0087 init.flags = 0;
0088
0089 fixup_mux->mux.reg = reg;
0090 fixup_mux->mux.shift = shift;
0091 fixup_mux->mux.mask = BIT(width) - 1;
0092 fixup_mux->mux.lock = &imx_ccm_lock;
0093 fixup_mux->mux.hw.init = &init;
0094 fixup_mux->ops = &clk_mux_ops;
0095 fixup_mux->fixup = fixup;
0096
0097 hw = &fixup_mux->mux.hw;
0098
0099 ret = clk_hw_register(NULL, hw);
0100 if (ret) {
0101 kfree(fixup_mux);
0102 return ERR_PTR(ret);
0103 }
0104
0105 return hw;
0106 }