[PATCH v6 7/7] clk: test: introduce additional test case showing v2 rate change + LCM parent
From: Brian Masney
Date: Fri Mar 13 2026 - 12:48:20 EST
Add a test case that uses the clk divider with the v2 rate negotiation
logic, plus the Lowest Common Multiple (LCM) to calculate the optimal
parent rate. The test ensures that the parent clk rate is set to a rate
that's acceptable to both children, and the sibling clock is not
affected.
The test in this commit use the following simplified clk tree with
the initial state:
parent
24 MHz
/ \
child1 child2
24 MHz 24 MHz
child1 and child2 both divider-only clocks that have CLK_SET_RATE_PARENT
set, and the parent is capable of achieving any rate.
child1 requests 32 MHz, and the tree ends up with the correct state:
parent
96 MHz
/ \
child1 child2
32 MHz 24 MHz
div=3 div=4
Additionally, add a note about why clk_dummy_div_lcm_ops + friends are
still needed.
Link: https://lore.kernel.org/linux-clk/aUSWU7UymULCXOeF@xxxxxxxxxx/
Link: https://lpc.events/event/19/contributions/2152/
Signed-off-by: Brian Masney <bmasney@xxxxxxxxxx>
---
drivers/clk/clk_test.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
index 40bc01a0259d8d49ca4c1983b6c10a3684a95f0b..00511afe5faa8b2631633ab796ece1bfe6944fb5 100644
--- a/drivers/clk/clk_test.c
+++ b/drivers/clk/clk_test.c
@@ -181,6 +181,14 @@ static const struct clk_ops clk_dummy_div_ops = {
.set_rate = clk_dummy_div_set_rate,
};
+/*
+ * drivers/clk/clk-divider.c has support for v2 rate negotiation, and setting
+ * the parent based on the LCM, however we need to be able to test just setting
+ * the parent rate based on the LCM, and not set the v2 rate negotiation flag.
+ * This is to demonstrate existing functionality in the clk core, and ensure it
+ * stays the same. That's why we need to keep clk_dummy_div_lcm_ops, and can't
+ * just use clk_dummy_div_ops.
+ */
static int clk_dummy_div_lcm_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
@@ -709,6 +717,18 @@ clk_rate_change_sibling_div_div_test_lcm_ops_v1_params[] = {
KUNIT_ARRAY_PARAM_DESC(clk_rate_change_sibling_div_div_test_lcm_ops_v1,
clk_rate_change_sibling_div_div_test_lcm_ops_v1_params, desc)
+static const struct clk_rate_change_sibling_div_div_test_param
+clk_rate_change_sibling_div_div_test_regular_ops_v2_params[] = {
+ {
+ .desc = "regular_ops_v2",
+ .ops = &clk_dummy_div_ops,
+ .extra_child_flags = CLK_V2_RATE_NEGOTIATION,
+ },
+};
+
+KUNIT_ARRAY_PARAM_DESC(clk_rate_change_sibling_div_div_test_regular_ops_v2,
+ clk_rate_change_sibling_div_div_test_regular_ops_v2_params, desc)
+
static int clk_rate_change_sibling_div_div_test_init(struct kunit *test)
{
const struct clk_rate_change_sibling_div_div_test_param *param = test->param_value;
@@ -836,6 +856,31 @@ static void clk_test_rate_change_sibling_div_div_3_v1(struct kunit *test)
KUNIT_EXPECT_EQ(test, ctx->child2.div, 1);
}
+/*
+ * Test that, for a parent with two divider-only children with CLK_SET_RATE_PARENT
+ * set and one requests a rate incompatible with the existing parent rate, the
+ * sibling rate is not affected, and maintains it's rate.
+ */
+static void clk_test_rate_change_sibling_div_div_4_v2(struct kunit *test)
+{
+ struct clk_rate_change_sibling_div_div_context *ctx = test->priv;
+ int ret;
+
+ ret = clk_set_rate(ctx->child1_clk, 32 * HZ_PER_MHZ);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ /*
+ * With LCM-based parent + v2 rate changes, the parent should be at
+ * 96 MHz (LCM of 32 and 24), child1 at 32 MHz (div=3), and child2
+ * at 24 MHz (div=4).
+ */
+ KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->parent_clk), 96 * HZ_PER_MHZ);
+ KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child1_clk), 32 * HZ_PER_MHZ);
+ KUNIT_EXPECT_EQ(test, ctx->child1.div, 3);
+ KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child2_clk), 24 * HZ_PER_MHZ);
+ KUNIT_EXPECT_EQ(test, ctx->child2.div, 4);
+}
+
static struct kunit_case clk_rate_change_sibling_div_div_cases[] = {
KUNIT_CASE_PARAM(clk_test_rate_change_sibling_div_div_1,
clk_rate_change_sibling_div_div_test_regular_ops_gen_params),
@@ -843,6 +888,10 @@ static struct kunit_case clk_rate_change_sibling_div_div_cases[] = {
clk_rate_change_sibling_div_div_test_regular_ops_gen_params),
KUNIT_CASE_PARAM(clk_test_rate_change_sibling_div_div_3_v1,
clk_rate_change_sibling_div_div_test_lcm_ops_v1_gen_params),
+ KUNIT_CASE_PARAM(clk_test_rate_change_sibling_div_div_1,
+ clk_rate_change_sibling_div_div_test_regular_ops_v2_gen_params),
+ KUNIT_CASE_PARAM(clk_test_rate_change_sibling_div_div_4_v2,
+ clk_rate_change_sibling_div_div_test_regular_ops_v2_gen_params),
{}
};
--
2.53.0