xref: /kernel/linux/linux-6.6/drivers/clk/mmp/clk.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/io.h>
362306a36Sopenharmony_ci#include <linux/clk-provider.h>
462306a36Sopenharmony_ci#include <linux/slab.h>
562306a36Sopenharmony_ci#include <linux/of.h>
662306a36Sopenharmony_ci#include <linux/of_address.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "clk.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_civoid mmp_clk_init(struct device_node *np, struct mmp_clk_unit *unit,
1162306a36Sopenharmony_ci		int nr_clks)
1262306a36Sopenharmony_ci{
1362306a36Sopenharmony_ci	struct clk **clk_table;
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci	clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL);
1662306a36Sopenharmony_ci	if (!clk_table)
1762306a36Sopenharmony_ci		return;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	unit->clk_table = clk_table;
2062306a36Sopenharmony_ci	unit->nr_clks = nr_clks;
2162306a36Sopenharmony_ci	unit->clk_data.clks = clk_table;
2262306a36Sopenharmony_ci	unit->clk_data.clk_num = nr_clks;
2362306a36Sopenharmony_ci	of_clk_add_provider(np, of_clk_src_onecell_get, &unit->clk_data);
2462306a36Sopenharmony_ci}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_civoid mmp_register_fixed_rate_clks(struct mmp_clk_unit *unit,
2762306a36Sopenharmony_ci				struct mmp_param_fixed_rate_clk *clks,
2862306a36Sopenharmony_ci				int size)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	int i;
3162306a36Sopenharmony_ci	struct clk *clk;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
3462306a36Sopenharmony_ci		clk = clk_register_fixed_rate(NULL, clks[i].name,
3562306a36Sopenharmony_ci					clks[i].parent_name,
3662306a36Sopenharmony_ci					clks[i].flags,
3762306a36Sopenharmony_ci					clks[i].fixed_rate);
3862306a36Sopenharmony_ci		if (IS_ERR(clk)) {
3962306a36Sopenharmony_ci			pr_err("%s: failed to register clock %s\n",
4062306a36Sopenharmony_ci			       __func__, clks[i].name);
4162306a36Sopenharmony_ci			continue;
4262306a36Sopenharmony_ci		}
4362306a36Sopenharmony_ci		if (clks[i].id)
4462306a36Sopenharmony_ci			unit->clk_table[clks[i].id] = clk;
4562306a36Sopenharmony_ci	}
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_civoid mmp_register_fixed_factor_clks(struct mmp_clk_unit *unit,
4962306a36Sopenharmony_ci				struct mmp_param_fixed_factor_clk *clks,
5062306a36Sopenharmony_ci				int size)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	struct clk *clk;
5362306a36Sopenharmony_ci	int i;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
5662306a36Sopenharmony_ci		clk = clk_register_fixed_factor(NULL, clks[i].name,
5762306a36Sopenharmony_ci						clks[i].parent_name,
5862306a36Sopenharmony_ci						clks[i].flags, clks[i].mult,
5962306a36Sopenharmony_ci						clks[i].div);
6062306a36Sopenharmony_ci		if (IS_ERR(clk)) {
6162306a36Sopenharmony_ci			pr_err("%s: failed to register clock %s\n",
6262306a36Sopenharmony_ci			       __func__, clks[i].name);
6362306a36Sopenharmony_ci			continue;
6462306a36Sopenharmony_ci		}
6562306a36Sopenharmony_ci		if (clks[i].id)
6662306a36Sopenharmony_ci			unit->clk_table[clks[i].id] = clk;
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_civoid mmp_register_general_gate_clks(struct mmp_clk_unit *unit,
7162306a36Sopenharmony_ci				struct mmp_param_general_gate_clk *clks,
7262306a36Sopenharmony_ci				void __iomem *base, int size)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	struct clk *clk;
7562306a36Sopenharmony_ci	int i;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
7862306a36Sopenharmony_ci		clk = clk_register_gate(NULL, clks[i].name,
7962306a36Sopenharmony_ci					clks[i].parent_name,
8062306a36Sopenharmony_ci					clks[i].flags,
8162306a36Sopenharmony_ci					base + clks[i].offset,
8262306a36Sopenharmony_ci					clks[i].bit_idx,
8362306a36Sopenharmony_ci					clks[i].gate_flags,
8462306a36Sopenharmony_ci					clks[i].lock);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci		if (IS_ERR(clk)) {
8762306a36Sopenharmony_ci			pr_err("%s: failed to register clock %s\n",
8862306a36Sopenharmony_ci			       __func__, clks[i].name);
8962306a36Sopenharmony_ci			continue;
9062306a36Sopenharmony_ci		}
9162306a36Sopenharmony_ci		if (clks[i].id)
9262306a36Sopenharmony_ci			unit->clk_table[clks[i].id] = clk;
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_civoid mmp_register_gate_clks(struct mmp_clk_unit *unit,
9762306a36Sopenharmony_ci			struct mmp_param_gate_clk *clks,
9862306a36Sopenharmony_ci			void __iomem *base, int size)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	struct clk *clk;
10162306a36Sopenharmony_ci	int i;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
10462306a36Sopenharmony_ci		clk = mmp_clk_register_gate(NULL, clks[i].name,
10562306a36Sopenharmony_ci					clks[i].parent_name,
10662306a36Sopenharmony_ci					clks[i].flags,
10762306a36Sopenharmony_ci					base + clks[i].offset,
10862306a36Sopenharmony_ci					clks[i].mask,
10962306a36Sopenharmony_ci					clks[i].val_enable,
11062306a36Sopenharmony_ci					clks[i].val_disable,
11162306a36Sopenharmony_ci					clks[i].gate_flags,
11262306a36Sopenharmony_ci					clks[i].lock);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci		if (IS_ERR(clk)) {
11562306a36Sopenharmony_ci			pr_err("%s: failed to register clock %s\n",
11662306a36Sopenharmony_ci			       __func__, clks[i].name);
11762306a36Sopenharmony_ci			continue;
11862306a36Sopenharmony_ci		}
11962306a36Sopenharmony_ci		if (clks[i].id)
12062306a36Sopenharmony_ci			unit->clk_table[clks[i].id] = clk;
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_civoid mmp_register_mux_clks(struct mmp_clk_unit *unit,
12562306a36Sopenharmony_ci			struct mmp_param_mux_clk *clks,
12662306a36Sopenharmony_ci			void __iomem *base, int size)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	struct clk *clk;
12962306a36Sopenharmony_ci	int i;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
13262306a36Sopenharmony_ci		clk = clk_register_mux(NULL, clks[i].name,
13362306a36Sopenharmony_ci					clks[i].parent_name,
13462306a36Sopenharmony_ci					clks[i].num_parents,
13562306a36Sopenharmony_ci					clks[i].flags,
13662306a36Sopenharmony_ci					base + clks[i].offset,
13762306a36Sopenharmony_ci					clks[i].shift,
13862306a36Sopenharmony_ci					clks[i].width,
13962306a36Sopenharmony_ci					clks[i].mux_flags,
14062306a36Sopenharmony_ci					clks[i].lock);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci		if (IS_ERR(clk)) {
14362306a36Sopenharmony_ci			pr_err("%s: failed to register clock %s\n",
14462306a36Sopenharmony_ci			       __func__, clks[i].name);
14562306a36Sopenharmony_ci			continue;
14662306a36Sopenharmony_ci		}
14762306a36Sopenharmony_ci		if (clks[i].id)
14862306a36Sopenharmony_ci			unit->clk_table[clks[i].id] = clk;
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_civoid mmp_register_div_clks(struct mmp_clk_unit *unit,
15362306a36Sopenharmony_ci			struct mmp_param_div_clk *clks,
15462306a36Sopenharmony_ci			void __iomem *base, int size)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	struct clk *clk;
15762306a36Sopenharmony_ci	int i;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
16062306a36Sopenharmony_ci		clk = clk_register_divider(NULL, clks[i].name,
16162306a36Sopenharmony_ci					clks[i].parent_name,
16262306a36Sopenharmony_ci					clks[i].flags,
16362306a36Sopenharmony_ci					base + clks[i].offset,
16462306a36Sopenharmony_ci					clks[i].shift,
16562306a36Sopenharmony_ci					clks[i].width,
16662306a36Sopenharmony_ci					clks[i].div_flags,
16762306a36Sopenharmony_ci					clks[i].lock);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci		if (IS_ERR(clk)) {
17062306a36Sopenharmony_ci			pr_err("%s: failed to register clock %s\n",
17162306a36Sopenharmony_ci			       __func__, clks[i].name);
17262306a36Sopenharmony_ci			continue;
17362306a36Sopenharmony_ci		}
17462306a36Sopenharmony_ci		if (clks[i].id)
17562306a36Sopenharmony_ci			unit->clk_table[clks[i].id] = clk;
17662306a36Sopenharmony_ci	}
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_civoid mmp_clk_add(struct mmp_clk_unit *unit, unsigned int id,
18062306a36Sopenharmony_ci			struct clk *clk)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(clk)) {
18362306a36Sopenharmony_ci		pr_err("CLK %d has invalid pointer %p\n", id, clk);
18462306a36Sopenharmony_ci		return;
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci	if (id >= unit->nr_clks) {
18762306a36Sopenharmony_ci		pr_err("CLK %d is invalid\n", id);
18862306a36Sopenharmony_ci		return;
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	unit->clk_table[id] = clk;
19262306a36Sopenharmony_ci}
193