162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2017 NXP
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Dong Aisheng <aisheng.dong@nxp.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/clk.h>
962306a36Sopenharmony_ci#include <linux/clk-provider.h>
1062306a36Sopenharmony_ci#include <linux/device.h>
1162306a36Sopenharmony_ci#include <linux/export.h>
1262306a36Sopenharmony_ci#include <linux/of.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic int __must_check of_clk_bulk_get(struct device_node *np, int num_clks,
1662306a36Sopenharmony_ci					struct clk_bulk_data *clks)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	int ret;
1962306a36Sopenharmony_ci	int i;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci	for (i = 0; i < num_clks; i++) {
2262306a36Sopenharmony_ci		clks[i].id = NULL;
2362306a36Sopenharmony_ci		clks[i].clk = NULL;
2462306a36Sopenharmony_ci	}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	for (i = 0; i < num_clks; i++) {
2762306a36Sopenharmony_ci		of_property_read_string_index(np, "clock-names", i, &clks[i].id);
2862306a36Sopenharmony_ci		clks[i].clk = of_clk_get(np, i);
2962306a36Sopenharmony_ci		if (IS_ERR(clks[i].clk)) {
3062306a36Sopenharmony_ci			ret = PTR_ERR(clks[i].clk);
3162306a36Sopenharmony_ci			pr_err("%pOF: Failed to get clk index: %d ret: %d\n",
3262306a36Sopenharmony_ci			       np, i, ret);
3362306a36Sopenharmony_ci			clks[i].clk = NULL;
3462306a36Sopenharmony_ci			goto err;
3562306a36Sopenharmony_ci		}
3662306a36Sopenharmony_ci	}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	return 0;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cierr:
4162306a36Sopenharmony_ci	clk_bulk_put(i, clks);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	return ret;
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic int __must_check of_clk_bulk_get_all(struct device_node *np,
4762306a36Sopenharmony_ci					    struct clk_bulk_data **clks)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	struct clk_bulk_data *clk_bulk;
5062306a36Sopenharmony_ci	int num_clks;
5162306a36Sopenharmony_ci	int ret;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	num_clks = of_clk_get_parent_count(np);
5462306a36Sopenharmony_ci	if (!num_clks)
5562306a36Sopenharmony_ci		return 0;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	clk_bulk = kmalloc_array(num_clks, sizeof(*clk_bulk), GFP_KERNEL);
5862306a36Sopenharmony_ci	if (!clk_bulk)
5962306a36Sopenharmony_ci		return -ENOMEM;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	ret = of_clk_bulk_get(np, num_clks, clk_bulk);
6262306a36Sopenharmony_ci	if (ret) {
6362306a36Sopenharmony_ci		kfree(clk_bulk);
6462306a36Sopenharmony_ci		return ret;
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	*clks = clk_bulk;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	return num_clks;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_civoid clk_bulk_put(int num_clks, struct clk_bulk_data *clks)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	while (--num_clks >= 0) {
7562306a36Sopenharmony_ci		clk_put(clks[num_clks].clk);
7662306a36Sopenharmony_ci		clks[num_clks].clk = NULL;
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_bulk_put);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic int __clk_bulk_get(struct device *dev, int num_clks,
8262306a36Sopenharmony_ci			  struct clk_bulk_data *clks, bool optional)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	int ret;
8562306a36Sopenharmony_ci	int i;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	for (i = 0; i < num_clks; i++)
8862306a36Sopenharmony_ci		clks[i].clk = NULL;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	for (i = 0; i < num_clks; i++) {
9162306a36Sopenharmony_ci		clks[i].clk = clk_get(dev, clks[i].id);
9262306a36Sopenharmony_ci		if (IS_ERR(clks[i].clk)) {
9362306a36Sopenharmony_ci			ret = PTR_ERR(clks[i].clk);
9462306a36Sopenharmony_ci			clks[i].clk = NULL;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci			if (ret == -ENOENT && optional)
9762306a36Sopenharmony_ci				continue;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci			dev_err_probe(dev, ret,
10062306a36Sopenharmony_ci				      "Failed to get clk '%s'\n",
10162306a36Sopenharmony_ci				      clks[i].id);
10262306a36Sopenharmony_ci			goto err;
10362306a36Sopenharmony_ci		}
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	return 0;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cierr:
10962306a36Sopenharmony_ci	clk_bulk_put(i, clks);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	return ret;
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ciint __must_check clk_bulk_get(struct device *dev, int num_clks,
11562306a36Sopenharmony_ci			      struct clk_bulk_data *clks)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	return __clk_bulk_get(dev, num_clks, clks, false);
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ciEXPORT_SYMBOL(clk_bulk_get);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ciint __must_check clk_bulk_get_optional(struct device *dev, int num_clks,
12262306a36Sopenharmony_ci				       struct clk_bulk_data *clks)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	return __clk_bulk_get(dev, num_clks, clks, true);
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_bulk_get_optional);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_civoid clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(clks))
13162306a36Sopenharmony_ci		return;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	clk_bulk_put(num_clks, clks);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	kfree(clks);
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ciEXPORT_SYMBOL(clk_bulk_put_all);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ciint __must_check clk_bulk_get_all(struct device *dev,
14062306a36Sopenharmony_ci				  struct clk_bulk_data **clks)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	struct device_node *np = dev_of_node(dev);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	if (!np)
14562306a36Sopenharmony_ci		return 0;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return of_clk_bulk_get_all(np, clks);
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ciEXPORT_SYMBOL(clk_bulk_get_all);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci#ifdef CONFIG_HAVE_CLK_PREPARE
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci/**
15462306a36Sopenharmony_ci * clk_bulk_unprepare - undo preparation of a set of clock sources
15562306a36Sopenharmony_ci * @num_clks: the number of clk_bulk_data
15662306a36Sopenharmony_ci * @clks: the clk_bulk_data table being unprepared
15762306a36Sopenharmony_ci *
15862306a36Sopenharmony_ci * clk_bulk_unprepare may sleep, which differentiates it from clk_bulk_disable.
15962306a36Sopenharmony_ci * Returns 0 on success, -EERROR otherwise.
16062306a36Sopenharmony_ci */
16162306a36Sopenharmony_civoid clk_bulk_unprepare(int num_clks, const struct clk_bulk_data *clks)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	while (--num_clks >= 0)
16462306a36Sopenharmony_ci		clk_unprepare(clks[num_clks].clk);
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_bulk_unprepare);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci/**
16962306a36Sopenharmony_ci * clk_bulk_prepare - prepare a set of clocks
17062306a36Sopenharmony_ci * @num_clks: the number of clk_bulk_data
17162306a36Sopenharmony_ci * @clks: the clk_bulk_data table being prepared
17262306a36Sopenharmony_ci *
17362306a36Sopenharmony_ci * clk_bulk_prepare may sleep, which differentiates it from clk_bulk_enable.
17462306a36Sopenharmony_ci * Returns 0 on success, -EERROR otherwise.
17562306a36Sopenharmony_ci */
17662306a36Sopenharmony_ciint __must_check clk_bulk_prepare(int num_clks,
17762306a36Sopenharmony_ci				  const struct clk_bulk_data *clks)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	int ret;
18062306a36Sopenharmony_ci	int i;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	for (i = 0; i < num_clks; i++) {
18362306a36Sopenharmony_ci		ret = clk_prepare(clks[i].clk);
18462306a36Sopenharmony_ci		if (ret) {
18562306a36Sopenharmony_ci			pr_err("Failed to prepare clk '%s': %d\n",
18662306a36Sopenharmony_ci				clks[i].id, ret);
18762306a36Sopenharmony_ci			goto err;
18862306a36Sopenharmony_ci		}
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	return 0;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cierr:
19462306a36Sopenharmony_ci	clk_bulk_unprepare(i, clks);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	return  ret;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_bulk_prepare);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci#endif /* CONFIG_HAVE_CLK_PREPARE */
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci/**
20362306a36Sopenharmony_ci * clk_bulk_disable - gate a set of clocks
20462306a36Sopenharmony_ci * @num_clks: the number of clk_bulk_data
20562306a36Sopenharmony_ci * @clks: the clk_bulk_data table being gated
20662306a36Sopenharmony_ci *
20762306a36Sopenharmony_ci * clk_bulk_disable must not sleep, which differentiates it from
20862306a36Sopenharmony_ci * clk_bulk_unprepare. clk_bulk_disable must be called before
20962306a36Sopenharmony_ci * clk_bulk_unprepare.
21062306a36Sopenharmony_ci */
21162306a36Sopenharmony_civoid clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	while (--num_clks >= 0)
21562306a36Sopenharmony_ci		clk_disable(clks[num_clks].clk);
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_bulk_disable);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci/**
22062306a36Sopenharmony_ci * clk_bulk_enable - ungate a set of clocks
22162306a36Sopenharmony_ci * @num_clks: the number of clk_bulk_data
22262306a36Sopenharmony_ci * @clks: the clk_bulk_data table being ungated
22362306a36Sopenharmony_ci *
22462306a36Sopenharmony_ci * clk_bulk_enable must not sleep
22562306a36Sopenharmony_ci * Returns 0 on success, -EERROR otherwise.
22662306a36Sopenharmony_ci */
22762306a36Sopenharmony_ciint __must_check clk_bulk_enable(int num_clks, const struct clk_bulk_data *clks)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	int ret;
23062306a36Sopenharmony_ci	int i;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	for (i = 0; i < num_clks; i++) {
23362306a36Sopenharmony_ci		ret = clk_enable(clks[i].clk);
23462306a36Sopenharmony_ci		if (ret) {
23562306a36Sopenharmony_ci			pr_err("Failed to enable clk '%s': %d\n",
23662306a36Sopenharmony_ci				clks[i].id, ret);
23762306a36Sopenharmony_ci			goto err;
23862306a36Sopenharmony_ci		}
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	return 0;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cierr:
24462306a36Sopenharmony_ci	clk_bulk_disable(i, clks);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	return  ret;
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_bulk_enable);
249