162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// OWL factor clock driver
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci// Copyright (c) 2014 Actions Semi Inc.
662306a36Sopenharmony_ci// Author: David Liu <liuwei@actions-semi.com>
762306a36Sopenharmony_ci//
862306a36Sopenharmony_ci// Copyright (c) 2018 Linaro Ltd.
962306a36Sopenharmony_ci// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/clk-provider.h>
1262306a36Sopenharmony_ci#include <linux/regmap.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "owl-factor.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic unsigned int _get_table_maxval(const struct clk_factor_table *table)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	unsigned int maxval = 0;
1962306a36Sopenharmony_ci	const struct clk_factor_table *clkt;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci	for (clkt = table; clkt->div; clkt++)
2262306a36Sopenharmony_ci		if (clkt->val > maxval)
2362306a36Sopenharmony_ci			maxval = clkt->val;
2462306a36Sopenharmony_ci	return maxval;
2562306a36Sopenharmony_ci}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic int _get_table_div_mul(const struct clk_factor_table *table,
2862306a36Sopenharmony_ci			unsigned int val, unsigned int *mul, unsigned int *div)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	const struct clk_factor_table *clkt;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	for (clkt = table; clkt->div; clkt++) {
3362306a36Sopenharmony_ci		if (clkt->val == val) {
3462306a36Sopenharmony_ci			*mul = clkt->mul;
3562306a36Sopenharmony_ci			*div = clkt->div;
3662306a36Sopenharmony_ci			return 1;
3762306a36Sopenharmony_ci		}
3862306a36Sopenharmony_ci	}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	return 0;
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic unsigned int _get_table_val(const struct clk_factor_table *table,
4462306a36Sopenharmony_ci			unsigned long rate, unsigned long parent_rate)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	const struct clk_factor_table *clkt;
4762306a36Sopenharmony_ci	int val = -1;
4862306a36Sopenharmony_ci	u64 calc_rate;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	for (clkt = table; clkt->div; clkt++) {
5162306a36Sopenharmony_ci		calc_rate = parent_rate * clkt->mul;
5262306a36Sopenharmony_ci		do_div(calc_rate, clkt->div);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci		if ((unsigned long)calc_rate <= rate) {
5562306a36Sopenharmony_ci			val = clkt->val;
5662306a36Sopenharmony_ci			break;
5762306a36Sopenharmony_ci		}
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	if (val == -1)
6162306a36Sopenharmony_ci		val = _get_table_maxval(table);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	return val;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic int owl_clk_val_best(const struct owl_factor_hw *factor_hw,
6762306a36Sopenharmony_ci			struct clk_hw *hw, unsigned long rate,
6862306a36Sopenharmony_ci			unsigned long *best_parent_rate)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	const struct clk_factor_table *clkt = factor_hw->table;
7162306a36Sopenharmony_ci	unsigned long parent_rate, try_parent_rate, best = 0, cur_rate;
7262306a36Sopenharmony_ci	unsigned long parent_rate_saved = *best_parent_rate;
7362306a36Sopenharmony_ci	int bestval = 0;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	if (!rate)
7662306a36Sopenharmony_ci		rate = 1;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
7962306a36Sopenharmony_ci		parent_rate = *best_parent_rate;
8062306a36Sopenharmony_ci		bestval = _get_table_val(clkt, rate, parent_rate);
8162306a36Sopenharmony_ci		return bestval;
8262306a36Sopenharmony_ci	}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	for (clkt = factor_hw->table; clkt->div; clkt++) {
8562306a36Sopenharmony_ci		try_parent_rate = rate * clkt->div / clkt->mul;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci		if (try_parent_rate == parent_rate_saved) {
8862306a36Sopenharmony_ci			pr_debug("%s: [%d %d %d] found try_parent_rate %ld\n",
8962306a36Sopenharmony_ci				__func__, clkt->val, clkt->mul, clkt->div,
9062306a36Sopenharmony_ci				try_parent_rate);
9162306a36Sopenharmony_ci			/*
9262306a36Sopenharmony_ci			 * It's the most ideal case if the requested rate can be
9362306a36Sopenharmony_ci			 * divided from parent clock without any need to change
9462306a36Sopenharmony_ci			 * parent rate, so return the divider immediately.
9562306a36Sopenharmony_ci			 */
9662306a36Sopenharmony_ci			*best_parent_rate = parent_rate_saved;
9762306a36Sopenharmony_ci			return clkt->val;
9862306a36Sopenharmony_ci		}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci		parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
10162306a36Sopenharmony_ci				try_parent_rate);
10262306a36Sopenharmony_ci		cur_rate = DIV_ROUND_UP(parent_rate, clkt->div) * clkt->mul;
10362306a36Sopenharmony_ci		if (cur_rate <= rate && cur_rate > best) {
10462306a36Sopenharmony_ci			bestval = clkt->val;
10562306a36Sopenharmony_ci			best = cur_rate;
10662306a36Sopenharmony_ci			*best_parent_rate = parent_rate;
10762306a36Sopenharmony_ci		}
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	if (!bestval) {
11162306a36Sopenharmony_ci		bestval = _get_table_maxval(clkt);
11262306a36Sopenharmony_ci		*best_parent_rate = clk_hw_round_rate(
11362306a36Sopenharmony_ci				clk_hw_get_parent(hw), 1);
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return bestval;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cilong owl_factor_helper_round_rate(struct owl_clk_common *common,
12062306a36Sopenharmony_ci				const struct owl_factor_hw *factor_hw,
12162306a36Sopenharmony_ci				unsigned long rate,
12262306a36Sopenharmony_ci				unsigned long *parent_rate)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	const struct clk_factor_table *clkt = factor_hw->table;
12562306a36Sopenharmony_ci	unsigned int val, mul = 0, div = 1;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	val = owl_clk_val_best(factor_hw, &common->hw, rate, parent_rate);
12862306a36Sopenharmony_ci	_get_table_div_mul(clkt, val, &mul, &div);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	return *parent_rate * mul / div;
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic long owl_factor_round_rate(struct clk_hw *hw, unsigned long rate,
13462306a36Sopenharmony_ci			unsigned long *parent_rate)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	struct owl_factor *factor = hw_to_owl_factor(hw);
13762306a36Sopenharmony_ci	struct owl_factor_hw *factor_hw = &factor->factor_hw;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	return owl_factor_helper_round_rate(&factor->common, factor_hw,
14062306a36Sopenharmony_ci					rate, parent_rate);
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ciunsigned long owl_factor_helper_recalc_rate(struct owl_clk_common *common,
14462306a36Sopenharmony_ci					 const struct owl_factor_hw *factor_hw,
14562306a36Sopenharmony_ci					 unsigned long parent_rate)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	const struct clk_factor_table *clkt = factor_hw->table;
14862306a36Sopenharmony_ci	unsigned long long int rate;
14962306a36Sopenharmony_ci	u32 reg, val, mul, div;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	div = 0;
15262306a36Sopenharmony_ci	mul = 0;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	regmap_read(common->regmap, factor_hw->reg, &reg);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	val = reg >> factor_hw->shift;
15762306a36Sopenharmony_ci	val &= div_mask(factor_hw);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	_get_table_div_mul(clkt, val, &mul, &div);
16062306a36Sopenharmony_ci	if (!div) {
16162306a36Sopenharmony_ci		WARN(!(factor_hw->fct_flags & CLK_DIVIDER_ALLOW_ZERO),
16262306a36Sopenharmony_ci			"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
16362306a36Sopenharmony_ci			__clk_get_name(common->hw.clk));
16462306a36Sopenharmony_ci		return parent_rate;
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	rate = (unsigned long long int)parent_rate * mul;
16862306a36Sopenharmony_ci	do_div(rate, div);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	return rate;
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic unsigned long owl_factor_recalc_rate(struct clk_hw *hw,
17462306a36Sopenharmony_ci			unsigned long parent_rate)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	struct owl_factor *factor = hw_to_owl_factor(hw);
17762306a36Sopenharmony_ci	struct owl_factor_hw *factor_hw = &factor->factor_hw;
17862306a36Sopenharmony_ci	struct owl_clk_common *common = &factor->common;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	return owl_factor_helper_recalc_rate(common, factor_hw, parent_rate);
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ciint owl_factor_helper_set_rate(const struct owl_clk_common *common,
18462306a36Sopenharmony_ci				const struct owl_factor_hw *factor_hw,
18562306a36Sopenharmony_ci				unsigned long rate,
18662306a36Sopenharmony_ci				unsigned long parent_rate)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	u32 val, reg;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	val = _get_table_val(factor_hw->table, rate, parent_rate);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	if (val > div_mask(factor_hw))
19362306a36Sopenharmony_ci		val = div_mask(factor_hw);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	regmap_read(common->regmap, factor_hw->reg, &reg);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	reg &= ~(div_mask(factor_hw) << factor_hw->shift);
19862306a36Sopenharmony_ci	reg |= val << factor_hw->shift;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	regmap_write(common->regmap, factor_hw->reg, reg);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	return 0;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic int owl_factor_set_rate(struct clk_hw *hw, unsigned long rate,
20662306a36Sopenharmony_ci			       unsigned long parent_rate)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct owl_factor *factor = hw_to_owl_factor(hw);
20962306a36Sopenharmony_ci	struct owl_factor_hw *factor_hw = &factor->factor_hw;
21062306a36Sopenharmony_ci	struct owl_clk_common *common = &factor->common;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	return owl_factor_helper_set_rate(common, factor_hw,
21362306a36Sopenharmony_ci					rate, parent_rate);
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ciconst struct clk_ops owl_factor_ops = {
21762306a36Sopenharmony_ci	.round_rate	= owl_factor_round_rate,
21862306a36Sopenharmony_ci	.recalc_rate	= owl_factor_recalc_rate,
21962306a36Sopenharmony_ci	.set_rate	= owl_factor_set_rate,
22062306a36Sopenharmony_ci};
221