Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: fractional-divider: allow overriding of approximation

Fractional dividers may have special requirements concerning numerator
and denominator selection that differ from just getting the best
approximation.

For example on Rockchip socs the denominator must be at least 20 times
larger than the numerator to generate precise clock frequencies.

Therefore add the ability to provide custom approximation functions.

Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
Acked-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>

authored by

Elaine Zhang and committed by
Heiko Stuebner
ec52e462 33461405

+23 -8
+20 -8
drivers/clk/clk-fractional-divider.c
··· 49 49 return ret; 50 50 } 51 51 52 - static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate, 53 - unsigned long *parent_rate) 52 + static void clk_fd_general_approximation(struct clk_hw *hw, unsigned long rate, 53 + unsigned long *parent_rate, 54 + unsigned long *m, unsigned long *n) 54 55 { 55 56 struct clk_fractional_divider *fd = to_clk_fd(hw); 56 57 unsigned long scale; 57 - unsigned long m, n; 58 - u64 ret; 59 - 60 - if (!rate || rate >= *parent_rate) 61 - return *parent_rate; 62 58 63 59 /* 64 60 * Get rate closer to *parent_rate to guarantee there is no overflow ··· 67 71 68 72 rational_best_approximation(rate, *parent_rate, 69 73 GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0), 70 - &m, &n); 74 + m, n); 75 + } 76 + 77 + static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate, 78 + unsigned long *parent_rate) 79 + { 80 + struct clk_fractional_divider *fd = to_clk_fd(hw); 81 + unsigned long m, n; 82 + u64 ret; 83 + 84 + if (!rate || rate >= *parent_rate) 85 + return *parent_rate; 86 + 87 + if (fd->approximation) 88 + fd->approximation(hw, rate, parent_rate, &m, &n); 89 + else 90 + clk_fd_general_approximation(hw, rate, parent_rate, &m, &n); 71 91 72 92 ret = (u64)*parent_rate * m; 73 93 do_div(ret, n);
+3
include/linux/clk-provider.h
··· 565 565 u8 nwidth; 566 566 u32 nmask; 567 567 u8 flags; 568 + void (*approximation)(struct clk_hw *hw, 569 + unsigned long rate, unsigned long *parent_rate, 570 + unsigned long *m, unsigned long *n); 568 571 spinlock_t *lock; 569 572 }; 570 573