Skip to content

Commit

Permalink
clk: fractional-divider: Export approximation algorithm to the CCF users
Browse files Browse the repository at this point in the history
At least one user currently duplicates some functions that are provided
by fractional divider module. Let's export approximation algorithm and
replace the open-coded variant.

As a bonus the exported function will get better documentation in place.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Acked-by: Heiko Stuebner <heiko@sntech.de>
Link: https://lore.kernel.org/r/20210812170025.67074-1-andriy.shevchenko@linux.intel.com
[sboyd@kernel.org: Add header guard because why not]
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
  • Loading branch information
Andy Shevchenko authored and Stephen Boyd committed Aug 12, 2021
1 parent e73f0f0 commit 4e7cf74
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 18 deletions.
11 changes: 7 additions & 4 deletions drivers/clk/clk-fractional-divider.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#include <linux/slab.h>
#include <linux/rational.h>

#include "clk-fractional-divider.h"

static inline u32 clk_fd_readl(struct clk_fractional_divider *fd)
{
if (fd->flags & CLK_FRAC_DIVIDER_BIG_ENDIAN)
Expand Down Expand Up @@ -68,9 +70,10 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
return ret;
}

static void clk_fd_general_approximation(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate,
unsigned long *m, unsigned long *n)
void clk_fractional_divider_general_approximation(struct clk_hw *hw,
unsigned long rate,
unsigned long *parent_rate,
unsigned long *m, unsigned long *n)
{
struct clk_fractional_divider *fd = to_clk_fd(hw);
unsigned long scale;
Expand Down Expand Up @@ -102,7 +105,7 @@ static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
if (fd->approximation)
fd->approximation(hw, rate, parent_rate, &m, &n);
else
clk_fd_general_approximation(hw, rate, parent_rate, &m, &n);
clk_fractional_divider_general_approximation(hw, rate, parent_rate, &m, &n);

ret = (u64)*parent_rate * m;
do_div(ret, n);
Expand Down
13 changes: 13 additions & 0 deletions drivers/clk/clk-fractional-divider.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _CLK_FRACTIONAL_DIV_H
#define _CLK_FRACTIONAL_DIV_H

struct clk_hw;

void clk_fractional_divider_general_approximation(struct clk_hw *hw,
unsigned long rate,
unsigned long *parent_rate,
unsigned long *m,
unsigned long *n);

#endif
17 changes: 3 additions & 14 deletions drivers/clk/rockchip/clk.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include <linux/regmap.h>
#include <linux/reboot.h>
#include <linux/rational.h>

#include "../clk-fractional-divider.h"
#include "clk.h"

/*
Expand Down Expand Up @@ -178,10 +180,8 @@ static void rockchip_fractional_approximation(struct clk_hw *hw,
unsigned long rate, unsigned long *parent_rate,
unsigned long *m, unsigned long *n)
{
struct clk_fractional_divider *fd = to_clk_fd(hw);
unsigned long p_rate, p_parent_rate;
struct clk_hw *p_parent;
unsigned long scale;

p_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
if ((rate * 20 > p_rate) && (p_rate % rate != 0)) {
Expand All @@ -190,18 +190,7 @@ static void rockchip_fractional_approximation(struct clk_hw *hw,
*parent_rate = p_parent_rate;
}

/*
* Get rate closer to *parent_rate to guarantee there is no overflow
* for m and n. In the result it will be the nearest rate left shifted
* by (scale - fd->nwidth) bits.
*/
scale = fls_long(*parent_rate / rate - 1);
if (scale > fd->nwidth)
rate <<= scale - fd->nwidth;

rational_best_approximation(rate, *parent_rate,
GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
m, n);
clk_fractional_divider_general_approximation(hw, rate, parent_rate, m, n);
}

static struct clk *rockchip_clk_register_frac_branch(
Expand Down

0 comments on commit 4e7cf74

Please sign in to comment.