18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/io.h>
38c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
48c2ecf20Sopenharmony_ci#include <linux/slab.h>
58c2ecf20Sopenharmony_ci#include <linux/of.h>
68c2ecf20Sopenharmony_ci#include <linux/of_address.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "clk.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_civoid mmp_clk_init(struct device_node *np, struct mmp_clk_unit *unit,
118c2ecf20Sopenharmony_ci		int nr_clks)
128c2ecf20Sopenharmony_ci{
138c2ecf20Sopenharmony_ci	struct clk **clk_table;
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci	clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL);
168c2ecf20Sopenharmony_ci	if (!clk_table)
178c2ecf20Sopenharmony_ci		return;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	unit->clk_table = clk_table;
208c2ecf20Sopenharmony_ci	unit->nr_clks = nr_clks;
218c2ecf20Sopenharmony_ci	unit->clk_data.clks = clk_table;
228c2ecf20Sopenharmony_ci	unit->clk_data.clk_num = nr_clks;
238c2ecf20Sopenharmony_ci	of_clk_add_provider(np, of_clk_src_onecell_get, &unit->clk_data);
248c2ecf20Sopenharmony_ci}
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_civoid mmp_register_fixed_rate_clks(struct mmp_clk_unit *unit,
278c2ecf20Sopenharmony_ci				struct mmp_param_fixed_rate_clk *clks,
288c2ecf20Sopenharmony_ci				int size)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	int i;
318c2ecf20Sopenharmony_ci	struct clk *clk;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++) {
348c2ecf20Sopenharmony_ci		clk = clk_register_fixed_rate(NULL, clks[i].name,
358c2ecf20Sopenharmony_ci					clks[i].parent_name,
368c2ecf20Sopenharmony_ci					clks[i].flags,
378c2ecf20Sopenharmony_ci					clks[i].fixed_rate);
388c2ecf20Sopenharmony_ci		if (IS_ERR(clk)) {
398c2ecf20Sopenharmony_ci			pr_err("%s: failed to register clock %s\n",
408c2ecf20Sopenharmony_ci			       __func__, clks[i].name);
418c2ecf20Sopenharmony_ci			continue;
428c2ecf20Sopenharmony_ci		}
438c2ecf20Sopenharmony_ci		if (clks[i].id)
448c2ecf20Sopenharmony_ci			unit->clk_table[clks[i].id] = clk;
458c2ecf20Sopenharmony_ci	}
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_civoid mmp_register_fixed_factor_clks(struct mmp_clk_unit *unit,
498c2ecf20Sopenharmony_ci				struct mmp_param_fixed_factor_clk *clks,
508c2ecf20Sopenharmony_ci				int size)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	struct clk *clk;
538c2ecf20Sopenharmony_ci	int i;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++) {
568c2ecf20Sopenharmony_ci		clk = clk_register_fixed_factor(NULL, clks[i].name,
578c2ecf20Sopenharmony_ci						clks[i].parent_name,
588c2ecf20Sopenharmony_ci						clks[i].flags, clks[i].mult,
598c2ecf20Sopenharmony_ci						clks[i].div);
608c2ecf20Sopenharmony_ci		if (IS_ERR(clk)) {
618c2ecf20Sopenharmony_ci			pr_err("%s: failed to register clock %s\n",
628c2ecf20Sopenharmony_ci			       __func__, clks[i].name);
638c2ecf20Sopenharmony_ci			continue;
648c2ecf20Sopenharmony_ci		}
658c2ecf20Sopenharmony_ci		if (clks[i].id)
668c2ecf20Sopenharmony_ci			unit->clk_table[clks[i].id] = clk;
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_civoid mmp_register_general_gate_clks(struct mmp_clk_unit *unit,
718c2ecf20Sopenharmony_ci				struct mmp_param_general_gate_clk *clks,
728c2ecf20Sopenharmony_ci				void __iomem *base, int size)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	struct clk *clk;
758c2ecf20Sopenharmony_ci	int i;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++) {
788c2ecf20Sopenharmony_ci		clk = clk_register_gate(NULL, clks[i].name,
798c2ecf20Sopenharmony_ci					clks[i].parent_name,
808c2ecf20Sopenharmony_ci					clks[i].flags,
818c2ecf20Sopenharmony_ci					base + clks[i].offset,
828c2ecf20Sopenharmony_ci					clks[i].bit_idx,
838c2ecf20Sopenharmony_ci					clks[i].gate_flags,
848c2ecf20Sopenharmony_ci					clks[i].lock);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci		if (IS_ERR(clk)) {
878c2ecf20Sopenharmony_ci			pr_err("%s: failed to register clock %s\n",
888c2ecf20Sopenharmony_ci			       __func__, clks[i].name);
898c2ecf20Sopenharmony_ci			continue;
908c2ecf20Sopenharmony_ci		}
918c2ecf20Sopenharmony_ci		if (clks[i].id)
928c2ecf20Sopenharmony_ci			unit->clk_table[clks[i].id] = clk;
938c2ecf20Sopenharmony_ci	}
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_civoid mmp_register_gate_clks(struct mmp_clk_unit *unit,
978c2ecf20Sopenharmony_ci			struct mmp_param_gate_clk *clks,
988c2ecf20Sopenharmony_ci			void __iomem *base, int size)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	struct clk *clk;
1018c2ecf20Sopenharmony_ci	int i;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++) {
1048c2ecf20Sopenharmony_ci		clk = mmp_clk_register_gate(NULL, clks[i].name,
1058c2ecf20Sopenharmony_ci					clks[i].parent_name,
1068c2ecf20Sopenharmony_ci					clks[i].flags,
1078c2ecf20Sopenharmony_ci					base + clks[i].offset,
1088c2ecf20Sopenharmony_ci					clks[i].mask,
1098c2ecf20Sopenharmony_ci					clks[i].val_enable,
1108c2ecf20Sopenharmony_ci					clks[i].val_disable,
1118c2ecf20Sopenharmony_ci					clks[i].gate_flags,
1128c2ecf20Sopenharmony_ci					clks[i].lock);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci		if (IS_ERR(clk)) {
1158c2ecf20Sopenharmony_ci			pr_err("%s: failed to register clock %s\n",
1168c2ecf20Sopenharmony_ci			       __func__, clks[i].name);
1178c2ecf20Sopenharmony_ci			continue;
1188c2ecf20Sopenharmony_ci		}
1198c2ecf20Sopenharmony_ci		if (clks[i].id)
1208c2ecf20Sopenharmony_ci			unit->clk_table[clks[i].id] = clk;
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_civoid mmp_register_mux_clks(struct mmp_clk_unit *unit,
1258c2ecf20Sopenharmony_ci			struct mmp_param_mux_clk *clks,
1268c2ecf20Sopenharmony_ci			void __iomem *base, int size)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	struct clk *clk;
1298c2ecf20Sopenharmony_ci	int i;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++) {
1328c2ecf20Sopenharmony_ci		clk = clk_register_mux(NULL, clks[i].name,
1338c2ecf20Sopenharmony_ci					clks[i].parent_name,
1348c2ecf20Sopenharmony_ci					clks[i].num_parents,
1358c2ecf20Sopenharmony_ci					clks[i].flags,
1368c2ecf20Sopenharmony_ci					base + clks[i].offset,
1378c2ecf20Sopenharmony_ci					clks[i].shift,
1388c2ecf20Sopenharmony_ci					clks[i].width,
1398c2ecf20Sopenharmony_ci					clks[i].mux_flags,
1408c2ecf20Sopenharmony_ci					clks[i].lock);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci		if (IS_ERR(clk)) {
1438c2ecf20Sopenharmony_ci			pr_err("%s: failed to register clock %s\n",
1448c2ecf20Sopenharmony_ci			       __func__, clks[i].name);
1458c2ecf20Sopenharmony_ci			continue;
1468c2ecf20Sopenharmony_ci		}
1478c2ecf20Sopenharmony_ci		if (clks[i].id)
1488c2ecf20Sopenharmony_ci			unit->clk_table[clks[i].id] = clk;
1498c2ecf20Sopenharmony_ci	}
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_civoid mmp_register_div_clks(struct mmp_clk_unit *unit,
1538c2ecf20Sopenharmony_ci			struct mmp_param_div_clk *clks,
1548c2ecf20Sopenharmony_ci			void __iomem *base, int size)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	struct clk *clk;
1578c2ecf20Sopenharmony_ci	int i;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++) {
1608c2ecf20Sopenharmony_ci		clk = clk_register_divider(NULL, clks[i].name,
1618c2ecf20Sopenharmony_ci					clks[i].parent_name,
1628c2ecf20Sopenharmony_ci					clks[i].flags,
1638c2ecf20Sopenharmony_ci					base + clks[i].offset,
1648c2ecf20Sopenharmony_ci					clks[i].shift,
1658c2ecf20Sopenharmony_ci					clks[i].width,
1668c2ecf20Sopenharmony_ci					clks[i].div_flags,
1678c2ecf20Sopenharmony_ci					clks[i].lock);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci		if (IS_ERR(clk)) {
1708c2ecf20Sopenharmony_ci			pr_err("%s: failed to register clock %s\n",
1718c2ecf20Sopenharmony_ci			       __func__, clks[i].name);
1728c2ecf20Sopenharmony_ci			continue;
1738c2ecf20Sopenharmony_ci		}
1748c2ecf20Sopenharmony_ci		if (clks[i].id)
1758c2ecf20Sopenharmony_ci			unit->clk_table[clks[i].id] = clk;
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_civoid mmp_clk_add(struct mmp_clk_unit *unit, unsigned int id,
1808c2ecf20Sopenharmony_ci			struct clk *clk)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	if (IS_ERR_OR_NULL(clk)) {
1838c2ecf20Sopenharmony_ci		pr_err("CLK %d has invalid pointer %p\n", id, clk);
1848c2ecf20Sopenharmony_ci		return;
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci	if (id >= unit->nr_clks) {
1878c2ecf20Sopenharmony_ci		pr_err("CLK %d is invalid\n", id);
1888c2ecf20Sopenharmony_ci		return;
1898c2ecf20Sopenharmony_ci	}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	unit->clk_table[id] = clk;
1928c2ecf20Sopenharmony_ci}
193