#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/completion.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <kunit/clk.h>
#include <kunit/of.h>
#include <kunit/platform_device.h>
#include <kunit/resource.h>
#include <kunit/test.h>
#include "clk-fixed-rate_test.h"
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);
}
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;
}
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;
}
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));
}
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));
}
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,
};
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));
}
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));
}
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));
}
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);
}
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));
}
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");