Lines Matching +full:r8a73a4 +full:- +full:mstp +full:- +full:clocks
6 * Based on clk-mstp.c, clk-rcar-gen2.c, and clk-rcar-gen3.c
17 #include <linux/clk-provider.h>
30 #include <linux/reset-controller.h>
33 #include <dt-bindings/clock/renesas-cpg-mssr.h>
35 #include "renesas-cpg-mssr.h"
36 #include "clk-div6.h"
48 * If the registers exist, these are valid for SH-Mobile, R-Mobile,
49 * R-Car Gen2, R-Car Gen3, and RZ/G1.
50 * These are NOT valid for R-Car Gen1 and RZ/A1!
90 #define RMSTPCR(i) (smstpcr[i] - 0x20)
92 /* Modem Module Stop Control Register offsets (r8a73a4) */
106 * @clks: Array containing all Core and Module Clocks
107 * @num_core_clks: Number of Core Clocks in clks[]
108 * @num_mod_clks: Number of Module Clocks in clks[]
136 * struct mstp_clock - MSTP gating clock
137 * @hw: handle between common and hardware-specific interfaces
138 * @index: MSTP clock number
152 struct cpg_mssr_priv *priv = clock->priv; in cpg_mstp_clock_endisable()
153 unsigned int reg = clock->index / 32; in cpg_mstp_clock_endisable()
154 unsigned int bit = clock->index % 32; in cpg_mstp_clock_endisable()
155 struct device *dev = priv->dev; in cpg_mstp_clock_endisable()
161 dev_dbg(dev, "MSTP %u%02u/%pC %s\n", reg, bit, hw->clk, in cpg_mstp_clock_endisable()
163 spin_lock_irqsave(&priv->rmw_lock, flags); in cpg_mstp_clock_endisable()
165 value = readl(priv->base + SMSTPCR(reg)); in cpg_mstp_clock_endisable()
170 writel(value, priv->base + SMSTPCR(reg)); in cpg_mstp_clock_endisable()
172 spin_unlock_irqrestore(&priv->rmw_lock, flags); in cpg_mstp_clock_endisable()
177 for (i = 1000; i > 0; --i) { in cpg_mstp_clock_endisable()
178 if (!(readl(priv->base + MSTPSR(reg)) & bitmask)) in cpg_mstp_clock_endisable()
185 priv->base + SMSTPCR(reg), bit); in cpg_mstp_clock_endisable()
186 return -ETIMEDOUT; in cpg_mstp_clock_endisable()
205 struct cpg_mssr_priv *priv = clock->priv; in cpg_mstp_clock_is_enabled()
208 value = readl(priv->base + MSTPSR(clock->index / 32)); in cpg_mstp_clock_is_enabled()
210 return !(value & BIT(clock->index % 32)); in cpg_mstp_clock_is_enabled()
223 unsigned int clkidx = clkspec->args[1]; in cpg_mssr_clk_src_twocell_get()
225 struct device *dev = priv->dev; in cpg_mssr_clk_src_twocell_get()
230 switch (clkspec->args[0]) { in cpg_mssr_clk_src_twocell_get()
233 if (clkidx > priv->last_dt_core_clk) { in cpg_mssr_clk_src_twocell_get()
236 return ERR_PTR(-EINVAL); in cpg_mssr_clk_src_twocell_get()
238 clk = priv->clks[clkidx]; in cpg_mssr_clk_src_twocell_get()
244 if (clkidx % 100 > 31 || idx >= priv->num_mod_clks) { in cpg_mssr_clk_src_twocell_get()
247 return ERR_PTR(-EINVAL); in cpg_mssr_clk_src_twocell_get()
249 clk = priv->clks[priv->num_core_clks + idx]; in cpg_mssr_clk_src_twocell_get()
253 dev_err(dev, "Invalid CPG clock type %u\n", clkspec->args[0]); in cpg_mssr_clk_src_twocell_get()
254 return ERR_PTR(-EINVAL); in cpg_mssr_clk_src_twocell_get()
262 clkspec->args[0], clkspec->args[1], clk, in cpg_mssr_clk_src_twocell_get()
271 struct clk *clk = ERR_PTR(-ENOTSUPP), *parent; in cpg_mssr_register_core_clk()
272 struct device *dev = priv->dev; in cpg_mssr_register_core_clk()
273 unsigned int id = core->id, div = core->div; in cpg_mssr_register_core_clk()
276 WARN_DEBUG(id >= priv->num_core_clks); in cpg_mssr_register_core_clk()
277 WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT); in cpg_mssr_register_core_clk()
279 if (!core->name) { in cpg_mssr_register_core_clk()
284 switch (core->type) { in cpg_mssr_register_core_clk()
286 clk = of_clk_get_by_name(priv->dev->of_node, core->name); in cpg_mssr_register_core_clk()
292 WARN_DEBUG(core->parent >= priv->num_core_clks); in cpg_mssr_register_core_clk()
293 parent = priv->clks[core->parent]; in cpg_mssr_register_core_clk()
301 if (core->type == CLK_TYPE_DIV6_RO) in cpg_mssr_register_core_clk()
303 div *= (readl(priv->base + core->offset) & 0x3f) + 1; in cpg_mssr_register_core_clk()
305 if (core->type == CLK_TYPE_DIV6P1) { in cpg_mssr_register_core_clk()
306 clk = cpg_div6_register(core->name, 1, &parent_name, in cpg_mssr_register_core_clk()
307 priv->base + core->offset, in cpg_mssr_register_core_clk()
308 &priv->notifiers); in cpg_mssr_register_core_clk()
310 clk = clk_register_fixed_factor(NULL, core->name, in cpg_mssr_register_core_clk()
312 core->mult, div); in cpg_mssr_register_core_clk()
317 if (info->cpg_clk_register) in cpg_mssr_register_core_clk()
318 clk = info->cpg_clk_register(dev, core, info, in cpg_mssr_register_core_clk()
319 priv->clks, priv->base, in cpg_mssr_register_core_clk()
320 &priv->notifiers); in cpg_mssr_register_core_clk()
323 core->name, core->type); in cpg_mssr_register_core_clk()
331 priv->clks[id] = clk; in cpg_mssr_register_core_clk()
336 core->name, PTR_ERR(clk)); in cpg_mssr_register_core_clk()
344 struct device *dev = priv->dev; in cpg_mssr_register_mod_clk()
345 unsigned int id = mod->id; in cpg_mssr_register_mod_clk()
351 WARN_DEBUG(id < priv->num_core_clks); in cpg_mssr_register_mod_clk()
352 WARN_DEBUG(id >= priv->num_core_clks + priv->num_mod_clks); in cpg_mssr_register_mod_clk()
353 WARN_DEBUG(mod->parent >= priv->num_core_clks + priv->num_mod_clks); in cpg_mssr_register_mod_clk()
354 WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT); in cpg_mssr_register_mod_clk()
356 if (!mod->name) { in cpg_mssr_register_mod_clk()
361 parent = priv->clks[mod->parent]; in cpg_mssr_register_mod_clk()
369 clk = ERR_PTR(-ENOMEM); in cpg_mssr_register_mod_clk()
373 init.name = mod->name; in cpg_mssr_register_mod_clk()
376 for (i = 0; i < info->num_crit_mod_clks; i++) in cpg_mssr_register_mod_clk()
377 if (id == info->crit_mod_clks[i]) { in cpg_mssr_register_mod_clk()
378 dev_dbg(dev, "MSTP %s setting CLK_IS_CRITICAL\n", in cpg_mssr_register_mod_clk()
379 mod->name); in cpg_mssr_register_mod_clk()
388 clock->index = id - priv->num_core_clks; in cpg_mssr_register_mod_clk()
389 clock->priv = priv; in cpg_mssr_register_mod_clk()
390 clock->hw.init = &init; in cpg_mssr_register_mod_clk()
392 clk = clk_register(NULL, &clock->hw); in cpg_mssr_register_mod_clk()
397 priv->clks[id] = clk; in cpg_mssr_register_mod_clk()
398 priv->smstpcr_saved[clock->index / 32].mask |= BIT(clock->index % 32); in cpg_mssr_register_mod_clk()
403 mod->name, PTR_ERR(clk)); in cpg_mssr_register_mod_clk()
421 if (clkspec->np != pd->np || clkspec->args_count != 2) in cpg_mssr_is_pm_clk()
424 switch (clkspec->args[0]) { in cpg_mssr_is_pm_clk()
426 for (i = 0; i < pd->num_core_pm_clks; i++) in cpg_mssr_is_pm_clk()
427 if (clkspec->args[1] == pd->core_pm_clks[i]) in cpg_mssr_is_pm_clk()
442 struct device_node *np = dev->of_node; in cpg_mssr_attach_dev()
450 return -EPROBE_DEFER; in cpg_mssr_attach_dev()
453 while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i, in cpg_mssr_attach_dev()
502 struct device_node *np = dev->of_node; in cpg_mssr_add_clk_domain()
509 return -ENOMEM; in cpg_mssr_add_clk_domain()
511 pd->np = np; in cpg_mssr_add_clk_domain()
512 pd->num_core_pm_clks = num_core_pm_clks; in cpg_mssr_add_clk_domain()
513 memcpy(pd->core_pm_clks, core_pm_clks, pm_size); in cpg_mssr_add_clk_domain()
515 genpd = &pd->genpd; in cpg_mssr_add_clk_domain()
516 genpd->name = np->name; in cpg_mssr_add_clk_domain()
517 genpd->flags = GENPD_FLAG_PM_CLK | GENPD_FLAG_ALWAYS_ON | in cpg_mssr_add_clk_domain()
519 genpd->attach_dev = cpg_mssr_attach_dev; in cpg_mssr_add_clk_domain()
520 genpd->detach_dev = cpg_mssr_detach_dev; in cpg_mssr_add_clk_domain()
540 dev_dbg(priv->dev, "reset %u%02u\n", reg, bit); in cpg_mssr_reset()
543 writel(bitmask, priv->base + SRCR(reg)); in cpg_mssr_reset()
549 writel(bitmask, priv->base + SRSTCLR(reg)); in cpg_mssr_reset()
561 dev_dbg(priv->dev, "assert %u%02u\n", reg, bit); in cpg_mssr_assert()
563 writel(bitmask, priv->base + SRCR(reg)); in cpg_mssr_assert()
575 dev_dbg(priv->dev, "deassert %u%02u\n", reg, bit); in cpg_mssr_deassert()
577 writel(bitmask, priv->base + SRSTCLR(reg)); in cpg_mssr_deassert()
589 return !!(readl(priv->base + SRCR(reg)) & bitmask); in cpg_mssr_status()
603 unsigned int unpacked = reset_spec->args[0]; in cpg_mssr_reset_xlate()
606 if (unpacked % 100 > 31 || idx >= rcdev->nr_resets) { in cpg_mssr_reset_xlate()
607 dev_err(priv->dev, "Invalid reset index %u\n", unpacked); in cpg_mssr_reset_xlate()
608 return -EINVAL; in cpg_mssr_reset_xlate()
616 priv->rcdev.ops = &cpg_mssr_reset_ops; in cpg_mssr_reset_controller_register()
617 priv->rcdev.of_node = priv->dev->of_node; in cpg_mssr_reset_controller_register()
618 priv->rcdev.of_reset_n_cells = 1; in cpg_mssr_reset_controller_register()
619 priv->rcdev.of_xlate = cpg_mssr_reset_xlate; in cpg_mssr_reset_controller_register()
620 priv->rcdev.nr_resets = priv->num_mod_clks; in cpg_mssr_reset_controller_register()
621 return devm_reset_controller_register(priv->dev, &priv->rcdev); in cpg_mssr_reset_controller_register()
635 .compatible = "renesas,r8a7743-cpg-mssr",
641 .compatible = "renesas,r8a7745-cpg-mssr",
647 .compatible = "renesas,r8a77470-cpg-mssr",
653 .compatible = "renesas,r8a7790-cpg-mssr",
659 .compatible = "renesas,r8a7791-cpg-mssr",
662 /* R-Car M2-N is (almost) identical to R-Car M2-W w.r.t. clocks. */
664 .compatible = "renesas,r8a7793-cpg-mssr",
670 .compatible = "renesas,r8a7792-cpg-mssr",
676 .compatible = "renesas,r8a7794-cpg-mssr",
682 .compatible = "renesas,r8a7795-cpg-mssr",
688 .compatible = "renesas,r8a7796-cpg-mssr",
694 .compatible = "renesas,r8a77965-cpg-mssr",
700 .compatible = "renesas,r8a77970-cpg-mssr",
706 .compatible = "renesas,r8a77980-cpg-mssr",
712 .compatible = "renesas,r8a77990-cpg-mssr",
718 .compatible = "renesas,r8a77995-cpg-mssr",
741 for (reg = 0; reg < ARRAY_SIZE(priv->smstpcr_saved); reg++) { in cpg_mssr_suspend_noirq()
742 if (priv->smstpcr_saved[reg].mask) in cpg_mssr_suspend_noirq()
743 priv->smstpcr_saved[reg].val = in cpg_mssr_suspend_noirq()
744 readl(priv->base + SMSTPCR(reg)); in cpg_mssr_suspend_noirq()
747 /* Save core clocks */ in cpg_mssr_suspend_noirq()
748 raw_notifier_call_chain(&priv->notifiers, PM_EVENT_SUSPEND, NULL); in cpg_mssr_suspend_noirq()
763 /* Restore core clocks */ in cpg_mssr_resume_noirq()
764 raw_notifier_call_chain(&priv->notifiers, PM_EVENT_RESUME, NULL); in cpg_mssr_resume_noirq()
766 /* Restore module clocks */ in cpg_mssr_resume_noirq()
767 for (reg = 0; reg < ARRAY_SIZE(priv->smstpcr_saved); reg++) { in cpg_mssr_resume_noirq()
768 mask = priv->smstpcr_saved[reg].mask; in cpg_mssr_resume_noirq()
772 oldval = readl(priv->base + SMSTPCR(reg)); in cpg_mssr_resume_noirq()
774 newval |= priv->smstpcr_saved[reg].val & mask; in cpg_mssr_resume_noirq()
778 writel(newval, priv->base + SMSTPCR(reg)); in cpg_mssr_resume_noirq()
780 /* Wait until enabled clocks are really enabled */ in cpg_mssr_resume_noirq()
781 mask &= ~priv->smstpcr_saved[reg].val; in cpg_mssr_resume_noirq()
785 for (i = 1000; i > 0; --i) { in cpg_mssr_resume_noirq()
786 oldval = readl(priv->base + MSTPSR(reg)); in cpg_mssr_resume_noirq()
794 priv->base + SMSTPCR(reg), oldval & mask); in cpg_mssr_resume_noirq()
811 struct device *dev = &pdev->dev; in cpg_mssr_probe()
812 struct device_node *np = dev->of_node; in cpg_mssr_probe()
821 if (info->init) { in cpg_mssr_probe()
822 error = info->init(dev); in cpg_mssr_probe()
829 return -ENOMEM; in cpg_mssr_probe()
831 priv->dev = dev; in cpg_mssr_probe()
832 spin_lock_init(&priv->rmw_lock); in cpg_mssr_probe()
835 priv->base = devm_ioremap_resource(dev, res); in cpg_mssr_probe()
836 if (IS_ERR(priv->base)) in cpg_mssr_probe()
837 return PTR_ERR(priv->base); in cpg_mssr_probe()
839 nclks = info->num_total_core_clks + info->num_hw_mod_clks; in cpg_mssr_probe()
842 return -ENOMEM; in cpg_mssr_probe()
845 priv->clks = clks; in cpg_mssr_probe()
846 priv->num_core_clks = info->num_total_core_clks; in cpg_mssr_probe()
847 priv->num_mod_clks = info->num_hw_mod_clks; in cpg_mssr_probe()
848 priv->last_dt_core_clk = info->last_dt_core_clk; in cpg_mssr_probe()
849 RAW_INIT_NOTIFIER_HEAD(&priv->notifiers); in cpg_mssr_probe()
852 clks[i] = ERR_PTR(-ENOENT); in cpg_mssr_probe()
854 for (i = 0; i < info->num_core_clks; i++) in cpg_mssr_probe()
855 cpg_mssr_register_core_clk(&info->core_clks[i], info, priv); in cpg_mssr_probe()
857 for (i = 0; i < info->num_mod_clks; i++) in cpg_mssr_probe()
858 cpg_mssr_register_mod_clk(&info->mod_clks[i], info, priv); in cpg_mssr_probe()
870 error = cpg_mssr_add_clk_domain(dev, info->core_pm_clks, in cpg_mssr_probe()
871 info->num_core_pm_clks); in cpg_mssr_probe()
884 .name = "renesas-cpg-mssr",