From 7f5a4fb5e8abcdd7f35e296f1755dacd91b2aab6 Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Mon, 22 Feb 2021 10:20:34 +0800 Subject: [PATCH] clk: rockchip: add flag CLK_FRAC_DIVIDER_NO_LIMIT for fractional divider There are some clks(uart) that do not have to comply with the 20 times fractional divider limit. Change-Id: I420d8ba3b5de65d9e0ea74920d5ea8450ae94465 Signed-off-by: Elaine Zhang --- drivers/clk/rockchip/clk.c | 22 +++++++++++++++++----- include/linux/clk-provider.h | 3 +++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index abf6c7fc5245..d7acb3be75d1 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -203,11 +203,23 @@ static void rockchip_fractional_approximation(struct clk_hw *hw, } 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); - *m = 0; - *n = 1; - return; + /* + * Fractional frequency divider to do + * integer frequency divider does not + * need 20 times the limit. + */ + if (!(*parent_rate % rate)) { + *m = 1; + *n = *parent_rate / rate; + return; + } else if (!(fd->flags & CLK_FRAC_DIVIDER_NO_LIMIT)) { + 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; + } } } diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 90fe290299cd..200a80e4bfed 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -953,6 +953,8 @@ void clk_hw_unregister_fixed_factor(struct clk_hw *hw); * CLK_FRAC_DIVIDER_BIG_ENDIAN - By default little endian register accesses are * used for the divider register. Setting this flag makes the register * accesses big endian. + * CLK_FRAC_DIVIDER_NO_LIMIT - not need to follow the 20 times limit on + * fractional divider */ struct clk_fractional_divider { struct clk_hw hw; @@ -975,6 +977,7 @@ struct clk_fractional_divider { #define CLK_FRAC_DIVIDER_ZERO_BASED BIT(0) #define CLK_FRAC_DIVIDER_BIG_ENDIAN BIT(1) +#define CLK_FRAC_DIVIDER_NO_LIMIT BIT(2) extern const struct clk_ops clk_fractional_divider_ops; struct clk *clk_register_fractional_divider(struct device *dev,