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/bitops.h> 8 #include <linux/clk-provider.h> 9 #include <linux/err.h> 10 #include <linux/io.h> 11 #include <linux/mfd/syscon.h> 12 #include <linux/module.h> 13 #include <linux/of.h> 14 #include <linux/of_device.h> 15 #include <linux/platform_device.h> 16 #include <linux/slab.h> 17 18 #include "clk-mtk.h" 19 #include "clk-gate.h" 20 21 struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num) 22 { 23 int i; 24 struct clk_onecell_data *clk_data; 25 26 clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); 27 if (!clk_data) 28 return NULL; 29 30 clk_data->clks = kcalloc(clk_num, sizeof(*clk_data->clks), GFP_KERNEL); 31 if (!clk_data->clks) 32 goto err_out; 33 34 clk_data->clk_num = clk_num; 35 36 for (i = 0; i < clk_num; i++) 37 clk_data->clks[i] = ERR_PTR(-ENOENT); 38 39 return clk_data; 40 err_out: 41 kfree(clk_data); 42 43 return NULL; 44 } 45 EXPORT_SYMBOL_GPL(mtk_alloc_clk_data); 46 47 void mtk_free_clk_data(struct clk_onecell_data *clk_data) 48 { 49 if (!clk_data) 50 return; 51 52 kfree(clk_data->clks); 53 kfree(clk_data); 54 } 55 56 int mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, int num, 57 struct clk_onecell_data *clk_data) 58 { 59 int i; 60 struct clk *clk; 61 62 if (!clk_data) 63 return -ENOMEM; 64 65 for (i = 0; i < num; i++) { 66 const struct mtk_fixed_clk *rc = &clks[i]; 67 68 if (!IS_ERR_OR_NULL(clk_data->clks[rc->id])) { 69 pr_warn("Trying to register duplicate clock ID: %d\n", rc->id); 70 continue; 71 } 72 73 clk = clk_register_fixed_rate(NULL, rc->name, rc->parent, 0, 74 rc->rate); 75 76 if (IS_ERR(clk)) { 77 pr_err("Failed to register clk %s: %pe\n", rc->name, clk); 78 goto err; 79 } 80 81 clk_data->clks[rc->id] = clk; 82 } 83 84 return 0; 85 86 err: 87 while (--i >= 0) { 88 const struct mtk_fixed_clk *rc = &clks[i]; 89 90 if (IS_ERR_OR_NULL(clk_data->clks[rc->id])) 91 continue; 92 93 clk_unregister_fixed_rate(clk_data->clks[rc->id]); 94 clk_data->clks[rc->id] = ERR_PTR(-ENOENT); 95 } 96 97 return PTR_ERR(clk); 98 } 99 EXPORT_SYMBOL_GPL(mtk_clk_register_fixed_clks); 100 101 void mtk_clk_unregister_fixed_clks(const struct mtk_fixed_clk *clks, int num, 102 struct clk_onecell_data *clk_data) 103 { 104 int i; 105 106 if (!clk_data) 107 return; 108 109 for (i = num; i > 0; i--) { 110 const struct mtk_fixed_clk *rc = &clks[i - 1]; 111 112 if (IS_ERR_OR_NULL(clk_data->clks[rc->id])) 113 continue; 114 115 clk_unregister_fixed_rate(clk_data->clks[rc->id]); 116 clk_data->clks[rc->id] = ERR_PTR(-ENOENT); 117 } 118 } 119 EXPORT_SYMBOL_GPL(mtk_clk_unregister_fixed_clks); 120 121 int mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num, 122 struct clk_onecell_data *clk_data) 123 { 124 int i; 125 struct clk *clk; 126 127 if (!clk_data) 128 return -ENOMEM; 129 130 for (i = 0; i < num; i++) { 131 const struct mtk_fixed_factor *ff = &clks[i]; 132 133 if (!IS_ERR_OR_NULL(clk_data->clks[ff->id])) { 134 pr_warn("Trying to register duplicate clock ID: %d\n", ff->id); 135 continue; 136 } 137 138 clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name, 139 CLK_SET_RATE_PARENT, ff->mult, ff->div); 140 141 if (IS_ERR(clk)) { 142 pr_err("Failed to register clk %s: %pe\n", ff->name, clk); 143 goto err; 144 } 145 146 clk_data->clks[ff->id] = clk; 147 } 148 149 return 0; 150 151 err: 152 while (--i >= 0) { 153 const struct mtk_fixed_factor *ff = &clks[i]; 154 155 if (IS_ERR_OR_NULL(clk_data->clks[ff->id])) 156 continue; 157 158 clk_unregister_fixed_factor(clk_data->clks[ff->id]); 159 clk_data->clks[ff->id] = ERR_PTR(-ENOENT); 160 } 161 162 return PTR_ERR(clk); 163 } 164 EXPORT_SYMBOL_GPL(mtk_clk_register_factors); 165 166 void mtk_clk_unregister_factors(const struct mtk_fixed_factor *clks, int num, 167 struct clk_onecell_data *clk_data) 168 { 169 int i; 170 171 if (!clk_data) 172 return; 173 174 for (i = num; i > 0; i--) { 175 const struct mtk_fixed_factor *ff = &clks[i - 1]; 176 177 if (IS_ERR_OR_NULL(clk_data->clks[ff->id])) 178 continue; 179 180 clk_unregister_fixed_factor(clk_data->clks[ff->id]); 181 clk_data->clks[ff->id] = ERR_PTR(-ENOENT); 182 } 183 } 184 EXPORT_SYMBOL_GPL(mtk_clk_unregister_factors); 185 186 struct clk *mtk_clk_register_composite(const struct mtk_composite *mc, 187 void __iomem *base, spinlock_t *lock) 188 { 189 struct clk *clk; 190 struct clk_mux *mux = NULL; 191 struct clk_gate *gate = NULL; 192 struct clk_divider *div = NULL; 193 struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *div_hw = NULL; 194 const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *div_ops = NULL; 195 const char * const *parent_names; 196 const char *parent; 197 int num_parents; 198 int ret; 199 200 if (mc->mux_shift >= 0) { 201 mux = kzalloc(sizeof(*mux), GFP_KERNEL); 202 if (!mux) 203 return ERR_PTR(-ENOMEM); 204 205 mux->reg = base + mc->mux_reg; 206 mux->mask = BIT(mc->mux_width) - 1; 207 mux->shift = mc->mux_shift; 208 mux->lock = lock; 209 mux->flags = mc->mux_flags; 210 mux_hw = &mux->hw; 211 mux_ops = &clk_mux_ops; 212 213 parent_names = mc->parent_names; 214 num_parents = mc->num_parents; 215 } else { 216 parent = mc->parent; 217 parent_names = &parent; 218 num_parents = 1; 219 } 220 221 if (mc->gate_shift >= 0) { 222 gate = kzalloc(sizeof(*gate), GFP_KERNEL); 223 if (!gate) { 224 ret = -ENOMEM; 225 goto err_out; 226 } 227 228 gate->reg = base + mc->gate_reg; 229 gate->bit_idx = mc->gate_shift; 230 gate->flags = CLK_GATE_SET_TO_DISABLE; 231 gate->lock = lock; 232 233 gate_hw = &gate->hw; 234 gate_ops = &clk_gate_ops; 235 } 236 237 if (mc->divider_shift >= 0) { 238 div = kzalloc(sizeof(*div), GFP_KERNEL); 239 if (!div) { 240 ret = -ENOMEM; 241 goto err_out; 242 } 243 244 div->reg = base + mc->divider_reg; 245 div->shift = mc->divider_shift; 246 div->width = mc->divider_width; 247 div->lock = lock; 248 249 div_hw = &div->hw; 250 div_ops = &clk_divider_ops; 251 } 252 253 clk = clk_register_composite(NULL, mc->name, parent_names, num_parents, 254 mux_hw, mux_ops, 255 div_hw, div_ops, 256 gate_hw, gate_ops, 257 mc->flags); 258 259 if (IS_ERR(clk)) { 260 ret = PTR_ERR(clk); 261 goto err_out; 262 } 263 264 return clk; 265 err_out: 266 kfree(div); 267 kfree(gate); 268 kfree(mux); 269 270 return ERR_PTR(ret); 271 } 272 273 static void mtk_clk_unregister_composite(struct clk *clk) 274 { 275 struct clk_hw *hw; 276 struct clk_composite *composite; 277 struct clk_mux *mux = NULL; 278 struct clk_gate *gate = NULL; 279 struct clk_divider *div = NULL; 280 281 hw = __clk_get_hw(clk); 282 if (!hw) 283 return; 284 285 composite = to_clk_composite(hw); 286 if (composite->mux_hw) 287 mux = to_clk_mux(composite->mux_hw); 288 if (composite->gate_hw) 289 gate = to_clk_gate(composite->gate_hw); 290 if (composite->rate_hw) 291 div = to_clk_divider(composite->rate_hw); 292 293 clk_unregister_composite(clk); 294 kfree(div); 295 kfree(gate); 296 kfree(mux); 297 } 298 299 int mtk_clk_register_composites(const struct mtk_composite *mcs, int num, 300 void __iomem *base, spinlock_t *lock, 301 struct clk_onecell_data *clk_data) 302 { 303 struct clk *clk; 304 int i; 305 306 if (!clk_data) 307 return -ENOMEM; 308 309 for (i = 0; i < num; i++) { 310 const struct mtk_composite *mc = &mcs[i]; 311 312 if (!IS_ERR_OR_NULL(clk_data->clks[mc->id])) { 313 pr_warn("Trying to register duplicate clock ID: %d\n", 314 mc->id); 315 continue; 316 } 317 318 clk = mtk_clk_register_composite(mc, base, lock); 319 320 if (IS_ERR(clk)) { 321 pr_err("Failed to register clk %s: %pe\n", mc->name, clk); 322 goto err; 323 } 324 325 clk_data->clks[mc->id] = clk; 326 } 327 328 return 0; 329 330 err: 331 while (--i >= 0) { 332 const struct mtk_composite *mc = &mcs[i]; 333 334 if (IS_ERR_OR_NULL(clk_data->clks[mcs->id])) 335 continue; 336 337 mtk_clk_unregister_composite(clk_data->clks[mc->id]); 338 clk_data->clks[mc->id] = ERR_PTR(-ENOENT); 339 } 340 341 return PTR_ERR(clk); 342 } 343 EXPORT_SYMBOL_GPL(mtk_clk_register_composites); 344 345 void mtk_clk_unregister_composites(const struct mtk_composite *mcs, int num, 346 struct clk_onecell_data *clk_data) 347 { 348 int i; 349 350 if (!clk_data) 351 return; 352 353 for (i = num; i > 0; i--) { 354 const struct mtk_composite *mc = &mcs[i - 1]; 355 356 if (IS_ERR_OR_NULL(clk_data->clks[mc->id])) 357 continue; 358 359 mtk_clk_unregister_composite(clk_data->clks[mc->id]); 360 clk_data->clks[mc->id] = ERR_PTR(-ENOENT); 361 } 362 } 363 EXPORT_SYMBOL_GPL(mtk_clk_unregister_composites); 364 365 int mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, int num, 366 void __iomem *base, spinlock_t *lock, 367 struct clk_onecell_data *clk_data) 368 { 369 struct clk *clk; 370 int i; 371 372 if (!clk_data) 373 return -ENOMEM; 374 375 for (i = 0; i < num; i++) { 376 const struct mtk_clk_divider *mcd = &mcds[i]; 377 378 if (!IS_ERR_OR_NULL(clk_data->clks[mcd->id])) { 379 pr_warn("Trying to register duplicate clock ID: %d\n", 380 mcd->id); 381 continue; 382 } 383 384 clk = clk_register_divider(NULL, mcd->name, mcd->parent_name, 385 mcd->flags, base + mcd->div_reg, mcd->div_shift, 386 mcd->div_width, mcd->clk_divider_flags, lock); 387 388 if (IS_ERR(clk)) { 389 pr_err("Failed to register clk %s: %pe\n", mcd->name, clk); 390 goto err; 391 } 392 393 clk_data->clks[mcd->id] = clk; 394 } 395 396 return 0; 397 398 err: 399 while (--i >= 0) { 400 const struct mtk_clk_divider *mcd = &mcds[i]; 401 402 if (IS_ERR_OR_NULL(clk_data->clks[mcd->id])) 403 continue; 404 405 mtk_clk_unregister_composite(clk_data->clks[mcd->id]); 406 clk_data->clks[mcd->id] = ERR_PTR(-ENOENT); 407 } 408 409 return PTR_ERR(clk); 410 } 411 412 void mtk_clk_unregister_dividers(const struct mtk_clk_divider *mcds, int num, 413 struct clk_onecell_data *clk_data) 414 { 415 int i; 416 417 if (!clk_data) 418 return; 419 420 for (i = num; i > 0; i--) { 421 const struct mtk_clk_divider *mcd = &mcds[i - 1]; 422 423 if (IS_ERR_OR_NULL(clk_data->clks[mcd->id])) 424 continue; 425 426 clk_unregister_divider(clk_data->clks[mcd->id]); 427 clk_data->clks[mcd->id] = ERR_PTR(-ENOENT); 428 } 429 } 430 431 int mtk_clk_simple_probe(struct platform_device *pdev) 432 { 433 const struct mtk_clk_desc *mcd; 434 struct clk_onecell_data *clk_data; 435 struct device_node *node = pdev->dev.of_node; 436 int r; 437 438 mcd = of_device_get_match_data(&pdev->dev); 439 if (!mcd) 440 return -EINVAL; 441 442 clk_data = mtk_alloc_clk_data(mcd->num_clks); 443 if (!clk_data) 444 return -ENOMEM; 445 446 r = mtk_clk_register_gates(node, mcd->clks, mcd->num_clks, clk_data); 447 if (r) 448 goto free_data; 449 450 r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); 451 if (r) 452 goto unregister_clks; 453 454 platform_set_drvdata(pdev, clk_data); 455 456 return r; 457 458 unregister_clks: 459 mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data); 460 free_data: 461 mtk_free_clk_data(clk_data); 462 return r; 463 } 464 465 int mtk_clk_simple_remove(struct platform_device *pdev) 466 { 467 const struct mtk_clk_desc *mcd = of_device_get_match_data(&pdev->dev); 468 struct clk_onecell_data *clk_data = platform_get_drvdata(pdev); 469 struct device_node *node = pdev->dev.of_node; 470 471 of_clk_del_provider(node); 472 mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data); 473 mtk_free_clk_data(clk_data); 474 475 return 0; 476 } 477 478 MODULE_LICENSE("GPL"); 479