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