int dev_pm_opp_of_find_icc_paths()

in of.c [455:516]


int dev_pm_opp_of_find_icc_paths(struct device *dev,
				 struct opp_table *opp_table)
{
	struct device_node *np;
	int ret, i, count, num_paths;
	struct icc_path **paths;

	ret = _bandwidth_supported(dev, opp_table);
	if (ret == -EINVAL)
		return 0; /* Empty OPP table is a valid corner-case, let's not fail */
	else if (ret <= 0)
		return ret;

	ret = 0;

	np = of_node_get(dev->of_node);
	if (!np)
		return 0;

	count = of_count_phandle_with_args(np, "interconnects",
					   "#interconnect-cells");
	of_node_put(np);
	if (count < 0)
		return 0;

	/* two phandles when #interconnect-cells = <1> */
	if (count % 2) {
		dev_err(dev, "%s: Invalid interconnects values\n", __func__);
		return -EINVAL;
	}

	num_paths = count / 2;
	paths = kcalloc(num_paths, sizeof(*paths), GFP_KERNEL);
	if (!paths)
		return -ENOMEM;

	for (i = 0; i < num_paths; i++) {
		paths[i] = of_icc_get_by_index(dev, i);
		if (IS_ERR(paths[i])) {
			ret = PTR_ERR(paths[i]);
			if (ret != -EPROBE_DEFER) {
				dev_err(dev, "%s: Unable to get path%d: %d\n",
					__func__, i, ret);
			}
			goto err;
		}
	}

	if (opp_table) {
		opp_table->paths = paths;
		opp_table->path_count = num_paths;
		return 0;
	}

err:
	while (i--)
		icc_put(paths[i]);

	kfree(paths);

	return ret;
}