clk: conf: Support assigned-clock-sscs

Parse the Spread Spectrum Configuration(SSC) from device tree and configure
them before using the clock.

Each SSC is three u32 elements which means '<modfreq spreaddepth
modmethod>', so assigned-clock-sscs is an array of multiple three u32
elements.

Reviewed-by: Brian Masney <bmasney@redhat.com>
Reviewed-by: Sebin Francis <sebin.francis@ti.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
Signed-off-by: Brian Masney <bmasney@redhat.com>
This commit is contained in:
Peng Fan
2026-06-12 16:46:25 +08:00
committed by Brian Masney
parent c86814e703
commit a7f16660af

View File

@@ -155,6 +155,78 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier)
return 0;
}
static int __set_clk_spread_spectrum(struct device_node *node, bool clk_supplier)
{
u32 elem_size = sizeof(struct clk_spread_spectrum);
struct clk_spread_spectrum *sscs;
struct of_phandle_args clkspec;
int rc, count, index;
struct clk *clk;
/* modfreq, spreadPercent, modmethod */
count = of_property_count_elems_of_size(node, "assigned-clock-sscs", elem_size);
if (count <= 0)
return 0;
sscs = kcalloc(count, elem_size, GFP_KERNEL);
if (!sscs)
return -ENOMEM;
rc = of_property_read_u32_array(node, "assigned-clock-sscs", (u32 *)sscs,
count * 3);
if (rc)
goto free_sscs;
for (index = 0; index < count; index++) {
struct clk_spread_spectrum *conf = &sscs[index];
struct clk_hw *hw;
if (!conf->modfreq_hz && !conf->spread_bp && !conf->method)
continue;
rc = of_parse_phandle_with_args(node, "assigned-clocks", "#clock-cells",
index, &clkspec);
if (rc < 0) {
/* skip empty (null) phandles */
if (rc == -ENOENT) {
rc = 0;
continue;
} else
goto free_sscs;
}
if (clkspec.np == node && !clk_supplier) {
of_node_put(clkspec.np);
goto free_sscs;
}
clk = of_clk_get_from_provider(&clkspec);
of_node_put(clkspec.np);
if (IS_ERR(clk)) {
if (PTR_ERR(clk) != -EPROBE_DEFER)
pr_warn("clk: couldn't get clock %d for %pOF\n",
index, node);
rc = PTR_ERR(clk);
goto free_sscs;
}
hw = __clk_get_hw(clk);
rc = clk_hw_set_spread_spectrum(hw, conf);
if (rc < 0) {
pr_err("clk: couldn't set %s clk spread spectrum %u %u %u: %d\n",
__clk_get_name(clk), conf->modfreq_hz, conf->spread_bp,
conf->method, rc);
/* Do not fail */
rc = 0;
}
clk_put(clk);
}
free_sscs:
kfree(sscs);
return rc;
}
/**
* of_clk_set_defaults() - parse and set assigned clocks configuration
* @node: device node to apply clock settings for
@@ -174,6 +246,10 @@ int of_clk_set_defaults(struct device_node *node, bool clk_supplier)
if (!node)
return 0;
rc = __set_clk_spread_spectrum(node, clk_supplier);
if (rc < 0)
return rc;
rc = __set_clk_parents(node, clk_supplier);
if (rc < 0)
return rc;