Lines Matching +full:speed +full:- +full:grade

1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2013 - 2021 Xilinx
13 #include <linux/clk-provider.h>
53 #define div_mask(width) ((1 << (width)) - 1)
66 * struct clk_wzrd - Clock wizard private data structure
75 * @speed_grade: Speed grade of the device
91 * struct clk_wzrd_divider - clock divider specific to clk_wzrd
93 * @hw: handle between common and hardware-specific interfaces
115 /* maximum frequencies for input/output clocks per speed grade */
129 void __iomem *div_addr = divider->base + divider->offset; in clk_wzrd_recalc_rate()
132 val = readl(div_addr) >> divider->shift; in clk_wzrd_recalc_rate()
133 val &= div_mask(divider->width); in clk_wzrd_recalc_rate()
135 return divider_recalc_rate(hw, parent_rate, val, divider->table, in clk_wzrd_recalc_rate()
136 divider->flags, divider->width); in clk_wzrd_recalc_rate()
146 void __iomem *div_addr = divider->base + divider->offset; in clk_wzrd_dynamic_reconfig()
148 if (divider->lock) in clk_wzrd_dynamic_reconfig()
149 spin_lock_irqsave(divider->lock, flags); in clk_wzrd_dynamic_reconfig()
151 __acquire(divider->lock); in clk_wzrd_dynamic_reconfig()
163 err = readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, in clk_wzrd_dynamic_reconfig()
171 divider->base + WZRD_DR_INIT_REG_OFFSET); in clk_wzrd_dynamic_reconfig()
173 divider->base + WZRD_DR_INIT_REG_OFFSET); in clk_wzrd_dynamic_reconfig()
176 err = readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, in clk_wzrd_dynamic_reconfig()
180 if (divider->lock) in clk_wzrd_dynamic_reconfig()
181 spin_unlock_irqrestore(divider->lock, flags); in clk_wzrd_dynamic_reconfig()
183 __release(divider->lock); in clk_wzrd_dynamic_reconfig()
213 void __iomem *div_addr = divider->base + divider->offset; in clk_wzrd_recalc_ratef()
216 div = val & div_mask(divider->width); in clk_wzrd_recalc_ratef()
229 void __iomem *div_addr = divider->base + divider->offset; in clk_wzrd_dynamic_reconfig_f()
235 f = (u32)(pre - (clockout0_div * 1000)); in clk_wzrd_dynamic_reconfig_f()
246 err = readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, value, in clk_wzrd_dynamic_reconfig_f()
254 divider->base + WZRD_DR_INIT_REG_OFFSET); in clk_wzrd_dynamic_reconfig_f()
256 divider->base + WZRD_DR_INIT_REG_OFFSET); in clk_wzrd_dynamic_reconfig_f()
259 return readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, value, in clk_wzrd_dynamic_reconfig_f()
293 return ERR_PTR(-ENOMEM); in clk_wzrd_register_divf()
303 div->base = base; in clk_wzrd_register_divf()
304 div->offset = offset; in clk_wzrd_register_divf()
305 div->shift = shift; in clk_wzrd_register_divf()
306 div->width = width; in clk_wzrd_register_divf()
307 div->flags = clk_divider_flags; in clk_wzrd_register_divf()
308 div->lock = lock; in clk_wzrd_register_divf()
309 div->hw.init = &init; in clk_wzrd_register_divf()
310 div->table = table; in clk_wzrd_register_divf()
312 hw = &div->hw; in clk_wzrd_register_divf()
317 return hw->clk; in clk_wzrd_register_divf()
337 return ERR_PTR(-ENOMEM); in clk_wzrd_register_divider()
345 div->base = base; in clk_wzrd_register_divider()
346 div->offset = offset; in clk_wzrd_register_divider()
347 div->shift = shift; in clk_wzrd_register_divider()
348 div->width = width; in clk_wzrd_register_divider()
349 div->flags = clk_divider_flags; in clk_wzrd_register_divider()
350 div->lock = lock; in clk_wzrd_register_divider()
351 div->hw.init = &init; in clk_wzrd_register_divider()
352 div->table = table; in clk_wzrd_register_divider()
354 hw = &div->hw; in clk_wzrd_register_divider()
359 return hw->clk; in clk_wzrd_register_divider()
369 if (clk_wzrd->suspended) in clk_wzrd_clk_notifier()
372 if (ndata->clk == clk_wzrd->clk_in1) in clk_wzrd_clk_notifier()
373 max = clk_wzrd_max_freq[clk_wzrd->speed_grade - 1]; in clk_wzrd_clk_notifier()
374 else if (ndata->clk == clk_wzrd->axi_clk) in clk_wzrd_clk_notifier()
381 if (ndata->new_rate > max) in clk_wzrd_clk_notifier()
395 clk_disable_unprepare(clk_wzrd->axi_clk); in clk_wzrd_suspend()
396 clk_wzrd->suspended = true; in clk_wzrd_suspend()
406 ret = clk_prepare_enable(clk_wzrd->axi_clk); in clk_wzrd_resume()
412 clk_wzrd->suspended = false; in clk_wzrd_resume()
428 struct device_node *np = pdev->dev.of_node; in clk_wzrd_probe()
432 clk_wzrd = devm_kzalloc(&pdev->dev, sizeof(*clk_wzrd), GFP_KERNEL); in clk_wzrd_probe()
434 return -ENOMEM; in clk_wzrd_probe()
437 clk_wzrd->base = devm_platform_ioremap_resource(pdev, 0); in clk_wzrd_probe()
438 if (IS_ERR(clk_wzrd->base)) in clk_wzrd_probe()
439 return PTR_ERR(clk_wzrd->base); in clk_wzrd_probe()
441 ret = of_property_read_u32(np, "xlnx,speed-grade", &clk_wzrd->speed_grade); in clk_wzrd_probe()
443 if (clk_wzrd->speed_grade < 1 || clk_wzrd->speed_grade > 3) { in clk_wzrd_probe()
444 dev_warn(&pdev->dev, "invalid speed grade '%d'\n", in clk_wzrd_probe()
445 clk_wzrd->speed_grade); in clk_wzrd_probe()
446 clk_wzrd->speed_grade = 0; in clk_wzrd_probe()
450 clk_wzrd->clk_in1 = devm_clk_get(&pdev->dev, "clk_in1"); in clk_wzrd_probe()
451 if (IS_ERR(clk_wzrd->clk_in1)) in clk_wzrd_probe()
452 return dev_err_probe(&pdev->dev, PTR_ERR(clk_wzrd->clk_in1), in clk_wzrd_probe()
455 clk_wzrd->axi_clk = devm_clk_get(&pdev->dev, "s_axi_aclk"); in clk_wzrd_probe()
456 if (IS_ERR(clk_wzrd->axi_clk)) in clk_wzrd_probe()
457 return dev_err_probe(&pdev->dev, PTR_ERR(clk_wzrd->axi_clk), in clk_wzrd_probe()
459 ret = clk_prepare_enable(clk_wzrd->axi_clk); in clk_wzrd_probe()
461 dev_err(&pdev->dev, "enabling s_axi_aclk failed\n"); in clk_wzrd_probe()
464 rate = clk_get_rate(clk_wzrd->axi_clk); in clk_wzrd_probe()
466 dev_err(&pdev->dev, "s_axi_aclk frequency (%lu) too high\n", in clk_wzrd_probe()
468 ret = -EINVAL; in clk_wzrd_probe()
472 reg = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(0)); in clk_wzrd_probe()
479 clk_name = kasprintf(GFP_KERNEL, "%s_mul", dev_name(&pdev->dev)); in clk_wzrd_probe()
481 ret = -ENOMEM; in clk_wzrd_probe()
485 ret = of_property_read_u32(np, "xlnx,nr-outputs", &nr_outputs); in clk_wzrd_probe()
487 ret = -EINVAL; in clk_wzrd_probe()
493 clk_wzrd->clks_internal[wzrd_clk_mul] = clk_register_fixed_factor in clk_wzrd_probe()
494 (&pdev->dev, clk_name, in clk_wzrd_probe()
495 __clk_get_name(clk_wzrd->clk_in1), in clk_wzrd_probe()
497 if (IS_ERR(clk_wzrd->clks_internal[wzrd_clk_mul])) { in clk_wzrd_probe()
498 dev_err(&pdev->dev, "unable to register fixed-factor clock\n"); in clk_wzrd_probe()
499 ret = PTR_ERR(clk_wzrd->clks_internal[wzrd_clk_mul]); in clk_wzrd_probe()
503 clk_name = kasprintf(GFP_KERNEL, "%s_mul_div", dev_name(&pdev->dev)); in clk_wzrd_probe()
505 ret = -ENOMEM; in clk_wzrd_probe()
509 ctrl_reg = clk_wzrd->base + WZRD_CLK_CFG_REG(0); in clk_wzrd_probe()
511 clk_wzrd->clks_internal[wzrd_clk_mul_div] = clk_register_divider in clk_wzrd_probe()
512 (&pdev->dev, clk_name, in clk_wzrd_probe()
513 __clk_get_name(clk_wzrd->clks_internal[wzrd_clk_mul]), in clk_wzrd_probe()
516 if (IS_ERR(clk_wzrd->clks_internal[wzrd_clk_mul_div])) { in clk_wzrd_probe()
517 dev_err(&pdev->dev, "unable to register divider clock\n"); in clk_wzrd_probe()
518 ret = PTR_ERR(clk_wzrd->clks_internal[wzrd_clk_mul_div]); in clk_wzrd_probe()
523 for (i = nr_outputs - 1; i >= 0 ; i--) { in clk_wzrd_probe()
526 clkout_name = kasprintf(GFP_KERNEL, "%s_out%d", dev_name(&pdev->dev), i); in clk_wzrd_probe()
528 ret = -ENOMEM; in clk_wzrd_probe()
533 clk_wzrd->clkout[i] = clk_wzrd_register_divf in clk_wzrd_probe()
534 (&pdev->dev, clkout_name, in clk_wzrd_probe()
536 clk_wzrd->base, (WZRD_CLK_CFG_REG(2) + i * 12), in clk_wzrd_probe()
542 clk_wzrd->clkout[i] = clk_wzrd_register_divider in clk_wzrd_probe()
543 (&pdev->dev, clkout_name, in clk_wzrd_probe()
545 clk_wzrd->base, (WZRD_CLK_CFG_REG(2) + i * 12), in clk_wzrd_probe()
550 if (IS_ERR(clk_wzrd->clkout[i])) { in clk_wzrd_probe()
554 clk_unregister(clk_wzrd->clkout[j]); in clk_wzrd_probe()
555 dev_err(&pdev->dev, in clk_wzrd_probe()
557 ret = PTR_ERR(clk_wzrd->clkout[i]); in clk_wzrd_probe()
564 clk_wzrd->clk_data.clks = clk_wzrd->clkout; in clk_wzrd_probe()
565 clk_wzrd->clk_data.clk_num = ARRAY_SIZE(clk_wzrd->clkout); in clk_wzrd_probe()
566 of_clk_add_provider(np, of_clk_src_onecell_get, &clk_wzrd->clk_data); in clk_wzrd_probe()
568 if (clk_wzrd->speed_grade) { in clk_wzrd_probe()
569 clk_wzrd->nb.notifier_call = clk_wzrd_clk_notifier; in clk_wzrd_probe()
571 ret = clk_notifier_register(clk_wzrd->clk_in1, in clk_wzrd_probe()
572 &clk_wzrd->nb); in clk_wzrd_probe()
574 dev_warn(&pdev->dev, in clk_wzrd_probe()
577 ret = clk_notifier_register(clk_wzrd->axi_clk, &clk_wzrd->nb); in clk_wzrd_probe()
579 dev_warn(&pdev->dev, in clk_wzrd_probe()
586 clk_unregister(clk_wzrd->clks_internal[1]); in clk_wzrd_probe()
589 clk_unregister(clk_wzrd->clks_internal[0]); in clk_wzrd_probe()
591 clk_disable_unprepare(clk_wzrd->axi_clk); in clk_wzrd_probe()
601 of_clk_del_provider(pdev->dev.of_node); in clk_wzrd_remove()
604 clk_unregister(clk_wzrd->clkout[i]); in clk_wzrd_remove()
606 clk_unregister(clk_wzrd->clks_internal[i]); in clk_wzrd_remove()
608 if (clk_wzrd->speed_grade) { in clk_wzrd_remove()
609 clk_notifier_unregister(clk_wzrd->axi_clk, &clk_wzrd->nb); in clk_wzrd_remove()
610 clk_notifier_unregister(clk_wzrd->clk_in1, &clk_wzrd->nb); in clk_wzrd_remove()
613 clk_disable_unprepare(clk_wzrd->axi_clk); in clk_wzrd_remove()
619 { .compatible = "xlnx,clocking-wizard" },
620 { .compatible = "xlnx,clocking-wizard-v5.2" },
621 { .compatible = "xlnx,clocking-wizard-v6.0" },
628 .name = "clk-wizard",