1ebafb63dSStephen Boyd // SPDX-License-Identifier: GPL-2.0
286be408bSSylwester Nawrocki /*
386be408bSSylwester Nawrocki * Copyright (C) 2014 Samsung Electronics Co., Ltd.
486be408bSSylwester Nawrocki * Sylwester Nawrocki <s.nawrocki@samsung.com>
586be408bSSylwester Nawrocki */
686be408bSSylwester Nawrocki
786be408bSSylwester Nawrocki #include <linux/clk.h>
886be408bSSylwester Nawrocki #include <linux/clk-provider.h>
986be408bSSylwester Nawrocki #include <linux/clk/clk-conf.h>
1086be408bSSylwester Nawrocki #include <linux/device.h>
1186be408bSSylwester Nawrocki #include <linux/of.h>
1286be408bSSylwester Nawrocki #include <linux/printk.h>
1386be408bSSylwester Nawrocki
__set_clk_parents(struct device_node * node,bool clk_supplier)1486be408bSSylwester Nawrocki static int __set_clk_parents(struct device_node *node, bool clk_supplier)
1586be408bSSylwester Nawrocki {
1686be408bSSylwester Nawrocki struct of_phandle_args clkspec;
1786be408bSSylwester Nawrocki int index, rc, num_parents;
1886be408bSSylwester Nawrocki struct clk *clk, *pclk;
1986be408bSSylwester Nawrocki
2086be408bSSylwester Nawrocki num_parents = of_count_phandle_with_args(node, "assigned-clock-parents",
2186be408bSSylwester Nawrocki "#clock-cells");
2286be408bSSylwester Nawrocki if (num_parents == -EINVAL)
2316673931SRob Herring pr_err("clk: invalid value of clock-parents property at %pOF\n",
2416673931SRob Herring node);
2586be408bSSylwester Nawrocki
2686be408bSSylwester Nawrocki for (index = 0; index < num_parents; index++) {
2786be408bSSylwester Nawrocki rc = of_parse_phandle_with_args(node, "assigned-clock-parents",
2886be408bSSylwester Nawrocki "#clock-cells", index, &clkspec);
2986be408bSSylwester Nawrocki if (rc < 0) {
3086be408bSSylwester Nawrocki /* skip empty (null) phandles */
3186be408bSSylwester Nawrocki if (rc == -ENOENT)
3286be408bSSylwester Nawrocki continue;
3386be408bSSylwester Nawrocki else
3486be408bSSylwester Nawrocki return rc;
3586be408bSSylwester Nawrocki }
3627a6e1b0SClément Léger if (clkspec.np == node && !clk_supplier) {
3727a6e1b0SClément Léger of_node_put(clkspec.np);
3886be408bSSylwester Nawrocki return 0;
3927a6e1b0SClément Léger }
40306c342fSStephen Boyd pclk = of_clk_get_from_provider(&clkspec);
4127a6e1b0SClément Léger of_node_put(clkspec.np);
4286be408bSSylwester Nawrocki if (IS_ERR(pclk)) {
43e2d79333SGeert Uytterhoeven if (PTR_ERR(pclk) != -EPROBE_DEFER)
4416673931SRob Herring pr_warn("clk: couldn't get parent clock %d for %pOF\n",
4516673931SRob Herring index, node);
4686be408bSSylwester Nawrocki return PTR_ERR(pclk);
4786be408bSSylwester Nawrocki }
4886be408bSSylwester Nawrocki
4986be408bSSylwester Nawrocki rc = of_parse_phandle_with_args(node, "assigned-clocks",
5086be408bSSylwester Nawrocki "#clock-cells", index, &clkspec);
5186be408bSSylwester Nawrocki if (rc < 0)
5286be408bSSylwester Nawrocki goto err;
5386be408bSSylwester Nawrocki if (clkspec.np == node && !clk_supplier) {
5427a6e1b0SClément Léger of_node_put(clkspec.np);
5586be408bSSylwester Nawrocki rc = 0;
5686be408bSSylwester Nawrocki goto err;
5786be408bSSylwester Nawrocki }
58306c342fSStephen Boyd clk = of_clk_get_from_provider(&clkspec);
5927a6e1b0SClément Léger of_node_put(clkspec.np);
606ba19bf0SDan Carpenter if (IS_ERR(clk)) {
61e2d79333SGeert Uytterhoeven if (PTR_ERR(clk) != -EPROBE_DEFER)
6216673931SRob Herring pr_warn("clk: couldn't get assigned clock %d for %pOF\n",
6316673931SRob Herring index, node);
646ba19bf0SDan Carpenter rc = PTR_ERR(clk);
6586be408bSSylwester Nawrocki goto err;
6686be408bSSylwester Nawrocki }
6786be408bSSylwester Nawrocki
6886be408bSSylwester Nawrocki rc = clk_set_parent(clk, pclk);
6986be408bSSylwester Nawrocki if (rc < 0)
7086be408bSSylwester Nawrocki pr_err("clk: failed to reparent %s to %s: %d\n",
7186be408bSSylwester Nawrocki __clk_get_name(clk), __clk_get_name(pclk), rc);
7286be408bSSylwester Nawrocki clk_put(clk);
7386be408bSSylwester Nawrocki clk_put(pclk);
7486be408bSSylwester Nawrocki }
7586be408bSSylwester Nawrocki return 0;
7686be408bSSylwester Nawrocki err:
7786be408bSSylwester Nawrocki clk_put(pclk);
7886be408bSSylwester Nawrocki return rc;
7986be408bSSylwester Nawrocki }
8086be408bSSylwester Nawrocki
__set_clk_rates(struct device_node * node,bool clk_supplier)8186be408bSSylwester Nawrocki static int __set_clk_rates(struct device_node *node, bool clk_supplier)
8286be408bSSylwester Nawrocki {
8386be408bSSylwester Nawrocki struct of_phandle_args clkspec;
8486be408bSSylwester Nawrocki int rc, index = 0;
8586be408bSSylwester Nawrocki struct clk *clk;
8686be408bSSylwester Nawrocki u32 rate;
8786be408bSSylwester Nawrocki
88*914ef7d1SLuca Ceresoli of_property_for_each_u32(node, "assigned-clock-rates", rate) {
8986be408bSSylwester Nawrocki if (rate) {
9086be408bSSylwester Nawrocki rc = of_parse_phandle_with_args(node, "assigned-clocks",
9186be408bSSylwester Nawrocki "#clock-cells", index, &clkspec);
9286be408bSSylwester Nawrocki if (rc < 0) {
9386be408bSSylwester Nawrocki /* skip empty (null) phandles */
9486be408bSSylwester Nawrocki if (rc == -ENOENT)
9586be408bSSylwester Nawrocki continue;
9686be408bSSylwester Nawrocki else
9786be408bSSylwester Nawrocki return rc;
9886be408bSSylwester Nawrocki }
9927a6e1b0SClément Léger if (clkspec.np == node && !clk_supplier) {
10027a6e1b0SClément Léger of_node_put(clkspec.np);
10186be408bSSylwester Nawrocki return 0;
10227a6e1b0SClément Léger }
10386be408bSSylwester Nawrocki
104306c342fSStephen Boyd clk = of_clk_get_from_provider(&clkspec);
10527a6e1b0SClément Léger of_node_put(clkspec.np);
10686be408bSSylwester Nawrocki if (IS_ERR(clk)) {
107e2d79333SGeert Uytterhoeven if (PTR_ERR(clk) != -EPROBE_DEFER)
10816673931SRob Herring pr_warn("clk: couldn't get clock %d for %pOF\n",
10916673931SRob Herring index, node);
11086be408bSSylwester Nawrocki return PTR_ERR(clk);
11186be408bSSylwester Nawrocki }
11286be408bSSylwester Nawrocki
11386be408bSSylwester Nawrocki rc = clk_set_rate(clk, rate);
11486be408bSSylwester Nawrocki if (rc < 0)
115ee177c5dSBryan O'Donoghue pr_err("clk: couldn't set %s clk rate to %u (%d), current rate: %lu\n",
1162885c3b2SChanwoo Choi __clk_get_name(clk), rate, rc,
1172885c3b2SChanwoo Choi clk_get_rate(clk));
11886be408bSSylwester Nawrocki clk_put(clk);
11986be408bSSylwester Nawrocki }
12086be408bSSylwester Nawrocki index++;
12186be408bSSylwester Nawrocki }
12286be408bSSylwester Nawrocki return 0;
12386be408bSSylwester Nawrocki }
12486be408bSSylwester Nawrocki
12586be408bSSylwester Nawrocki /**
12686be408bSSylwester Nawrocki * of_clk_set_defaults() - parse and set assigned clocks configuration
12786be408bSSylwester Nawrocki * @node: device node to apply clock settings for
12886be408bSSylwester Nawrocki * @clk_supplier: true if clocks supplied by @node should also be considered
12986be408bSSylwester Nawrocki *
13086be408bSSylwester Nawrocki * This function parses 'assigned-{clocks/clock-parents/clock-rates}' properties
13186be408bSSylwester Nawrocki * and sets any specified clock parents and rates. The @clk_supplier argument
13286be408bSSylwester Nawrocki * should be set to true if @node may be also a clock supplier of any clock
13386be408bSSylwester Nawrocki * listed in its 'assigned-clocks' or 'assigned-clock-parents' properties.
134004cbb47SShailendra Verma * If @clk_supplier is false the function exits returning 0 as soon as it
13586be408bSSylwester Nawrocki * determines the @node is also a supplier of any of the clocks.
13686be408bSSylwester Nawrocki */
of_clk_set_defaults(struct device_node * node,bool clk_supplier)13786be408bSSylwester Nawrocki int of_clk_set_defaults(struct device_node *node, bool clk_supplier)
13886be408bSSylwester Nawrocki {
13986be408bSSylwester Nawrocki int rc;
14086be408bSSylwester Nawrocki
14186be408bSSylwester Nawrocki if (!node)
14286be408bSSylwester Nawrocki return 0;
14386be408bSSylwester Nawrocki
14486be408bSSylwester Nawrocki rc = __set_clk_parents(node, clk_supplier);
14586be408bSSylwester Nawrocki if (rc < 0)
14686be408bSSylwester Nawrocki return rc;
14786be408bSSylwester Nawrocki
14886be408bSSylwester Nawrocki return __set_clk_rates(node, clk_supplier);
14986be408bSSylwester Nawrocki }
150b11a6facSSylwester Nawrocki EXPORT_SYMBOL_GPL(of_clk_set_defaults);
151