brintos

brintos / linux-shallow public Read only

0
0
Text · 4.6 KiB · 303a0bb Raw
184 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2014 Samsung Electronics Co., Ltd.4 * Sylwester Nawrocki <s.nawrocki@samsung.com>5 */6 7#include <linux/clk.h>8#include <linux/clk-provider.h>9#include <linux/clk/clk-conf.h>10#include <linux/device.h>11#include <linux/of.h>12#include <linux/printk.h>13#include <linux/slab.h>14 15static int __set_clk_parents(struct device_node *node, bool clk_supplier)16{17	struct of_phandle_args clkspec;18	int index, rc, num_parents;19	struct clk *clk, *pclk;20 21	num_parents = of_count_phandle_with_args(node, "assigned-clock-parents",22						 "#clock-cells");23	if (num_parents == -EINVAL)24		pr_err("clk: invalid value of clock-parents property at %pOF\n",25		       node);26 27	for (index = 0; index < num_parents; index++) {28		rc = of_parse_phandle_with_args(node, "assigned-clock-parents",29					"#clock-cells",	index, &clkspec);30		if (rc < 0) {31			/* skip empty (null) phandles */32			if (rc == -ENOENT)33				continue;34			else35				return rc;36		}37		if (clkspec.np == node && !clk_supplier) {38			of_node_put(clkspec.np);39			return 0;40		}41		pclk = of_clk_get_from_provider(&clkspec);42		of_node_put(clkspec.np);43		if (IS_ERR(pclk)) {44			if (PTR_ERR(pclk) != -EPROBE_DEFER)45				pr_warn("clk: couldn't get parent clock %d for %pOF\n",46					index, node);47			return PTR_ERR(pclk);48		}49 50		rc = of_parse_phandle_with_args(node, "assigned-clocks",51					"#clock-cells", index, &clkspec);52		if (rc < 0)53			goto err;54		if (clkspec.np == node && !clk_supplier) {55			of_node_put(clkspec.np);56			rc = 0;57			goto err;58		}59		clk = of_clk_get_from_provider(&clkspec);60		of_node_put(clkspec.np);61		if (IS_ERR(clk)) {62			if (PTR_ERR(clk) != -EPROBE_DEFER)63				pr_warn("clk: couldn't get assigned clock %d for %pOF\n",64					index, node);65			rc = PTR_ERR(clk);66			goto err;67		}68 69		rc = clk_set_parent(clk, pclk);70		if (rc < 0)71			pr_err("clk: failed to reparent %s to %s: %d\n",72			       __clk_get_name(clk), __clk_get_name(pclk), rc);73		clk_put(clk);74		clk_put(pclk);75	}76	return 0;77err:78	clk_put(pclk);79	return rc;80}81 82static int __set_clk_rates(struct device_node *node, bool clk_supplier)83{84	struct of_phandle_args clkspec;85	int rc, count, count_64, index;86	struct clk *clk;87	u64 *rates_64 __free(kfree) = NULL;88	u32 *rates __free(kfree) = NULL;89 90	count = of_property_count_u32_elems(node, "assigned-clock-rates");91	count_64 = of_property_count_u64_elems(node, "assigned-clock-rates-u64");92	if (count_64 > 0) {93		count = count_64;94		rates_64 = kcalloc(count, sizeof(*rates_64), GFP_KERNEL);95		if (!rates_64)96			return -ENOMEM;97 98		rc = of_property_read_u64_array(node,99						"assigned-clock-rates-u64",100						rates_64, count);101	} else if (count > 0) {102		rates = kcalloc(count, sizeof(*rates), GFP_KERNEL);103		if (!rates)104			return -ENOMEM;105 106		rc = of_property_read_u32_array(node, "assigned-clock-rates",107						rates, count);108	} else {109		return 0;110	}111 112	if (rc)113		return rc;114 115	for (index = 0; index < count; index++) {116		unsigned long rate;117 118		if (rates_64)119			rate = rates_64[index];120		else121			rate = rates[index];122 123		if (rate) {124			rc = of_parse_phandle_with_args(node, "assigned-clocks",125					"#clock-cells",	index, &clkspec);126			if (rc < 0) {127				/* skip empty (null) phandles */128				if (rc == -ENOENT)129					continue;130				else131					return rc;132			}133			if (clkspec.np == node && !clk_supplier) {134				of_node_put(clkspec.np);135				return 0;136			}137 138			clk = of_clk_get_from_provider(&clkspec);139			of_node_put(clkspec.np);140			if (IS_ERR(clk)) {141				if (PTR_ERR(clk) != -EPROBE_DEFER)142					pr_warn("clk: couldn't get clock %d for %pOF\n",143						index, node);144				return PTR_ERR(clk);145			}146 147			rc = clk_set_rate(clk, rate);148			if (rc < 0)149				pr_err("clk: couldn't set %s clk rate to %lu (%d), current rate: %lu\n",150				       __clk_get_name(clk), rate, rc,151				       clk_get_rate(clk));152			clk_put(clk);153		}154	}155	return 0;156}157 158/**159 * of_clk_set_defaults() - parse and set assigned clocks configuration160 * @node: device node to apply clock settings for161 * @clk_supplier: true if clocks supplied by @node should also be considered162 *163 * This function parses 'assigned-{clocks/clock-parents/clock-rates}' properties164 * and sets any specified clock parents and rates. The @clk_supplier argument165 * should be set to true if @node may be also a clock supplier of any clock166 * listed in its 'assigned-clocks' or 'assigned-clock-parents' properties.167 * If @clk_supplier is false the function exits returning 0 as soon as it168 * determines the @node is also a supplier of any of the clocks.169 */170int of_clk_set_defaults(struct device_node *node, bool clk_supplier)171{172	int rc;173 174	if (!node)175		return 0;176 177	rc = __set_clk_parents(node, clk_supplier);178	if (rc < 0)179		return rc;180 181	return __set_clk_rates(node, clk_supplier);182}183EXPORT_SYMBOL_GPL(of_clk_set_defaults);184