[PATCH 3/5] clk: qcom: clk-branch: calculate timeout based on clock frequency

From: Xilin Wu

Date: Mon Apr 06 2026 - 11:56:24 EST


Clock branches with extremely low rates (tens of Hz to low kHz) take
much longer to toggle than the fixed 200 us timeout allows. A 1 kHz
clock needs at least 3 ms (3 cycles) to toggle.

Instead of increasing the timeout to a huge fixed value for all clocks,
dynamically compute the required timeout based on the current clock
rate, accounting for 3 cycles at the current clock rate.

Based on a downstream patch by Mike Tipton:
https://git.codelinaro.org/clo/la/kernel/qcom/-/commit/aa899c2d1fa31e247f04810f125ac9c60927c901

Fixes: 6e0ad1b6c1c9 ("clk: qcom: Add support for branches/gate clocks")
Signed-off-by: Mike Tipton <quic_mdtipton@xxxxxxxxxxx>
Signed-off-by: Xilin Wu <sophon@xxxxxxxxx>
---
drivers/clk/qcom/clk-branch.c | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c
index 444e7d8648d4..2641dcf93277 100644
--- a/drivers/clk/qcom/clk-branch.c
+++ b/drivers/clk/qcom/clk-branch.c
@@ -59,9 +59,27 @@ static bool clk_branch2_check_halt(const struct clk_branch *br, bool enabling)
return (val & CBCR_CLK_OFF) == (invert ? 0 : CBCR_CLK_OFF);
}

+static int get_branch_timeout(const struct clk_branch *br)
+{
+ unsigned long rate;
+ int timeout;
+
+ /*
+ * The time it takes a clock branch to toggle is roughly 3 clock cycles.
+ */
+ rate = clk_hw_get_rate(&br->clkr.hw);
+ if (!rate)
+ return 200;
+
+ timeout = 3 * (USEC_PER_SEC / rate);
+
+ return max(timeout, 200);
+}
+
static int clk_branch_wait(const struct clk_branch *br, bool enabling,
bool (check_halt)(const struct clk_branch *, bool))
{
+ int timeout, count;
bool voted = br->halt_check & BRANCH_VOTED;
const char *name = clk_hw_get_name(&br->clkr.hw);

@@ -77,9 +95,9 @@ static int clk_branch_wait(const struct clk_branch *br, bool enabling,
} else if (br->halt_check == BRANCH_HALT_ENABLE ||
br->halt_check == BRANCH_HALT ||
(enabling && voted)) {
- int count = 200;
+ timeout = get_branch_timeout(br);

- while (count-- > 0) {
+ for (count = timeout; count > 0; count--) {
if (check_halt(br, enabling))
return 0;
udelay(1);

--
2.53.0