0001
0002
0003
0004
0005
0006
0007 #include <linux/clk-provider.h>
0008 #include <linux/mfd/syscon.h>
0009 #include <linux/module.h>
0010 #include <linux/printk.h>
0011 #include <linux/regmap.h>
0012 #include <linux/slab.h>
0013 #include <linux/types.h>
0014
0015 #include "clk-gate.h"
0016
0017 struct mtk_clk_gate {
0018 struct clk_hw hw;
0019 struct regmap *regmap;
0020 int set_ofs;
0021 int clr_ofs;
0022 int sta_ofs;
0023 u8 bit;
0024 };
0025
0026 static inline struct mtk_clk_gate *to_mtk_clk_gate(struct clk_hw *hw)
0027 {
0028 return container_of(hw, struct mtk_clk_gate, hw);
0029 }
0030
0031 static u32 mtk_get_clockgating(struct clk_hw *hw)
0032 {
0033 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
0034 u32 val;
0035
0036 regmap_read(cg->regmap, cg->sta_ofs, &val);
0037
0038 return val & BIT(cg->bit);
0039 }
0040
0041 static int mtk_cg_bit_is_cleared(struct clk_hw *hw)
0042 {
0043 return mtk_get_clockgating(hw) == 0;
0044 }
0045
0046 static int mtk_cg_bit_is_set(struct clk_hw *hw)
0047 {
0048 return mtk_get_clockgating(hw) != 0;
0049 }
0050
0051 static void mtk_cg_set_bit(struct clk_hw *hw)
0052 {
0053 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
0054
0055 regmap_write(cg->regmap, cg->set_ofs, BIT(cg->bit));
0056 }
0057
0058 static void mtk_cg_clr_bit(struct clk_hw *hw)
0059 {
0060 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
0061
0062 regmap_write(cg->regmap, cg->clr_ofs, BIT(cg->bit));
0063 }
0064
0065 static void mtk_cg_set_bit_no_setclr(struct clk_hw *hw)
0066 {
0067 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
0068
0069 regmap_set_bits(cg->regmap, cg->sta_ofs, BIT(cg->bit));
0070 }
0071
0072 static void mtk_cg_clr_bit_no_setclr(struct clk_hw *hw)
0073 {
0074 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
0075
0076 regmap_clear_bits(cg->regmap, cg->sta_ofs, BIT(cg->bit));
0077 }
0078
0079 static int mtk_cg_enable(struct clk_hw *hw)
0080 {
0081 mtk_cg_clr_bit(hw);
0082
0083 return 0;
0084 }
0085
0086 static void mtk_cg_disable(struct clk_hw *hw)
0087 {
0088 mtk_cg_set_bit(hw);
0089 }
0090
0091 static int mtk_cg_enable_inv(struct clk_hw *hw)
0092 {
0093 mtk_cg_set_bit(hw);
0094
0095 return 0;
0096 }
0097
0098 static void mtk_cg_disable_inv(struct clk_hw *hw)
0099 {
0100 mtk_cg_clr_bit(hw);
0101 }
0102
0103 static int mtk_cg_enable_no_setclr(struct clk_hw *hw)
0104 {
0105 mtk_cg_clr_bit_no_setclr(hw);
0106
0107 return 0;
0108 }
0109
0110 static void mtk_cg_disable_no_setclr(struct clk_hw *hw)
0111 {
0112 mtk_cg_set_bit_no_setclr(hw);
0113 }
0114
0115 static int mtk_cg_enable_inv_no_setclr(struct clk_hw *hw)
0116 {
0117 mtk_cg_set_bit_no_setclr(hw);
0118
0119 return 0;
0120 }
0121
0122 static void mtk_cg_disable_inv_no_setclr(struct clk_hw *hw)
0123 {
0124 mtk_cg_clr_bit_no_setclr(hw);
0125 }
0126
0127 const struct clk_ops mtk_clk_gate_ops_setclr = {
0128 .is_enabled = mtk_cg_bit_is_cleared,
0129 .enable = mtk_cg_enable,
0130 .disable = mtk_cg_disable,
0131 };
0132 EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_setclr);
0133
0134 const struct clk_ops mtk_clk_gate_ops_setclr_inv = {
0135 .is_enabled = mtk_cg_bit_is_set,
0136 .enable = mtk_cg_enable_inv,
0137 .disable = mtk_cg_disable_inv,
0138 };
0139 EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_setclr_inv);
0140
0141 const struct clk_ops mtk_clk_gate_ops_no_setclr = {
0142 .is_enabled = mtk_cg_bit_is_cleared,
0143 .enable = mtk_cg_enable_no_setclr,
0144 .disable = mtk_cg_disable_no_setclr,
0145 };
0146 EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_no_setclr);
0147
0148 const struct clk_ops mtk_clk_gate_ops_no_setclr_inv = {
0149 .is_enabled = mtk_cg_bit_is_set,
0150 .enable = mtk_cg_enable_inv_no_setclr,
0151 .disable = mtk_cg_disable_inv_no_setclr,
0152 };
0153 EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_no_setclr_inv);
0154
0155 static struct clk_hw *mtk_clk_register_gate(const char *name,
0156 const char *parent_name,
0157 struct regmap *regmap, int set_ofs,
0158 int clr_ofs, int sta_ofs, u8 bit,
0159 const struct clk_ops *ops,
0160 unsigned long flags, struct device *dev)
0161 {
0162 struct mtk_clk_gate *cg;
0163 int ret;
0164 struct clk_init_data init = {};
0165
0166 cg = kzalloc(sizeof(*cg), GFP_KERNEL);
0167 if (!cg)
0168 return ERR_PTR(-ENOMEM);
0169
0170 init.name = name;
0171 init.flags = flags | CLK_SET_RATE_PARENT;
0172 init.parent_names = parent_name ? &parent_name : NULL;
0173 init.num_parents = parent_name ? 1 : 0;
0174 init.ops = ops;
0175
0176 cg->regmap = regmap;
0177 cg->set_ofs = set_ofs;
0178 cg->clr_ofs = clr_ofs;
0179 cg->sta_ofs = sta_ofs;
0180 cg->bit = bit;
0181
0182 cg->hw.init = &init;
0183
0184 ret = clk_hw_register(dev, &cg->hw);
0185 if (ret) {
0186 kfree(cg);
0187 return ERR_PTR(ret);
0188 }
0189
0190 return &cg->hw;
0191 }
0192
0193 static void mtk_clk_unregister_gate(struct clk_hw *hw)
0194 {
0195 struct mtk_clk_gate *cg;
0196 if (!hw)
0197 return;
0198
0199 cg = to_mtk_clk_gate(hw);
0200
0201 clk_hw_unregister(hw);
0202 kfree(cg);
0203 }
0204
0205 int mtk_clk_register_gates_with_dev(struct device_node *node,
0206 const struct mtk_gate *clks, int num,
0207 struct clk_hw_onecell_data *clk_data,
0208 struct device *dev)
0209 {
0210 int i;
0211 struct clk_hw *hw;
0212 struct regmap *regmap;
0213
0214 if (!clk_data)
0215 return -ENOMEM;
0216
0217 regmap = device_node_to_regmap(node);
0218 if (IS_ERR(regmap)) {
0219 pr_err("Cannot find regmap for %pOF: %pe\n", node, regmap);
0220 return PTR_ERR(regmap);
0221 }
0222
0223 for (i = 0; i < num; i++) {
0224 const struct mtk_gate *gate = &clks[i];
0225
0226 if (!IS_ERR_OR_NULL(clk_data->hws[gate->id])) {
0227 pr_warn("%pOF: Trying to register duplicate clock ID: %d\n",
0228 node, gate->id);
0229 continue;
0230 }
0231
0232 hw = mtk_clk_register_gate(gate->name, gate->parent_name,
0233 regmap,
0234 gate->regs->set_ofs,
0235 gate->regs->clr_ofs,
0236 gate->regs->sta_ofs,
0237 gate->shift, gate->ops,
0238 gate->flags, dev);
0239
0240 if (IS_ERR(hw)) {
0241 pr_err("Failed to register clk %s: %pe\n", gate->name,
0242 hw);
0243 goto err;
0244 }
0245
0246 clk_data->hws[gate->id] = hw;
0247 }
0248
0249 return 0;
0250
0251 err:
0252 while (--i >= 0) {
0253 const struct mtk_gate *gate = &clks[i];
0254
0255 if (IS_ERR_OR_NULL(clk_data->hws[gate->id]))
0256 continue;
0257
0258 mtk_clk_unregister_gate(clk_data->hws[gate->id]);
0259 clk_data->hws[gate->id] = ERR_PTR(-ENOENT);
0260 }
0261
0262 return PTR_ERR(hw);
0263 }
0264
0265 int mtk_clk_register_gates(struct device_node *node,
0266 const struct mtk_gate *clks, int num,
0267 struct clk_hw_onecell_data *clk_data)
0268 {
0269 return mtk_clk_register_gates_with_dev(node, clks, num, clk_data, NULL);
0270 }
0271 EXPORT_SYMBOL_GPL(mtk_clk_register_gates);
0272
0273 void mtk_clk_unregister_gates(const struct mtk_gate *clks, int num,
0274 struct clk_hw_onecell_data *clk_data)
0275 {
0276 int i;
0277
0278 if (!clk_data)
0279 return;
0280
0281 for (i = num; i > 0; i--) {
0282 const struct mtk_gate *gate = &clks[i - 1];
0283
0284 if (IS_ERR_OR_NULL(clk_data->hws[gate->id]))
0285 continue;
0286
0287 mtk_clk_unregister_gate(clk_data->hws[gate->id]);
0288 clk_data->hws[gate->id] = ERR_PTR(-ENOENT);
0289 }
0290 }
0291 EXPORT_SYMBOL_GPL(mtk_clk_unregister_gates);
0292
0293 MODULE_LICENSE("GPL");