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, ®); 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, ®); 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