clk: fractional-divider: Improve approximation when zero based and export

Consider the CLK_FRAC_DIVIDER_ZERO_BASED flag when finding the best
approximation for m and n. By doing so, increase the range of valid
values for the numerator and denominator by 1.

Furthermore, export the approximation function so that users of this
function can be compiled as modules.

Cc: A.s. Dong <aisheng.dong@nxp.com>
Signed-off-by: Frank Oltmanns <frank@oltmanns.dev>
Link: https://lore.kernel.org/r/20230617131041.18313-2-frank@oltmanns.dev
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
This commit is contained in:
Frank Oltmanns 2023-06-17 15:10:40 +02:00 committed by Stephen Boyd
parent 0bb80ecc33
commit 2e9abc6ec1
1 changed files with 20 additions and 7 deletions

View File

@ -123,6 +123,7 @@ void clk_fractional_divider_general_approximation(struct clk_hw *hw,
unsigned long *m, unsigned long *n)
{
struct clk_fractional_divider *fd = to_clk_fd(hw);
unsigned long max_m, max_n;
/*
* Get rate closer to *parent_rate to guarantee there is no overflow
@ -138,10 +139,17 @@ void clk_fractional_divider_general_approximation(struct clk_hw *hw,
rate <<= scale - fd->nwidth;
}
rational_best_approximation(rate, *parent_rate,
GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
m, n);
if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) {
max_m = 1 << fd->mwidth;
max_n = 1 << fd->nwidth;
} else {
max_m = GENMASK(fd->mwidth - 1, 0);
max_n = GENMASK(fd->nwidth - 1, 0);
}
rational_best_approximation(rate, *parent_rate, max_m, max_n, m, n);
}
EXPORT_SYMBOL_GPL(clk_fractional_divider_general_approximation);
static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
@ -169,13 +177,18 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
{
struct clk_fractional_divider *fd = to_clk_fd(hw);
unsigned long flags = 0;
unsigned long m, n;
unsigned long m, n, max_m, max_n;
u32 mmask, nmask;
u32 val;
rational_best_approximation(rate, parent_rate,
GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
&m, &n);
if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) {
max_m = 1 << fd->mwidth;
max_n = 1 << fd->nwidth;
} else {
max_m = GENMASK(fd->mwidth - 1, 0);
max_n = GENMASK(fd->nwidth - 1, 0);
}
rational_best_approximation(rate, parent_rate, max_m, max_n, &m, &n);
if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) {
m--;