0001
0002
0003
0004
0005
0006
0007 #include <linux/clk-provider.h>
0008 #include <linux/container_of.h>
0009 #include <linux/err.h>
0010 #include <linux/mfd/syscon.h>
0011 #include <linux/module.h>
0012 #include <linux/regmap.h>
0013 #include <linux/slab.h>
0014
0015 #include "clk-mtk.h"
0016 #include "clk-cpumux.h"
0017
0018 struct mtk_clk_cpumux {
0019 struct clk_hw hw;
0020 struct regmap *regmap;
0021 u32 reg;
0022 u32 mask;
0023 u8 shift;
0024 };
0025
0026 static inline struct mtk_clk_cpumux *to_mtk_clk_cpumux(struct clk_hw *_hw)
0027 {
0028 return container_of(_hw, struct mtk_clk_cpumux, hw);
0029 }
0030
0031 static u8 clk_cpumux_get_parent(struct clk_hw *hw)
0032 {
0033 struct mtk_clk_cpumux *mux = to_mtk_clk_cpumux(hw);
0034 unsigned int val;
0035
0036 regmap_read(mux->regmap, mux->reg, &val);
0037
0038 val >>= mux->shift;
0039 val &= mux->mask;
0040
0041 return val;
0042 }
0043
0044 static int clk_cpumux_set_parent(struct clk_hw *hw, u8 index)
0045 {
0046 struct mtk_clk_cpumux *mux = to_mtk_clk_cpumux(hw);
0047 u32 mask, val;
0048
0049 val = index << mux->shift;
0050 mask = mux->mask << mux->shift;
0051
0052 return regmap_update_bits(mux->regmap, mux->reg, mask, val);
0053 }
0054
0055 static const struct clk_ops clk_cpumux_ops = {
0056 .get_parent = clk_cpumux_get_parent,
0057 .set_parent = clk_cpumux_set_parent,
0058 };
0059
0060 static struct clk_hw *
0061 mtk_clk_register_cpumux(const struct mtk_composite *mux,
0062 struct regmap *regmap)
0063 {
0064 struct mtk_clk_cpumux *cpumux;
0065 int ret;
0066 struct clk_init_data init;
0067
0068 cpumux = kzalloc(sizeof(*cpumux), GFP_KERNEL);
0069 if (!cpumux)
0070 return ERR_PTR(-ENOMEM);
0071
0072 init.name = mux->name;
0073 init.ops = &clk_cpumux_ops;
0074 init.parent_names = mux->parent_names;
0075 init.num_parents = mux->num_parents;
0076 init.flags = mux->flags;
0077
0078 cpumux->reg = mux->mux_reg;
0079 cpumux->shift = mux->mux_shift;
0080 cpumux->mask = BIT(mux->mux_width) - 1;
0081 cpumux->regmap = regmap;
0082 cpumux->hw.init = &init;
0083
0084 ret = clk_hw_register(NULL, &cpumux->hw);
0085 if (ret) {
0086 kfree(cpumux);
0087 return ERR_PTR(ret);
0088 }
0089
0090 return &cpumux->hw;
0091 }
0092
0093 static void mtk_clk_unregister_cpumux(struct clk_hw *hw)
0094 {
0095 struct mtk_clk_cpumux *cpumux;
0096 if (!hw)
0097 return;
0098
0099 cpumux = to_mtk_clk_cpumux(hw);
0100
0101 clk_hw_unregister(hw);
0102 kfree(cpumux);
0103 }
0104
0105 int mtk_clk_register_cpumuxes(struct device_node *node,
0106 const struct mtk_composite *clks, int num,
0107 struct clk_hw_onecell_data *clk_data)
0108 {
0109 int i;
0110 struct clk_hw *hw;
0111 struct regmap *regmap;
0112
0113 regmap = device_node_to_regmap(node);
0114 if (IS_ERR(regmap)) {
0115 pr_err("Cannot find regmap for %pOF: %pe\n", node, regmap);
0116 return PTR_ERR(regmap);
0117 }
0118
0119 for (i = 0; i < num; i++) {
0120 const struct mtk_composite *mux = &clks[i];
0121
0122 if (!IS_ERR_OR_NULL(clk_data->hws[mux->id])) {
0123 pr_warn("%pOF: Trying to register duplicate clock ID: %d\n",
0124 node, mux->id);
0125 continue;
0126 }
0127
0128 hw = mtk_clk_register_cpumux(mux, regmap);
0129 if (IS_ERR(hw)) {
0130 pr_err("Failed to register clk %s: %pe\n", mux->name,
0131 hw);
0132 goto err;
0133 }
0134
0135 clk_data->hws[mux->id] = hw;
0136 }
0137
0138 return 0;
0139
0140 err:
0141 while (--i >= 0) {
0142 const struct mtk_composite *mux = &clks[i];
0143
0144 if (IS_ERR_OR_NULL(clk_data->hws[mux->id]))
0145 continue;
0146
0147 mtk_clk_unregister_cpumux(clk_data->hws[mux->id]);
0148 clk_data->hws[mux->id] = ERR_PTR(-ENOENT);
0149 }
0150
0151 return PTR_ERR(hw);
0152 }
0153
0154 void mtk_clk_unregister_cpumuxes(const struct mtk_composite *clks, int num,
0155 struct clk_hw_onecell_data *clk_data)
0156 {
0157 int i;
0158
0159 for (i = num; i > 0; i--) {
0160 const struct mtk_composite *mux = &clks[i - 1];
0161
0162 if (IS_ERR_OR_NULL(clk_data->hws[mux->id]))
0163 continue;
0164
0165 mtk_clk_unregister_cpumux(clk_data->hws[mux->id]);
0166 clk_data->hws[mux->id] = ERR_PTR(-ENOENT);
0167 }
0168 }
0169
0170 MODULE_LICENSE("GPL");