18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// OWL factor clock driver
48c2ecf20Sopenharmony_ci//
58c2ecf20Sopenharmony_ci// Copyright (c) 2014 Actions Semi Inc.
68c2ecf20Sopenharmony_ci// Author: David Liu <liuwei@actions-semi.com>
78c2ecf20Sopenharmony_ci//
88c2ecf20Sopenharmony_ci// Copyright (c) 2018 Linaro Ltd.
98c2ecf20Sopenharmony_ci// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
128c2ecf20Sopenharmony_ci#include <linux/regmap.h>
138c2ecf20Sopenharmony_ci#include <linux/slab.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "owl-factor.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistatic unsigned int _get_table_maxval(const struct clk_factor_table *table)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	unsigned int maxval = 0;
208c2ecf20Sopenharmony_ci	const struct clk_factor_table *clkt;
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci	for (clkt = table; clkt->div; clkt++)
238c2ecf20Sopenharmony_ci		if (clkt->val > maxval)
248c2ecf20Sopenharmony_ci			maxval = clkt->val;
258c2ecf20Sopenharmony_ci	return maxval;
268c2ecf20Sopenharmony_ci}
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic int _get_table_div_mul(const struct clk_factor_table *table,
298c2ecf20Sopenharmony_ci			unsigned int val, unsigned int *mul, unsigned int *div)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	const struct clk_factor_table *clkt;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	for (clkt = table; clkt->div; clkt++) {
348c2ecf20Sopenharmony_ci		if (clkt->val == val) {
358c2ecf20Sopenharmony_ci			*mul = clkt->mul;
368c2ecf20Sopenharmony_ci			*div = clkt->div;
378c2ecf20Sopenharmony_ci			return 1;
388c2ecf20Sopenharmony_ci		}
398c2ecf20Sopenharmony_ci	}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	return 0;
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic unsigned int _get_table_val(const struct clk_factor_table *table,
458c2ecf20Sopenharmony_ci			unsigned long rate, unsigned long parent_rate)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	const struct clk_factor_table *clkt;
488c2ecf20Sopenharmony_ci	int val = -1;
498c2ecf20Sopenharmony_ci	u64 calc_rate;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	for (clkt = table; clkt->div; clkt++) {
528c2ecf20Sopenharmony_ci		calc_rate = parent_rate * clkt->mul;
538c2ecf20Sopenharmony_ci		do_div(calc_rate, clkt->div);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci		if ((unsigned long)calc_rate <= rate) {
568c2ecf20Sopenharmony_ci			val = clkt->val;
578c2ecf20Sopenharmony_ci			break;
588c2ecf20Sopenharmony_ci		}
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	if (val == -1)
628c2ecf20Sopenharmony_ci		val = _get_table_maxval(table);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	return val;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic int owl_clk_val_best(const struct owl_factor_hw *factor_hw,
688c2ecf20Sopenharmony_ci			struct clk_hw *hw, unsigned long rate,
698c2ecf20Sopenharmony_ci			unsigned long *best_parent_rate)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	const struct clk_factor_table *clkt = factor_hw->table;
728c2ecf20Sopenharmony_ci	unsigned long parent_rate, try_parent_rate, best = 0, cur_rate;
738c2ecf20Sopenharmony_ci	unsigned long parent_rate_saved = *best_parent_rate;
748c2ecf20Sopenharmony_ci	int bestval = 0;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if (!rate)
778c2ecf20Sopenharmony_ci		rate = 1;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
808c2ecf20Sopenharmony_ci		parent_rate = *best_parent_rate;
818c2ecf20Sopenharmony_ci		bestval = _get_table_val(clkt, rate, parent_rate);
828c2ecf20Sopenharmony_ci		return bestval;
838c2ecf20Sopenharmony_ci	}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	for (clkt = factor_hw->table; clkt->div; clkt++) {
868c2ecf20Sopenharmony_ci		try_parent_rate = rate * clkt->div / clkt->mul;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci		if (try_parent_rate == parent_rate_saved) {
898c2ecf20Sopenharmony_ci			pr_debug("%s: [%d %d %d] found try_parent_rate %ld\n",
908c2ecf20Sopenharmony_ci				__func__, clkt->val, clkt->mul, clkt->div,
918c2ecf20Sopenharmony_ci				try_parent_rate);
928c2ecf20Sopenharmony_ci			/*
938c2ecf20Sopenharmony_ci			 * It's the most ideal case if the requested rate can be
948c2ecf20Sopenharmony_ci			 * divided from parent clock without any need to change
958c2ecf20Sopenharmony_ci			 * parent rate, so return the divider immediately.
968c2ecf20Sopenharmony_ci			 */
978c2ecf20Sopenharmony_ci			*best_parent_rate = parent_rate_saved;
988c2ecf20Sopenharmony_ci			return clkt->val;
998c2ecf20Sopenharmony_ci		}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci		parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
1028c2ecf20Sopenharmony_ci				try_parent_rate);
1038c2ecf20Sopenharmony_ci		cur_rate = DIV_ROUND_UP(parent_rate, clkt->div) * clkt->mul;
1048c2ecf20Sopenharmony_ci		if (cur_rate <= rate && cur_rate > best) {
1058c2ecf20Sopenharmony_ci			bestval = clkt->val;
1068c2ecf20Sopenharmony_ci			best = cur_rate;
1078c2ecf20Sopenharmony_ci			*best_parent_rate = parent_rate;
1088c2ecf20Sopenharmony_ci		}
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	if (!bestval) {
1128c2ecf20Sopenharmony_ci		bestval = _get_table_maxval(clkt);
1138c2ecf20Sopenharmony_ci		*best_parent_rate = clk_hw_round_rate(
1148c2ecf20Sopenharmony_ci				clk_hw_get_parent(hw), 1);
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	return bestval;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cilong owl_factor_helper_round_rate(struct owl_clk_common *common,
1218c2ecf20Sopenharmony_ci				const struct owl_factor_hw *factor_hw,
1228c2ecf20Sopenharmony_ci				unsigned long rate,
1238c2ecf20Sopenharmony_ci				unsigned long *parent_rate)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	const struct clk_factor_table *clkt = factor_hw->table;
1268c2ecf20Sopenharmony_ci	unsigned int val, mul = 0, div = 1;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	val = owl_clk_val_best(factor_hw, &common->hw, rate, parent_rate);
1298c2ecf20Sopenharmony_ci	_get_table_div_mul(clkt, val, &mul, &div);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	return *parent_rate * mul / div;
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic long owl_factor_round_rate(struct clk_hw *hw, unsigned long rate,
1358c2ecf20Sopenharmony_ci			unsigned long *parent_rate)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	struct owl_factor *factor = hw_to_owl_factor(hw);
1388c2ecf20Sopenharmony_ci	struct owl_factor_hw *factor_hw = &factor->factor_hw;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	return owl_factor_helper_round_rate(&factor->common, factor_hw,
1418c2ecf20Sopenharmony_ci					rate, parent_rate);
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ciunsigned long owl_factor_helper_recalc_rate(struct owl_clk_common *common,
1458c2ecf20Sopenharmony_ci					 const struct owl_factor_hw *factor_hw,
1468c2ecf20Sopenharmony_ci					 unsigned long parent_rate)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	const struct clk_factor_table *clkt = factor_hw->table;
1498c2ecf20Sopenharmony_ci	unsigned long long int rate;
1508c2ecf20Sopenharmony_ci	u32 reg, val, mul, div;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	div = 0;
1538c2ecf20Sopenharmony_ci	mul = 0;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	regmap_read(common->regmap, factor_hw->reg, &reg);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	val = reg >> factor_hw->shift;
1588c2ecf20Sopenharmony_ci	val &= div_mask(factor_hw);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	_get_table_div_mul(clkt, val, &mul, &div);
1618c2ecf20Sopenharmony_ci	if (!div) {
1628c2ecf20Sopenharmony_ci		WARN(!(factor_hw->fct_flags & CLK_DIVIDER_ALLOW_ZERO),
1638c2ecf20Sopenharmony_ci			"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
1648c2ecf20Sopenharmony_ci			__clk_get_name(common->hw.clk));
1658c2ecf20Sopenharmony_ci		return parent_rate;
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	rate = (unsigned long long int)parent_rate * mul;
1698c2ecf20Sopenharmony_ci	do_div(rate, div);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	return rate;
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic unsigned long owl_factor_recalc_rate(struct clk_hw *hw,
1758c2ecf20Sopenharmony_ci			unsigned long parent_rate)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	struct owl_factor *factor = hw_to_owl_factor(hw);
1788c2ecf20Sopenharmony_ci	struct owl_factor_hw *factor_hw = &factor->factor_hw;
1798c2ecf20Sopenharmony_ci	struct owl_clk_common *common = &factor->common;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	return owl_factor_helper_recalc_rate(common, factor_hw, parent_rate);
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ciint owl_factor_helper_set_rate(const struct owl_clk_common *common,
1858c2ecf20Sopenharmony_ci				const struct owl_factor_hw *factor_hw,
1868c2ecf20Sopenharmony_ci				unsigned long rate,
1878c2ecf20Sopenharmony_ci				unsigned long parent_rate)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	u32 val, reg;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	val = _get_table_val(factor_hw->table, rate, parent_rate);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	if (val > div_mask(factor_hw))
1948c2ecf20Sopenharmony_ci		val = div_mask(factor_hw);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	regmap_read(common->regmap, factor_hw->reg, &reg);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	reg &= ~(div_mask(factor_hw) << factor_hw->shift);
1998c2ecf20Sopenharmony_ci	reg |= val << factor_hw->shift;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	regmap_write(common->regmap, factor_hw->reg, reg);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	return 0;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic int owl_factor_set_rate(struct clk_hw *hw, unsigned long rate,
2078c2ecf20Sopenharmony_ci			       unsigned long parent_rate)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	struct owl_factor *factor = hw_to_owl_factor(hw);
2108c2ecf20Sopenharmony_ci	struct owl_factor_hw *factor_hw = &factor->factor_hw;
2118c2ecf20Sopenharmony_ci	struct owl_clk_common *common = &factor->common;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	return owl_factor_helper_set_rate(common, factor_hw,
2148c2ecf20Sopenharmony_ci					rate, parent_rate);
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ciconst struct clk_ops owl_factor_ops = {
2188c2ecf20Sopenharmony_ci	.round_rate	= owl_factor_round_rate,
2198c2ecf20Sopenharmony_ci	.recalc_rate	= owl_factor_recalc_rate,
2208c2ecf20Sopenharmony_ci	.set_rate	= owl_factor_set_rate,
2218c2ecf20Sopenharmony_ci};
222