0001
0002
0003
0004
0005
0006
0007 #include <linux/clk-provider.h>
0008 #include <linux/device.h>
0009 #include <linux/regmap.h>
0010
0011 #include "clk-uniphier.h"
0012
0013 struct uniphier_clk_mux {
0014 struct clk_hw hw;
0015 struct regmap *regmap;
0016 unsigned int reg;
0017 const unsigned int *masks;
0018 const unsigned int *vals;
0019 };
0020
0021 #define to_uniphier_clk_mux(_hw) container_of(_hw, struct uniphier_clk_mux, hw)
0022
0023 static int uniphier_clk_mux_set_parent(struct clk_hw *hw, u8 index)
0024 {
0025 struct uniphier_clk_mux *mux = to_uniphier_clk_mux(hw);
0026
0027 return regmap_write_bits(mux->regmap, mux->reg, mux->masks[index],
0028 mux->vals[index]);
0029 }
0030
0031 static u8 uniphier_clk_mux_get_parent(struct clk_hw *hw)
0032 {
0033 struct uniphier_clk_mux *mux = to_uniphier_clk_mux(hw);
0034 unsigned int num_parents = clk_hw_get_num_parents(hw);
0035 int ret;
0036 unsigned int val;
0037 unsigned int i;
0038
0039 ret = regmap_read(mux->regmap, mux->reg, &val);
0040 if (ret)
0041 return ret;
0042
0043 for (i = 0; i < num_parents; i++)
0044 if ((mux->masks[i] & val) == mux->vals[i])
0045 return i;
0046
0047 return -EINVAL;
0048 }
0049
0050 static const struct clk_ops uniphier_clk_mux_ops = {
0051 .determine_rate = __clk_mux_determine_rate,
0052 .set_parent = uniphier_clk_mux_set_parent,
0053 .get_parent = uniphier_clk_mux_get_parent,
0054 };
0055
0056 struct clk_hw *uniphier_clk_register_mux(struct device *dev,
0057 struct regmap *regmap,
0058 const char *name,
0059 const struct uniphier_clk_mux_data *data)
0060 {
0061 struct uniphier_clk_mux *mux;
0062 struct clk_init_data init;
0063 int ret;
0064
0065 mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
0066 if (!mux)
0067 return ERR_PTR(-ENOMEM);
0068
0069 init.name = name;
0070 init.ops = &uniphier_clk_mux_ops;
0071 init.flags = CLK_SET_RATE_PARENT;
0072 init.parent_names = data->parent_names;
0073 init.num_parents = data->num_parents;
0074
0075 mux->regmap = regmap;
0076 mux->reg = data->reg;
0077 mux->masks = data->masks;
0078 mux->vals = data->vals;
0079 mux->hw.init = &init;
0080
0081 ret = devm_clk_hw_register(dev, &mux->hw);
0082 if (ret)
0083 return ERR_PTR(ret);
0084
0085 return &mux->hw;
0086 }