1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2014 MediaTek Inc. 4 * Author: James Liao <jamesjj.liao@mediatek.com> 5 */ 6 7 #include <linux/clk-provider.h> 8 #include <linux/dev_printk.h> 9 #include <linux/mfd/syscon.h> 10 #include <linux/module.h> 11 #include <linux/printk.h> 12 #include <linux/regmap.h> 13 #include <linux/slab.h> 14 #include <linux/types.h> 15 16 #include "clk-mtk.h" 17 #include "clk-gate.h" 18 19 struct mtk_clk_gate { 20 struct clk_hw hw; 21 struct regmap *regmap; 22 struct regmap *regmap_hwv; 23 const struct mtk_gate *gate; 24 }; 25 26 static inline struct mtk_clk_gate *to_mtk_clk_gate(struct clk_hw *hw) 27 { 28 return container_of(hw, struct mtk_clk_gate, hw); 29 } 30 31 static u32 mtk_get_clockgating(struct clk_hw *hw) 32 { 33 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); 34 u32 val; 35 36 regmap_read(cg->regmap, cg->gate->regs->sta_ofs, &val); 37 38 return val & BIT(cg->gate->shift); 39 } 40 41 static int mtk_cg_bit_is_cleared(struct clk_hw *hw) 42 { 43 return mtk_get_clockgating(hw) == 0; 44 } 45 46 static int mtk_cg_bit_is_set(struct clk_hw *hw) 47 { 48 return mtk_get_clockgating(hw) != 0; 49 } 50 51 static void mtk_cg_set_bit(struct clk_hw *hw) 52 { 53 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); 54 55 regmap_write(cg->regmap, cg->gate->regs->set_ofs, BIT(cg->gate->shift)); 56 } 57 58 static void mtk_cg_clr_bit(struct clk_hw *hw) 59 { 60 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); 61 62 regmap_write(cg->regmap, cg->gate->regs->clr_ofs, BIT(cg->gate->shift)); 63 } 64 65 static void mtk_cg_set_bit_no_setclr(struct clk_hw *hw) 66 { 67 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); 68 69 regmap_set_bits(cg->regmap, cg->gate->regs->sta_ofs, 70 BIT(cg->gate->shift)); 71 } 72 73 static void mtk_cg_clr_bit_no_setclr(struct clk_hw *hw) 74 { 75 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); 76 77 regmap_clear_bits(cg->regmap, cg->gate->regs->sta_ofs, 78 BIT(cg->gate->shift)); 79 } 80 81 static int mtk_cg_enable(struct clk_hw *hw) 82 { 83 mtk_cg_clr_bit(hw); 84 85 return 0; 86 } 87 88 static void mtk_cg_disable(struct clk_hw *hw) 89 { 90 mtk_cg_set_bit(hw); 91 } 92 93 static int mtk_cg_enable_inv(struct clk_hw *hw) 94 { 95 mtk_cg_set_bit(hw); 96 97 return 0; 98 } 99 100 static void mtk_cg_disable_inv(struct clk_hw *hw) 101 { 102 mtk_cg_clr_bit(hw); 103 } 104 105 static int mtk_cg_hwv_set_en(struct clk_hw *hw, bool enable) 106 { 107 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); 108 u32 val; 109 110 regmap_write(cg->regmap_hwv, 111 enable ? cg->gate->hwv_regs->set_ofs : 112 cg->gate->hwv_regs->clr_ofs, 113 BIT(cg->gate->shift)); 114 115 return regmap_read_poll_timeout_atomic(cg->regmap_hwv, 116 cg->gate->hwv_regs->sta_ofs, val, 117 val & BIT(cg->gate->shift), 0, 118 MTK_WAIT_HWV_DONE_US); 119 } 120 121 static int mtk_cg_hwv_enable(struct clk_hw *hw) 122 { 123 return mtk_cg_hwv_set_en(hw, true); 124 } 125 126 static void mtk_cg_hwv_disable(struct clk_hw *hw) 127 { 128 mtk_cg_hwv_set_en(hw, false); 129 } 130 131 static int mtk_cg_enable_no_setclr(struct clk_hw *hw) 132 { 133 mtk_cg_clr_bit_no_setclr(hw); 134 135 return 0; 136 } 137 138 static void mtk_cg_disable_no_setclr(struct clk_hw *hw) 139 { 140 mtk_cg_set_bit_no_setclr(hw); 141 } 142 143 static int mtk_cg_enable_inv_no_setclr(struct clk_hw *hw) 144 { 145 mtk_cg_set_bit_no_setclr(hw); 146 147 return 0; 148 } 149 150 static void mtk_cg_disable_inv_no_setclr(struct clk_hw *hw) 151 { 152 mtk_cg_clr_bit_no_setclr(hw); 153 } 154 155 static bool mtk_cg_uses_hwv(const struct clk_ops *ops) 156 { 157 if (ops == &mtk_clk_gate_hwv_ops_setclr || 158 ops == &mtk_clk_gate_hwv_ops_setclr_inv) 159 return true; 160 161 return false; 162 } 163 164 const struct clk_ops mtk_clk_gate_ops_setclr = { 165 .is_enabled = mtk_cg_bit_is_cleared, 166 .enable = mtk_cg_enable, 167 .disable = mtk_cg_disable, 168 }; 169 EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_setclr); 170 171 const struct clk_ops mtk_clk_gate_ops_setclr_inv = { 172 .is_enabled = mtk_cg_bit_is_set, 173 .enable = mtk_cg_enable_inv, 174 .disable = mtk_cg_disable_inv, 175 }; 176 EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_setclr_inv); 177 178 const struct clk_ops mtk_clk_gate_hwv_ops_setclr = { 179 .is_enabled = mtk_cg_bit_is_cleared, 180 .enable = mtk_cg_hwv_enable, 181 .disable = mtk_cg_hwv_disable, 182 }; 183 EXPORT_SYMBOL_GPL(mtk_clk_gate_hwv_ops_setclr); 184 185 const struct clk_ops mtk_clk_gate_hwv_ops_setclr_inv = { 186 .is_enabled = mtk_cg_bit_is_set, 187 .enable = mtk_cg_hwv_enable, 188 .disable = mtk_cg_hwv_disable, 189 }; 190 EXPORT_SYMBOL_GPL(mtk_clk_gate_hwv_ops_setclr_inv); 191 192 const struct clk_ops mtk_clk_gate_ops_no_setclr = { 193 .is_enabled = mtk_cg_bit_is_cleared, 194 .enable = mtk_cg_enable_no_setclr, 195 .disable = mtk_cg_disable_no_setclr, 196 }; 197 EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_no_setclr); 198 199 const struct clk_ops mtk_clk_gate_ops_no_setclr_inv = { 200 .is_enabled = mtk_cg_bit_is_set, 201 .enable = mtk_cg_enable_inv_no_setclr, 202 .disable = mtk_cg_disable_inv_no_setclr, 203 }; 204 EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_no_setclr_inv); 205 206 static struct clk_hw *mtk_clk_register_gate(struct device *dev, 207 const struct mtk_gate *gate, 208 struct regmap *regmap, 209 struct regmap *regmap_hwv) 210 { 211 struct mtk_clk_gate *cg; 212 int ret; 213 struct clk_init_data init = {}; 214 215 cg = kzalloc(sizeof(*cg), GFP_KERNEL); 216 if (!cg) 217 return ERR_PTR(-ENOMEM); 218 219 init.name = gate->name; 220 init.flags = gate->flags | CLK_SET_RATE_PARENT; 221 init.parent_names = gate->parent_name ? &gate->parent_name : NULL; 222 init.num_parents = gate->parent_name ? 1 : 0; 223 init.ops = gate->ops; 224 if (mtk_cg_uses_hwv(init.ops) && !regmap_hwv) 225 return dev_err_ptr_probe( 226 dev, -ENXIO, 227 "regmap not found for hardware voter clocks\n"); 228 229 cg->regmap = regmap; 230 cg->regmap_hwv = regmap_hwv; 231 cg->gate = gate; 232 cg->hw.init = &init; 233 234 ret = clk_hw_register(dev, &cg->hw); 235 if (ret) { 236 kfree(cg); 237 return ERR_PTR(ret); 238 } 239 240 return &cg->hw; 241 } 242 243 static void mtk_clk_unregister_gate(struct clk_hw *hw) 244 { 245 struct mtk_clk_gate *cg; 246 if (!hw) 247 return; 248 249 cg = to_mtk_clk_gate(hw); 250 251 clk_hw_unregister(hw); 252 kfree(cg); 253 } 254 255 int mtk_clk_register_gates(struct device *dev, struct device_node *node, 256 const struct mtk_gate *clks, int num, 257 struct clk_hw_onecell_data *clk_data) 258 { 259 int i; 260 struct clk_hw *hw; 261 struct regmap *regmap; 262 struct regmap *regmap_hwv; 263 264 if (!clk_data) 265 return -ENOMEM; 266 267 regmap = device_node_to_regmap(node); 268 if (IS_ERR(regmap)) { 269 pr_err("Cannot find regmap for %pOF: %pe\n", node, regmap); 270 return PTR_ERR(regmap); 271 } 272 273 regmap_hwv = mtk_clk_get_hwv_regmap(node); 274 if (IS_ERR(regmap_hwv)) 275 return dev_err_probe( 276 dev, PTR_ERR(regmap_hwv), 277 "Cannot find hardware voter regmap for %pOF\n", node); 278 279 for (i = 0; i < num; i++) { 280 const struct mtk_gate *gate = &clks[i]; 281 282 if (!IS_ERR_OR_NULL(clk_data->hws[gate->id])) { 283 pr_warn("%pOF: Trying to register duplicate clock ID: %d\n", 284 node, gate->id); 285 continue; 286 } 287 288 hw = mtk_clk_register_gate(dev, gate, regmap, regmap_hwv); 289 290 if (IS_ERR(hw)) { 291 pr_err("Failed to register clk %s: %pe\n", gate->name, 292 hw); 293 goto err; 294 } 295 296 clk_data->hws[gate->id] = hw; 297 } 298 299 return 0; 300 301 err: 302 while (--i >= 0) { 303 const struct mtk_gate *gate = &clks[i]; 304 305 if (IS_ERR_OR_NULL(clk_data->hws[gate->id])) 306 continue; 307 308 mtk_clk_unregister_gate(clk_data->hws[gate->id]); 309 clk_data->hws[gate->id] = ERR_PTR(-ENOENT); 310 } 311 312 return PTR_ERR(hw); 313 } 314 EXPORT_SYMBOL_GPL(mtk_clk_register_gates); 315 316 void mtk_clk_unregister_gates(const struct mtk_gate *clks, int num, 317 struct clk_hw_onecell_data *clk_data) 318 { 319 int i; 320 321 if (!clk_data) 322 return; 323 324 for (i = num; i > 0; i--) { 325 const struct mtk_gate *gate = &clks[i - 1]; 326 327 if (IS_ERR_OR_NULL(clk_data->hws[gate->id])) 328 continue; 329 330 mtk_clk_unregister_gate(clk_data->hws[gate->id]); 331 clk_data->hws[gate->id] = ERR_PTR(-ENOENT); 332 } 333 } 334 EXPORT_SYMBOL_GPL(mtk_clk_unregister_gates); 335 336 MODULE_LICENSE("GPL"); 337