@@ -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;
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@rock-chips.com> --- drivers/clk/rockchip/clk.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)