0001
0002
0003
0004
0005
0006
0007 #include <linux/clk-provider.h>
0008 #include <linux/compiler_types.h>
0009 #include <linux/container_of.h>
0010 #include <linux/err.h>
0011 #include <linux/mfd/syscon.h>
0012 #include <linux/module.h>
0013 #include <linux/regmap.h>
0014 #include <linux/spinlock.h>
0015 #include <linux/slab.h>
0016
0017 #include "clk-mux.h"
0018
0019 struct mtk_clk_mux {
0020 struct clk_hw hw;
0021 struct regmap *regmap;
0022 const struct mtk_mux *data;
0023 spinlock_t *lock;
0024 bool reparent;
0025 };
0026
0027 static inline struct mtk_clk_mux *to_mtk_clk_mux(struct clk_hw *hw)
0028 {
0029 return container_of(hw, struct mtk_clk_mux, hw);
0030 }
0031
0032 static int mtk_clk_mux_enable_setclr(struct clk_hw *hw)
0033 {
0034 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
0035 unsigned long flags = 0;
0036
0037 if (mux->lock)
0038 spin_lock_irqsave(mux->lock, flags);
0039 else
0040 __acquire(mux->lock);
0041
0042 regmap_write(mux->regmap, mux->data->clr_ofs,
0043 BIT(mux->data->gate_shift));
0044
0045
0046
0047
0048
0049
0050 if (mux->reparent && mux->data->upd_shift >= 0) {
0051 regmap_write(mux->regmap, mux->data->upd_ofs,
0052 BIT(mux->data->upd_shift));
0053 mux->reparent = false;
0054 }
0055
0056 if (mux->lock)
0057 spin_unlock_irqrestore(mux->lock, flags);
0058 else
0059 __release(mux->lock);
0060
0061 return 0;
0062 }
0063
0064 static void mtk_clk_mux_disable_setclr(struct clk_hw *hw)
0065 {
0066 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
0067
0068 regmap_write(mux->regmap, mux->data->set_ofs,
0069 BIT(mux->data->gate_shift));
0070 }
0071
0072 static int mtk_clk_mux_is_enabled(struct clk_hw *hw)
0073 {
0074 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
0075 u32 val;
0076
0077 regmap_read(mux->regmap, mux->data->mux_ofs, &val);
0078
0079 return (val & BIT(mux->data->gate_shift)) == 0;
0080 }
0081
0082 static u8 mtk_clk_mux_get_parent(struct clk_hw *hw)
0083 {
0084 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
0085 u32 mask = GENMASK(mux->data->mux_width - 1, 0);
0086 u32 val;
0087
0088 regmap_read(mux->regmap, mux->data->mux_ofs, &val);
0089 val = (val >> mux->data->mux_shift) & mask;
0090
0091 return val;
0092 }
0093
0094 static int mtk_clk_mux_set_parent_setclr_lock(struct clk_hw *hw, u8 index)
0095 {
0096 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
0097 u32 mask = GENMASK(mux->data->mux_width - 1, 0);
0098 u32 val, orig;
0099 unsigned long flags = 0;
0100
0101 if (mux->lock)
0102 spin_lock_irqsave(mux->lock, flags);
0103 else
0104 __acquire(mux->lock);
0105
0106 regmap_read(mux->regmap, mux->data->mux_ofs, &orig);
0107 val = (orig & ~(mask << mux->data->mux_shift))
0108 | (index << mux->data->mux_shift);
0109
0110 if (val != orig) {
0111 regmap_write(mux->regmap, mux->data->clr_ofs,
0112 mask << mux->data->mux_shift);
0113 regmap_write(mux->regmap, mux->data->set_ofs,
0114 index << mux->data->mux_shift);
0115
0116 if (mux->data->upd_shift >= 0) {
0117 regmap_write(mux->regmap, mux->data->upd_ofs,
0118 BIT(mux->data->upd_shift));
0119 mux->reparent = true;
0120 }
0121 }
0122
0123 if (mux->lock)
0124 spin_unlock_irqrestore(mux->lock, flags);
0125 else
0126 __release(mux->lock);
0127
0128 return 0;
0129 }
0130
0131 const struct clk_ops mtk_mux_clr_set_upd_ops = {
0132 .get_parent = mtk_clk_mux_get_parent,
0133 .set_parent = mtk_clk_mux_set_parent_setclr_lock,
0134 };
0135 EXPORT_SYMBOL_GPL(mtk_mux_clr_set_upd_ops);
0136
0137 const struct clk_ops mtk_mux_gate_clr_set_upd_ops = {
0138 .enable = mtk_clk_mux_enable_setclr,
0139 .disable = mtk_clk_mux_disable_setclr,
0140 .is_enabled = mtk_clk_mux_is_enabled,
0141 .get_parent = mtk_clk_mux_get_parent,
0142 .set_parent = mtk_clk_mux_set_parent_setclr_lock,
0143 };
0144 EXPORT_SYMBOL_GPL(mtk_mux_gate_clr_set_upd_ops);
0145
0146 static struct clk_hw *mtk_clk_register_mux(const struct mtk_mux *mux,
0147 struct regmap *regmap,
0148 spinlock_t *lock)
0149 {
0150 struct mtk_clk_mux *clk_mux;
0151 struct clk_init_data init = {};
0152 int ret;
0153
0154 clk_mux = kzalloc(sizeof(*clk_mux), GFP_KERNEL);
0155 if (!clk_mux)
0156 return ERR_PTR(-ENOMEM);
0157
0158 init.name = mux->name;
0159 init.flags = mux->flags | CLK_SET_RATE_PARENT;
0160 init.parent_names = mux->parent_names;
0161 init.num_parents = mux->num_parents;
0162 init.ops = mux->ops;
0163
0164 clk_mux->regmap = regmap;
0165 clk_mux->data = mux;
0166 clk_mux->lock = lock;
0167 clk_mux->hw.init = &init;
0168
0169 ret = clk_hw_register(NULL, &clk_mux->hw);
0170 if (ret) {
0171 kfree(clk_mux);
0172 return ERR_PTR(ret);
0173 }
0174
0175 return &clk_mux->hw;
0176 }
0177
0178 static void mtk_clk_unregister_mux(struct clk_hw *hw)
0179 {
0180 struct mtk_clk_mux *mux;
0181 if (!hw)
0182 return;
0183
0184 mux = to_mtk_clk_mux(hw);
0185
0186 clk_hw_unregister(hw);
0187 kfree(mux);
0188 }
0189
0190 int mtk_clk_register_muxes(const struct mtk_mux *muxes,
0191 int num, struct device_node *node,
0192 spinlock_t *lock,
0193 struct clk_hw_onecell_data *clk_data)
0194 {
0195 struct regmap *regmap;
0196 struct clk_hw *hw;
0197 int i;
0198
0199 regmap = device_node_to_regmap(node);
0200 if (IS_ERR(regmap)) {
0201 pr_err("Cannot find regmap for %pOF: %pe\n", node, regmap);
0202 return PTR_ERR(regmap);
0203 }
0204
0205 for (i = 0; i < num; i++) {
0206 const struct mtk_mux *mux = &muxes[i];
0207
0208 if (!IS_ERR_OR_NULL(clk_data->hws[mux->id])) {
0209 pr_warn("%pOF: Trying to register duplicate clock ID: %d\n",
0210 node, mux->id);
0211 continue;
0212 }
0213
0214 hw = mtk_clk_register_mux(mux, regmap, lock);
0215
0216 if (IS_ERR(hw)) {
0217 pr_err("Failed to register clk %s: %pe\n", mux->name,
0218 hw);
0219 goto err;
0220 }
0221
0222 clk_data->hws[mux->id] = hw;
0223 }
0224
0225 return 0;
0226
0227 err:
0228 while (--i >= 0) {
0229 const struct mtk_mux *mux = &muxes[i];
0230
0231 if (IS_ERR_OR_NULL(clk_data->hws[mux->id]))
0232 continue;
0233
0234 mtk_clk_unregister_mux(clk_data->hws[mux->id]);
0235 clk_data->hws[mux->id] = ERR_PTR(-ENOENT);
0236 }
0237
0238 return PTR_ERR(hw);
0239 }
0240 EXPORT_SYMBOL_GPL(mtk_clk_register_muxes);
0241
0242 void mtk_clk_unregister_muxes(const struct mtk_mux *muxes, int num,
0243 struct clk_hw_onecell_data *clk_data)
0244 {
0245 int i;
0246
0247 if (!clk_data)
0248 return;
0249
0250 for (i = num; i > 0; i--) {
0251 const struct mtk_mux *mux = &muxes[i - 1];
0252
0253 if (IS_ERR_OR_NULL(clk_data->hws[mux->id]))
0254 continue;
0255
0256 mtk_clk_unregister_mux(clk_data->hws[mux->id]);
0257 clk_data->hws[mux->id] = ERR_PTR(-ENOENT);
0258 }
0259 }
0260 EXPORT_SYMBOL_GPL(mtk_clk_unregister_muxes);
0261
0262 MODULE_LICENSE("GPL");