xref: /openbmc/linux/drivers/clk/clk-conf.c (revision 060f35a317ef09101b128f399dce7ed13d019461)
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