[PATCH v4 2/5] clk: rockchip: fix up the frac clk get rate error

From: Elaine Zhang
Date: Tue Oct 13 2020 - 22:36:08 EST


support fractional divider with one level and two level parent clock
.i.e:

normal fractional divider is:
|--\
---[GPLL]---| \ |--\
---[CPLL]---|mux|--[GATE]--[DIV]-----------------------| \
---[NPLL]---| / | |mux|--[GATE]--[UART0]
|--/ |--[GATE]--[FRACDIV]--| /
|--/
but rk3399 uart is special:
|--\
---[GPLL]---| \ |--\
---[CPLL]---|mux|--|--[GATE]--[DIV]-----------------------| \
---[NPLL]---| / | | |mux|--[GATE]--[UART1]
|--/ | |--[GATE]--[FRACDIV]--| /
| |--/
|
| |--\
|--[GATE]--[DIV]-----------------------| \
| | |mux|--[GATE]--[UART2]
| |--[GATE]--[FRACDIV]--| /
| |--/
|
| |--\
|--[GATE]--[DIV]-----------------------| \
| |mux|--[GATE]--[UART3]
|--[GATE]--[FRACDIV]--| /
|--/

The special fractional divider, there are two levels of clock between FRACDIV and PLL.

Signed-off-by: Elaine Zhang <zhangqing@xxxxxxxxxxxxxx>
---
drivers/clk/rockchip/clk.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
index fac5a4a3f5c3..8f77c3f9fab7 100644
--- a/drivers/clk/rockchip/clk.c
+++ b/drivers/clk/rockchip/clk.c
@@ -190,16 +190,21 @@ static void rockchip_fractional_approximation(struct clk_hw *hw,
if (((rate * 20 > p_rate) && (p_rate % rate != 0)) ||
(fd->max_prate && fd->max_prate < p_rate)) {
p_parent = clk_hw_get_parent(clk_hw_get_parent(hw));
- p_parent_rate = clk_hw_get_rate(p_parent);
- *parent_rate = p_parent_rate;
- if (fd->max_prate && p_parent_rate > fd->max_prate) {
- div = DIV_ROUND_UP(p_parent_rate, fd->max_prate);
- *parent_rate = p_parent_rate / div;
+ if (!p_parent) {
+ *parent_rate = p_rate;
+ } else {
+ p_parent_rate = clk_hw_get_rate(p_parent);
+ *parent_rate = p_parent_rate;
+ if (fd->max_prate && p_parent_rate > fd->max_prate) {
+ div = DIV_ROUND_UP(p_parent_rate,
+ fd->max_prate);
+ *parent_rate = p_parent_rate / div;
+ }
}

if (*parent_rate < rate * 20) {
- pr_err("%s parent_rate(%ld) is low than rate(%ld)*20, fractional div is not allowed\n",
- clk_hw_get_name(hw), *parent_rate, rate);
+ pr_warn("%s p_rate(%ld) is low than rate(%ld)*20, use integer or half-div\n",
+ clk_hw_get_name(hw), *parent_rate, rate);
*m = 0;
*n = 1;
return;
--
2.17.1