[PATCH v2 1/2] clk: fractional-divider: switch to rational best approximation
From: Andy Shevchenko
Date: Mon Mar 30 2015 - 14:58:09 EST
This patch converts the code to use rational best approximation algorithm which
is more precise.
Suggested-by: Stephen Boyd <sboyd@xxxxxxxxxxxxxx>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx>
---
drivers/clk/Kconfig | 3 +--
drivers/clk/clk-fractional-divider.c | 39 ++++++++++++++----------------------
2 files changed, 16 insertions(+), 26 deletions(-)
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 0b474a0..46d90a9 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -14,6 +14,7 @@ config COMMON_CLK
select HAVE_CLK_PREPARE
select CLKDEV_LOOKUP
select SRCU
+ select RATIONAL
---help---
The common clock framework is a single definition of struct
clk, useful across many platforms, as well as an
@@ -63,7 +64,6 @@ config COMMON_CLK_SI5351
tristate "Clock driver for SiLabs 5351A/B/C"
depends on I2C
select REGMAP_I2C
- select RATIONAL
---help---
This driver supports Silicon Labs 5351A/B/C programmable clock
generators.
@@ -139,7 +139,6 @@ config COMMON_CLK_CDCE706
tristate "Clock driver for TI CDCE706 clock synthesizer"
depends on I2C
select REGMAP_I2C
- select RATIONAL
---help---
This driver supports TI CDCE706 programmable 3-PLL clock synthesizer.
diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c
index 6aa72d9..9c53704 100644
--- a/drivers/clk/clk-fractional-divider.c
+++ b/drivers/clk/clk-fractional-divider.c
@@ -7,13 +7,14 @@
*
* Adjustable fractional divider clock implementation.
* Output rate = (m / n) * parent_rate.
+ * Uses rational best approximation algorithm.
*/
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/slab.h>
-#include <linux/gcd.h>
+#include <linux/rational.h>
#define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw)
@@ -21,9 +22,9 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_fractional_divider *fd = to_clk_fd(hw);
+ unsigned long m, n;
unsigned long flags = 0;
- u32 val, m, n;
- u64 ret;
+ u32 val;
if (fd->lock)
spin_lock_irqsave(fd->lock, flags);
@@ -39,30 +40,22 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
if (!n || !m)
return parent_rate;
- ret = (u64)parent_rate * m;
- do_div(ret, n);
-
- return ret;
+ return mult_frac(parent_rate, m, n);
}
static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+ unsigned long *parent_rate)
{
struct clk_fractional_divider *fd = to_clk_fd(hw);
- unsigned maxn = (fd->nmask >> fd->nshift) + 1;
- unsigned div;
+ unsigned long m, n;
- if (!rate || rate >= *prate)
- return *prate;
+ if (!rate || rate >= *parent_rate)
+ return *parent_rate;
- div = gcd(*prate, rate);
-
- while ((*prate / div) > maxn) {
- div <<= 1;
- rate <<= 1;
- }
+ rational_best_approximation(rate, *parent_rate,
+ fd->mmask >> fd->mshift, fd->nmask >> fd->nshift, &m, &n);
- return rate;
+ return mult_frac(rate, m, n);
}
static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -70,13 +63,11 @@ 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 div;
- unsigned n, m;
+ unsigned long n, m;
u32 val;
- div = gcd(parent_rate, rate);
- m = rate / div;
- n = parent_rate / div;
+ rational_best_approximation(rate, parent_rate,
+ fd->mmask >> fd->mshift, fd->nmask >> fd->nshift, &m, &n);
if (fd->lock)
spin_lock_irqsave(fd->lock, flags);
--
2.1.4
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/