Lines Matching +full:r9a09g057 +full:- +full:cpg
1 // SPDX-License-Identifier: GPL-2.0
7 * Based on rzg2l-cpg.c
16 #include <linux/clk-provider.h>
26 #include <linux/reset-controller.h>
28 #include <dt-bindings/clock/renesas-cpg-mssr.h>
30 #include "rzv2h-cpg.h"
56 * struct rzv2h_cpg_priv - Clock Pulse Generator Private Data
58 * @dev: CPG device
59 * @base: CPG register block base address
65 * @num_resets: Number of Module Resets in info->resets[]
97 * struct mod_clock - Module clock
99 * @priv: CPG private data
100 * @hw: handle between common and hardware-specific interfaces
118 * struct ddiv_clk - DDIV clock
120 * @priv: CPG private data
136 struct rzv2h_cpg_priv *priv = pll_clk->priv; in rzv2h_cpg_pll_clk_recalc_rate()
140 if (!PLL_CLK_ACCESS(pll_clk->conf)) in rzv2h_cpg_pll_clk_recalc_rate()
143 clk1 = readl(priv->base + PLL_CLK1_OFFSET(pll_clk->conf)); in rzv2h_cpg_pll_clk_recalc_rate()
144 clk2 = readl(priv->base + PLL_CLK2_OFFSET(pll_clk->conf)); in rzv2h_cpg_pll_clk_recalc_rate()
161 void __iomem *base = priv->base; in rzv2h_cpg_pll_clk_register()
162 struct device *dev = priv->dev; in rzv2h_cpg_pll_clk_register()
169 parent = priv->clks[core->parent]; in rzv2h_cpg_pll_clk_register()
175 return ERR_PTR(-ENOMEM); in rzv2h_cpg_pll_clk_register()
178 init.name = core->name; in rzv2h_cpg_pll_clk_register()
184 pll_clk->hw.init = &init; in rzv2h_cpg_pll_clk_register()
185 pll_clk->conf = core->cfg.conf; in rzv2h_cpg_pll_clk_register()
186 pll_clk->base = base; in rzv2h_cpg_pll_clk_register()
187 pll_clk->priv = priv; in rzv2h_cpg_pll_clk_register()
188 pll_clk->type = core->type; in rzv2h_cpg_pll_clk_register()
190 ret = devm_clk_hw_register(dev, &pll_clk->hw); in rzv2h_cpg_pll_clk_register()
194 return pll_clk->hw.clk; in rzv2h_cpg_pll_clk_register()
203 val = readl(divider->reg) >> divider->shift; in rzv2h_ddiv_recalc_rate()
204 val &= clk_div_mask(divider->width); in rzv2h_ddiv_recalc_rate()
206 return divider_recalc_rate(hw, parent_rate, val, divider->table, in rzv2h_ddiv_recalc_rate()
207 divider->flags, divider->width); in rzv2h_ddiv_recalc_rate()
215 return divider_round_rate(hw, rate, prate, divider->table, in rzv2h_ddiv_round_rate()
216 divider->width, divider->flags); in rzv2h_ddiv_round_rate()
224 return divider_determine_rate(hw, req, divider->table, divider->width, in rzv2h_ddiv_determine_rate()
225 divider->flags); in rzv2h_ddiv_determine_rate()
241 struct rzv2h_cpg_priv *priv = ddiv->priv; in rzv2h_ddiv_set_rate()
247 value = divider_get_val(rate, parent_rate, divider->table, in rzv2h_ddiv_set_rate()
248 divider->width, divider->flags); in rzv2h_ddiv_set_rate()
252 spin_lock_irqsave(divider->lock, flags); in rzv2h_ddiv_set_rate()
254 ret = rzv2h_cpg_wait_ddiv_clk_update_done(priv->base, ddiv->mon); in rzv2h_ddiv_set_rate()
258 val = readl(divider->reg) | DDIV_DIVCTL_WEN(divider->shift); in rzv2h_ddiv_set_rate()
259 val &= ~(clk_div_mask(divider->width) << divider->shift); in rzv2h_ddiv_set_rate()
260 val |= (u32)value << divider->shift; in rzv2h_ddiv_set_rate()
261 writel(val, divider->reg); in rzv2h_ddiv_set_rate()
263 ret = rzv2h_cpg_wait_ddiv_clk_update_done(priv->base, ddiv->mon); in rzv2h_ddiv_set_rate()
267 spin_unlock_irqrestore(divider->lock, flags); in rzv2h_ddiv_set_rate()
272 spin_unlock_irqrestore(divider->lock, flags); in rzv2h_ddiv_set_rate()
287 struct ddiv cfg_ddiv = core->cfg.ddiv; in rzv2h_cpg_ddiv_clk_register()
289 struct device *dev = priv->dev; in rzv2h_cpg_ddiv_clk_register()
298 parent = priv->clks[core->parent]; in rzv2h_cpg_ddiv_clk_register()
305 return ERR_PTR(-EINVAL); in rzv2h_cpg_ddiv_clk_register()
307 ddiv = devm_kzalloc(priv->dev, sizeof(*ddiv), GFP_KERNEL); in rzv2h_cpg_ddiv_clk_register()
309 return ERR_PTR(-ENOMEM); in rzv2h_cpg_ddiv_clk_register()
311 init.name = core->name; in rzv2h_cpg_ddiv_clk_register()
316 ddiv->priv = priv; in rzv2h_cpg_ddiv_clk_register()
317 ddiv->mon = cfg_ddiv.monbit; in rzv2h_cpg_ddiv_clk_register()
318 div = &ddiv->div; in rzv2h_cpg_ddiv_clk_register()
319 div->reg = priv->base + cfg_ddiv.offset; in rzv2h_cpg_ddiv_clk_register()
320 div->shift = shift; in rzv2h_cpg_ddiv_clk_register()
321 div->width = width; in rzv2h_cpg_ddiv_clk_register()
322 div->flags = core->flag; in rzv2h_cpg_ddiv_clk_register()
323 div->lock = &priv->rmw_lock; in rzv2h_cpg_ddiv_clk_register()
324 div->hw.init = &init; in rzv2h_cpg_ddiv_clk_register()
325 div->table = core->dtable; in rzv2h_cpg_ddiv_clk_register()
327 ret = devm_clk_hw_register(dev, &div->hw); in rzv2h_cpg_ddiv_clk_register()
331 return div->hw.clk; in rzv2h_cpg_ddiv_clk_register()
338 unsigned int clkidx = clkspec->args[1]; in rzv2h_cpg_clk_src_twocell_get()
340 struct device *dev = priv->dev; in rzv2h_cpg_clk_src_twocell_get()
344 switch (clkspec->args[0]) { in rzv2h_cpg_clk_src_twocell_get()
347 if (clkidx > priv->last_dt_core_clk) { in rzv2h_cpg_clk_src_twocell_get()
349 return ERR_PTR(-EINVAL); in rzv2h_cpg_clk_src_twocell_get()
351 clk = priv->clks[clkidx]; in rzv2h_cpg_clk_src_twocell_get()
356 if (clkidx >= priv->num_mod_clks) { in rzv2h_cpg_clk_src_twocell_get()
358 return ERR_PTR(-EINVAL); in rzv2h_cpg_clk_src_twocell_get()
360 clk = priv->clks[priv->num_core_clks + clkidx]; in rzv2h_cpg_clk_src_twocell_get()
364 dev_err(dev, "Invalid CPG clock type %u\n", clkspec->args[0]); in rzv2h_cpg_clk_src_twocell_get()
365 return ERR_PTR(-EINVAL); in rzv2h_cpg_clk_src_twocell_get()
373 clkspec->args[0], clkspec->args[1], clk, in rzv2h_cpg_clk_src_twocell_get()
382 struct clk *clk = ERR_PTR(-EOPNOTSUPP), *parent; in rzv2h_cpg_register_core_clk()
383 unsigned int id = core->id, div = core->div; in rzv2h_cpg_register_core_clk()
384 struct device *dev = priv->dev; in rzv2h_cpg_register_core_clk()
388 WARN_DEBUG(id >= priv->num_core_clks); in rzv2h_cpg_register_core_clk()
389 WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT); in rzv2h_cpg_register_core_clk()
391 switch (core->type) { in rzv2h_cpg_register_core_clk()
393 clk = of_clk_get_by_name(priv->dev->of_node, core->name); in rzv2h_cpg_register_core_clk()
396 WARN_DEBUG(core->parent >= priv->num_core_clks); in rzv2h_cpg_register_core_clk()
397 parent = priv->clks[core->parent]; in rzv2h_cpg_register_core_clk()
404 clk_hw = devm_clk_hw_register_fixed_factor(dev, core->name, in rzv2h_cpg_register_core_clk()
406 core->mult, div); in rzv2h_cpg_register_core_clk()
410 clk = clk_hw->clk; in rzv2h_cpg_register_core_clk()
426 priv->clks[id] = clk; in rzv2h_cpg_register_core_clk()
431 core->name, PTR_ERR(clk)); in rzv2h_cpg_register_core_clk()
437 unsigned int reg = GET_CLK_ON_OFFSET(clock->on_index); in rzv2h_mod_clock_endisable()
438 struct rzv2h_cpg_priv *priv = clock->priv; in rzv2h_mod_clock_endisable()
439 u32 bitmask = BIT(clock->on_bit); in rzv2h_mod_clock_endisable()
440 struct device *dev = priv->dev; in rzv2h_mod_clock_endisable()
444 dev_dbg(dev, "CLK_ON 0x%x/%pC %s\n", reg, hw->clk, in rzv2h_mod_clock_endisable()
451 writel(value, priv->base + reg); in rzv2h_mod_clock_endisable()
453 if (!enable || clock->mon_index < 0) in rzv2h_mod_clock_endisable()
456 reg = GET_CLK_MON_OFFSET(clock->mon_index); in rzv2h_mod_clock_endisable()
457 bitmask = BIT(clock->mon_bit); in rzv2h_mod_clock_endisable()
458 error = readl_poll_timeout_atomic(priv->base + reg, value, in rzv2h_mod_clock_endisable()
462 priv->base + reg); in rzv2h_mod_clock_endisable()
480 struct rzv2h_cpg_priv *priv = clock->priv; in rzv2h_mod_clock_is_enabled()
484 if (clock->mon_index >= 0) { in rzv2h_mod_clock_is_enabled()
485 offset = GET_CLK_MON_OFFSET(clock->mon_index); in rzv2h_mod_clock_is_enabled()
486 bitmask = BIT(clock->mon_bit); in rzv2h_mod_clock_is_enabled()
488 offset = GET_CLK_ON_OFFSET(clock->on_index); in rzv2h_mod_clock_is_enabled()
489 bitmask = BIT(clock->on_bit); in rzv2h_mod_clock_is_enabled()
492 return readl(priv->base + offset) & bitmask; in rzv2h_mod_clock_is_enabled()
506 struct device *dev = priv->dev; in rzv2h_cpg_register_mod_clk()
513 id = GET_MOD_CLK_ID(priv->num_core_clks, mod->on_index, mod->on_bit); in rzv2h_cpg_register_mod_clk()
514 WARN_DEBUG(id >= priv->num_core_clks + priv->num_mod_clks); in rzv2h_cpg_register_mod_clk()
515 WARN_DEBUG(mod->parent >= priv->num_core_clks + priv->num_mod_clks); in rzv2h_cpg_register_mod_clk()
516 WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT); in rzv2h_cpg_register_mod_clk()
518 parent = priv->clks[mod->parent]; in rzv2h_cpg_register_mod_clk()
526 clk = ERR_PTR(-ENOMEM); in rzv2h_cpg_register_mod_clk()
530 init.name = mod->name; in rzv2h_cpg_register_mod_clk()
533 if (mod->critical) in rzv2h_cpg_register_mod_clk()
540 clock->on_index = mod->on_index; in rzv2h_cpg_register_mod_clk()
541 clock->on_bit = mod->on_bit; in rzv2h_cpg_register_mod_clk()
542 clock->mon_index = mod->mon_index; in rzv2h_cpg_register_mod_clk()
543 clock->mon_bit = mod->mon_bit; in rzv2h_cpg_register_mod_clk()
544 clock->priv = priv; in rzv2h_cpg_register_mod_clk()
545 clock->hw.init = &init; in rzv2h_cpg_register_mod_clk()
547 ret = devm_clk_hw_register(dev, &clock->hw); in rzv2h_cpg_register_mod_clk()
553 priv->clks[id] = clock->hw.clk; in rzv2h_cpg_register_mod_clk()
559 mod->name, PTR_ERR(clk)); in rzv2h_cpg_register_mod_clk()
566 unsigned int reg = GET_RST_OFFSET(priv->resets[id].reset_index); in rzv2h_cpg_assert()
567 u32 mask = BIT(priv->resets[id].reset_bit); in rzv2h_cpg_assert()
568 u8 monbit = priv->resets[id].mon_bit; in rzv2h_cpg_assert()
571 dev_dbg(rcdev->dev, "assert id:%ld offset:0x%x\n", id, reg); in rzv2h_cpg_assert()
573 writel(value, priv->base + reg); in rzv2h_cpg_assert()
575 reg = GET_RST_MON_OFFSET(priv->resets[id].mon_index); in rzv2h_cpg_assert()
578 return readl_poll_timeout_atomic(priv->base + reg, value, in rzv2h_cpg_assert()
586 unsigned int reg = GET_RST_OFFSET(priv->resets[id].reset_index); in rzv2h_cpg_deassert()
587 u32 mask = BIT(priv->resets[id].reset_bit); in rzv2h_cpg_deassert()
588 u8 monbit = priv->resets[id].mon_bit; in rzv2h_cpg_deassert()
591 dev_dbg(rcdev->dev, "deassert id:%ld offset:0x%x\n", id, reg); in rzv2h_cpg_deassert()
593 writel(value, priv->base + reg); in rzv2h_cpg_deassert()
595 reg = GET_RST_MON_OFFSET(priv->resets[id].mon_index); in rzv2h_cpg_deassert()
598 return readl_poll_timeout_atomic(priv->base + reg, value, in rzv2h_cpg_deassert()
618 unsigned int reg = GET_RST_MON_OFFSET(priv->resets[id].mon_index); in rzv2h_cpg_status()
619 u8 monbit = priv->resets[id].mon_bit; in rzv2h_cpg_status()
621 return !!(readl(priv->base + reg) & BIT(monbit)); in rzv2h_cpg_status()
635 unsigned int id = reset_spec->args[0]; in rzv2h_cpg_reset_xlate()
640 for (i = 0; i < rcdev->nr_resets; i++) { in rzv2h_cpg_reset_xlate()
641 if (rst_index == priv->resets[i].reset_index && in rzv2h_cpg_reset_xlate()
642 rst_bit == priv->resets[i].reset_bit) in rzv2h_cpg_reset_xlate()
646 return -EINVAL; in rzv2h_cpg_reset_xlate()
651 priv->rcdev.ops = &rzv2h_cpg_reset_ops; in rzv2h_cpg_reset_controller_register()
652 priv->rcdev.of_node = priv->dev->of_node; in rzv2h_cpg_reset_controller_register()
653 priv->rcdev.dev = priv->dev; in rzv2h_cpg_reset_controller_register()
654 priv->rcdev.of_reset_n_cells = 1; in rzv2h_cpg_reset_controller_register()
655 priv->rcdev.of_xlate = rzv2h_cpg_reset_xlate; in rzv2h_cpg_reset_controller_register()
656 priv->rcdev.nr_resets = priv->num_resets; in rzv2h_cpg_reset_controller_register()
658 return devm_reset_controller_register(priv->dev, &priv->rcdev); in rzv2h_cpg_reset_controller_register()
662 * struct rzv2h_cpg_pd - RZ/V2H power domain data structure
663 * @priv: pointer to CPG private data structure
673 struct device_node *np = dev->of_node; in rzv2h_cpg_attach_dev()
680 while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i, in rzv2h_cpg_attach_dev()
730 struct device *dev = priv->dev; in rzv2h_cpg_add_pm_domains()
731 struct device_node *np = dev->of_node; in rzv2h_cpg_add_pm_domains()
737 return -ENOMEM; in rzv2h_cpg_add_pm_domains()
739 pd->genpd.name = np->name; in rzv2h_cpg_add_pm_domains()
740 pd->priv = priv; in rzv2h_cpg_add_pm_domains()
741 pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON | GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP; in rzv2h_cpg_add_pm_domains()
742 pd->genpd.attach_dev = rzv2h_cpg_attach_dev; in rzv2h_cpg_add_pm_domains()
743 pd->genpd.detach_dev = rzv2h_cpg_detach_dev; in rzv2h_cpg_add_pm_domains()
744 ret = pm_genpd_init(&pd->genpd, &pm_domain_always_on_gov, false); in rzv2h_cpg_add_pm_domains()
748 ret = devm_add_action_or_reset(dev, rzv2h_cpg_genpd_remove_simple, &pd->genpd); in rzv2h_cpg_add_pm_domains()
752 return of_genpd_add_provider_simple(np, &pd->genpd); in rzv2h_cpg_add_pm_domains()
762 struct device *dev = &pdev->dev; in rzv2h_cpg_probe()
763 struct device_node *np = dev->of_node; in rzv2h_cpg_probe()
774 return -ENOMEM; in rzv2h_cpg_probe()
776 spin_lock_init(&priv->rmw_lock); in rzv2h_cpg_probe()
778 priv->dev = dev; in rzv2h_cpg_probe()
780 priv->base = devm_platform_ioremap_resource(pdev, 0); in rzv2h_cpg_probe()
781 if (IS_ERR(priv->base)) in rzv2h_cpg_probe()
782 return PTR_ERR(priv->base); in rzv2h_cpg_probe()
784 nclks = info->num_total_core_clks + info->num_hw_mod_clks; in rzv2h_cpg_probe()
787 return -ENOMEM; in rzv2h_cpg_probe()
789 priv->resets = devm_kmemdup(dev, info->resets, sizeof(*info->resets) * in rzv2h_cpg_probe()
790 info->num_resets, GFP_KERNEL); in rzv2h_cpg_probe()
791 if (!priv->resets) in rzv2h_cpg_probe()
792 return -ENOMEM; in rzv2h_cpg_probe()
795 priv->clks = clks; in rzv2h_cpg_probe()
796 priv->num_core_clks = info->num_total_core_clks; in rzv2h_cpg_probe()
797 priv->num_mod_clks = info->num_hw_mod_clks; in rzv2h_cpg_probe()
798 priv->last_dt_core_clk = info->last_dt_core_clk; in rzv2h_cpg_probe()
799 priv->num_resets = info->num_resets; in rzv2h_cpg_probe()
802 clks[i] = ERR_PTR(-ENOENT); in rzv2h_cpg_probe()
804 for (i = 0; i < info->num_core_clks; i++) in rzv2h_cpg_probe()
805 rzv2h_cpg_register_core_clk(&info->core_clks[i], priv); in rzv2h_cpg_probe()
807 for (i = 0; i < info->num_mod_clks; i++) in rzv2h_cpg_probe()
808 rzv2h_cpg_register_mod_clk(&info->mod_clks[i], priv); in rzv2h_cpg_probe()
832 .compatible = "renesas,r9a09g057-cpg",
841 .name = "rzv2h-cpg",
853 MODULE_DESCRIPTION("Renesas RZ/V2H CPG Driver");