// SPDX-License-Identifier: GPL-2.0 /* * KUnit test for clk fixed rate basic type */ #include #include #include #include #include #include #include #include #include #include #include "clk-fixed-rate_test.h" /** * struct clk_hw_fixed_rate_kunit_params - Parameters to pass to __clk_hw_register_fixed_rate() * @dev: device registering clk * @np: device_node of device registering clk * @name: name of clk * @parent_name: parent name of clk * @parent_hw: clk_hw pointer to parent of clk * @parent_data: parent_data describing parent of clk * @flags: clk framework flags * @fixed_rate: frequency of clk * @fixed_accuracy: accuracy of clk * @clk_fixed_flags: fixed rate specific clk flags */ struct clk_hw_fixed_rate_kunit_params { struct device *dev; struct device_node *np; const char *name; const char *parent_name; const struct clk_hw *parent_hw; const struct clk_parent_data *parent_data; unsigned long flags; unsigned long fixed_rate; unsigned long fixed_accuracy; unsigned long clk_fixed_flags; }; static int clk_hw_register_fixed_rate_kunit_init(struct kunit_resource *res, void *context) { struct clk_hw_fixed_rate_kunit_params *params = context; struct clk_hw *hw; hw = __clk_hw_register_fixed_rate(params->dev, params->np, params->name, params->parent_name, params->parent_hw, params->parent_data, params->flags, params->fixed_rate, params->fixed_accuracy, params->clk_fixed_flags, false); if (IS_ERR(hw)) return PTR_ERR(hw); res->data = hw; return 0; } static void clk_hw_register_fixed_rate_kunit_exit(struct kunit_resource *res) { struct clk_hw *hw = res->data; clk_hw_unregister_fixed_rate(hw); } /** * clk_hw_register_fixed_rate_kunit() - Test managed __clk_hw_register_fixed_rate() * @test: The test context * @params: Arguments to __clk_hw_register_fixed_rate() * * Return: Registered fixed rate clk_hw or ERR_PTR on failure */ static struct clk_hw * clk_hw_register_fixed_rate_kunit(struct kunit *test, struct clk_hw_fixed_rate_kunit_params *params) { struct clk_hw *hw; hw = kunit_alloc_resource(test, clk_hw_register_fixed_rate_kunit_init, clk_hw_register_fixed_rate_kunit_exit, GFP_KERNEL, params); if (!hw) return ERR_PTR(-EINVAL); return hw; } /** * clk_hw_unregister_fixed_rate_kunit() - Test managed clk_hw_unregister_fixed_rate() * @test: The test context * @hw: fixed rate clk to unregister upon test completion * * Automatically unregister @hw when @test is complete via * clk_hw_unregister_fixed_rate(). * * Return: 0 on success or negative errno on failure */ static int clk_hw_unregister_fixed_rate_kunit(struct kunit *test, struct clk_hw *hw) { if (!kunit_alloc_resource(test, NULL, clk_hw_register_fixed_rate_kunit_exit, GFP_KERNEL, hw)) return -ENOMEM; return 0; } /* * Test that clk_get_rate() on a fixed rate clk registered with * clk_hw_register_fixed_rate() gets the proper frequency. */ static void clk_fixed_rate_rate_test(struct kunit *test) { struct clk_hw *hw; struct clk *clk; const unsigned long fixed_rate = 230000; hw = clk_hw_register_fixed_rate(NULL, "test-fixed-rate", NULL, 0, fixed_rate); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); KUNIT_ASSERT_EQ(test, 0, clk_hw_unregister_fixed_rate_kunit(test, hw)); clk = clk_hw_get_clk_prepared_enabled_kunit(test, hw, __func__); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk); KUNIT_EXPECT_EQ(test, fixed_rate, clk_get_rate(clk)); } /* * Test that clk_get_accuracy() on a fixed rate clk registered via * clk_hw_register_fixed_rate_with_accuracy() gets the proper accuracy. */ static void clk_fixed_rate_accuracy_test(struct kunit *test) { struct clk_hw *hw; struct clk *clk; const unsigned long fixed_accuracy = 5000; hw = clk_hw_register_fixed_rate_with_accuracy(NULL, "test-fixed-rate", NULL, 0, 0, fixed_accuracy); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); KUNIT_ASSERT_EQ(test, 0, clk_hw_unregister_fixed_rate_kunit(test, hw)); clk = clk_hw_get_clk_kunit(test, hw, __func__); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk); KUNIT_EXPECT_EQ(test, fixed_accuracy, clk_get_accuracy(clk)); } /* Test suite for a fixed rate clk without any parent */ static struct kunit_case clk_fixed_rate_test_cases[] = { KUNIT_CASE(clk_fixed_rate_rate_test), KUNIT_CASE(clk_fixed_rate_accuracy_test), {} }; static struct kunit_suite clk_fixed_rate_suite = { .name = "clk_fixed_rate", .test_cases = clk_fixed_rate_test_cases, }; /* * Test that clk_get_parent() on a fixed rate clk gets the proper parent. */ static void clk_fixed_rate_parent_test(struct kunit *test) { struct clk_hw *hw, *parent_hw; struct clk *expected_parent, *actual_parent; struct clk *clk; const char *parent_name = "test-fixed-rate-parent"; struct clk_hw_fixed_rate_kunit_params parent_params = { .name = parent_name, }; parent_hw = clk_hw_register_fixed_rate_kunit(test, &parent_params); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_hw); KUNIT_ASSERT_STREQ(test, parent_name, clk_hw_get_name(parent_hw)); expected_parent = clk_hw_get_clk_kunit(test, parent_hw, __func__); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, expected_parent); hw = clk_hw_register_fixed_rate(NULL, "test-fixed-rate", parent_name, 0, 0); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); KUNIT_ASSERT_EQ(test, 0, clk_hw_unregister_fixed_rate_kunit(test, hw)); clk = clk_hw_get_clk_kunit(test, hw, __func__); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk); actual_parent = clk_get_parent(clk); KUNIT_EXPECT_TRUE(test, clk_is_match(expected_parent, actual_parent)); } /* * Test that clk_get_rate() on a fixed rate clk ignores the parent rate. */ static void clk_fixed_rate_parent_rate_test(struct kunit *test) { struct clk_hw *hw, *parent_hw; struct clk *clk; const unsigned long expected_rate = 1405; const unsigned long parent_rate = 90402; const char *parent_name = "test-fixed-rate-parent"; struct clk_hw_fixed_rate_kunit_params parent_params = { .name = parent_name, .fixed_rate = parent_rate, }; parent_hw = clk_hw_register_fixed_rate_kunit(test, &parent_params); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_hw); KUNIT_ASSERT_STREQ(test, parent_name, clk_hw_get_name(parent_hw)); hw = clk_hw_register_fixed_rate(NULL, "test-fixed-rate", parent_name, 0, expected_rate); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); KUNIT_ASSERT_EQ(test, 0, clk_hw_unregister_fixed_rate_kunit(test, hw)); clk = clk_hw_get_clk_prepared_enabled_kunit(test, hw, __func__); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk); KUNIT_EXPECT_EQ(test, expected_rate, clk_get_rate(clk)); } /* * Test that clk_get_accuracy() on a fixed rate clk ignores the parent accuracy. */ static void clk_fixed_rate_parent_accuracy_test(struct kunit *test) { struct clk_hw *hw, *parent_hw; struct clk *clk; const unsigned long expected_accuracy = 900; const unsigned long parent_accuracy = 24000; const char *parent_name = "test-fixed-rate-parent"; struct clk_hw_fixed_rate_kunit_params parent_params = { .name = parent_name, .fixed_accuracy = parent_accuracy, }; parent_hw = clk_hw_register_fixed_rate_kunit(test, &parent_params); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_hw); KUNIT_ASSERT_STREQ(test, parent_name, clk_hw_get_name(parent_hw)); hw = clk_hw_register_fixed_rate_with_accuracy(NULL, "test-fixed-rate", parent_name, 0, 0, expected_accuracy); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); KUNIT_ASSERT_EQ(test, 0, clk_hw_unregister_fixed_rate_kunit(test, hw)); clk = clk_hw_get_clk_kunit(test, hw, __func__); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk); KUNIT_EXPECT_EQ(test, expected_accuracy, clk_get_accuracy(clk)); } /* Test suite for a fixed rate clk with a parent */ static struct kunit_case clk_fixed_rate_parent_test_cases[] = { KUNIT_CASE(clk_fixed_rate_parent_test), KUNIT_CASE(clk_fixed_rate_parent_rate_test), KUNIT_CASE(clk_fixed_rate_parent_accuracy_test), {} }; static struct kunit_suite clk_fixed_rate_parent_suite = { .name = "clk_fixed_rate_parent", .test_cases = clk_fixed_rate_parent_test_cases, }; struct clk_fixed_rate_of_test_context { struct device *dev; struct platform_driver pdrv; struct completion probed; }; static inline struct clk_fixed_rate_of_test_context * pdev_to_clk_fixed_rate_of_test_context(struct platform_device *pdev) { return container_of(to_platform_driver(pdev->dev.driver), struct clk_fixed_rate_of_test_context, pdrv); } /* * Test that of_fixed_clk_setup() registers a fixed rate clk with the proper * rate. */ static void clk_fixed_rate_of_probe_test(struct kunit *test) { struct clk_fixed_rate_of_test_context *ctx = test->priv; struct device *dev = ctx->dev; struct clk *clk; clk = clk_get_kunit(test, dev, NULL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk); KUNIT_ASSERT_EQ(test, 0, clk_prepare_enable_kunit(test, clk)); KUNIT_EXPECT_EQ(test, TEST_FIXED_FREQUENCY, clk_get_rate(clk)); } /* * Test that of_fixed_clk_setup() registers a fixed rate clk with the proper * accuracy. */ static void clk_fixed_rate_of_accuracy_test(struct kunit *test) { struct clk_fixed_rate_of_test_context *ctx = test->priv; struct device *dev = ctx->dev; struct clk *clk; clk = clk_get_kunit(test, dev, NULL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk); KUNIT_EXPECT_EQ(test, TEST_FIXED_ACCURACY, clk_get_accuracy(clk)); } static struct kunit_case clk_fixed_rate_of_cases[] = { KUNIT_CASE(clk_fixed_rate_of_probe_test), KUNIT_CASE(clk_fixed_rate_of_accuracy_test), {} }; static int clk_fixed_rate_of_test_probe(struct platform_device *pdev) { struct clk_fixed_rate_of_test_context *ctx; ctx = pdev_to_clk_fixed_rate_of_test_context(pdev); ctx->dev = &pdev->dev; complete(&ctx->probed); return 0; } static int clk_fixed_rate_of_init(struct kunit *test) { struct clk_fixed_rate_of_test_context *ctx; static const struct of_device_id match_table[] = { { .compatible = "test,single-clk-consumer" }, { } }; KUNIT_ASSERT_EQ(test, 0, of_overlay_apply_kunit(test, kunit_clk_fixed_rate_test)); ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); test->priv = ctx; ctx->pdrv.probe = clk_fixed_rate_of_test_probe; ctx->pdrv.driver.of_match_table = match_table; ctx->pdrv.driver.name = __func__; ctx->pdrv.driver.owner = THIS_MODULE; init_completion(&ctx->probed); KUNIT_ASSERT_EQ(test, 0, kunit_platform_driver_register(test, &ctx->pdrv)); KUNIT_ASSERT_NE(test, 0, wait_for_completion_timeout(&ctx->probed, HZ)); return 0; } static struct kunit_suite clk_fixed_rate_of_suite = { .name = "clk_fixed_rate_of", .init = clk_fixed_rate_of_init, .test_cases = clk_fixed_rate_of_cases, }; kunit_test_suites( &clk_fixed_rate_suite, &clk_fixed_rate_of_suite, &clk_fixed_rate_parent_suite, ); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("KUnit test for clk fixed rate basic type");