diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 1dd6bfb7aa0eb..790e86c806b95 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -453,7 +453,7 @@ static int clk_rcg2_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); - u32 notn_m, n, m, d, not2d, mask, duty_per, cfg; + u32 notn_m, n, m, d, not2d, mask, cfg; int ret; /* Duty-cycle cannot be modified for non-MND RCGs */ @@ -472,21 +472,14 @@ static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) n = (~(notn_m) + m) & mask; - duty_per = (duty->num * 100) / duty->den; - - /* Calculate 2d value */ - d = DIV_ROUND_CLOSEST(n * duty_per * 2, 100); + /* Calculate 2d value directly from the requested duty ratio */ + d = DIV_ROUND_CLOSEST_ULL((u64)n * duty->num * 2, duty->den); /* - * Check bit widths of 2d. If D is too big reduce duty cycle. - * Also make sure it is never zero. + * Check bit widths of 2d. Clamp 2d to the hardware range [m, 2*(n-m)] + * so it is never zero and never exceeds the maximum achievable duty. */ - d = clamp_val(d, 1, mask); - - if ((d / 2) > (n - m)) - d = (n - m) * 2; - else if ((d / 2) < (m / 2)) - d = m; + d = clamp_val(d, m, (n - m) * 2); not2d = ~d & mask; @@ -1039,6 +1032,23 @@ clk_rcg2_shared_force_enable_clear(struct clk_hw *hw, const struct freq_tbl *f) return clk_rcg2_clear_force_enable(hw); } +static int clk_rcg2_shared_set_duty_cycle(struct clk_hw *hw, + struct clk_duty *duty) +{ + int ret; + + ret = clk_rcg2_set_force_enable(hw); + if (ret) + return ret; + + ret = clk_rcg2_set_duty_cycle(hw, duty); + + if (clk_rcg2_clear_force_enable(hw)) + return -EBUSY; + + return ret; +} + static int __clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate, enum freq_policy policy) @@ -1224,6 +1234,8 @@ const struct clk_ops clk_rcg2_shared_ops = { .determine_rate = clk_rcg2_determine_rate, .set_rate = clk_rcg2_shared_set_rate, .set_rate_and_parent = clk_rcg2_shared_set_rate_and_parent, + .get_duty_cycle = clk_rcg2_get_duty_cycle, + .set_duty_cycle = clk_rcg2_shared_set_duty_cycle, }; EXPORT_SYMBOL_GPL(clk_rcg2_shared_ops); diff --git a/drivers/clk/qcom/gcc-sa8775p.c b/drivers/clk/qcom/gcc-sa8775p.c index 95b2a1334d19b..d67e21ce3d07c 100644 --- a/drivers/clk/qcom/gcc-sa8775p.c +++ b/drivers/clk/qcom/gcc-sa8775p.c @@ -726,7 +726,7 @@ static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = { F(10000, P_BI_TCXO, 16, 1, 120), F(20000, P_BI_TCXO, 16, 1, 60), F(25000, P_BI_TCXO, 16, 1, 48), - F(40000, P_BI_TCXO, 16, 1, 30), + F(40000, P_BI_TCXO, 2, 1, 240), F(100000, P_BI_TCXO, 16, 1, 12), F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), @@ -743,7 +743,7 @@ static struct clk_rcg2 gcc_gp1_clk_src = { .name = "gcc_gp1_clk_src", .parent_data = gcc_parent_data_2, .num_parents = ARRAY_SIZE(gcc_parent_data_2), - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -757,7 +757,7 @@ static struct clk_rcg2 gcc_gp2_clk_src = { .name = "gcc_gp2_clk_src", .parent_data = gcc_parent_data_2, .num_parents = ARRAY_SIZE(gcc_parent_data_2), - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -771,7 +771,7 @@ static struct clk_rcg2 gcc_gp3_clk_src = { .name = "gcc_gp3_clk_src", .parent_data = gcc_parent_data_2, .num_parents = ARRAY_SIZE(gcc_parent_data_2), - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -785,7 +785,7 @@ static struct clk_rcg2 gcc_gp4_clk_src = { .name = "gcc_gp4_clk_src", .parent_data = gcc_parent_data_2, .num_parents = ARRAY_SIZE(gcc_parent_data_2), - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -799,7 +799,7 @@ static struct clk_rcg2 gcc_gp5_clk_src = { .name = "gcc_gp5_clk_src", .parent_data = gcc_parent_data_2, .num_parents = ARRAY_SIZE(gcc_parent_data_2), - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, };