mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 22:54:17 -04:00
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:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user