1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Kunit test for clk gate basic type
4 */
5#include <linux/clk.h>
6#include <linux/clk-provider.h>
7#include <linux/platform_device.h>
8
9#include <kunit/test.h>
10
11static void clk_gate_register_test_dev(struct kunit *test)
12{
13	struct clk_hw *ret;
14	struct platform_device *pdev;
15
16	pdev = platform_device_register_simple("test_gate_device", -1, NULL, 0);
17	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
18
19	ret = clk_hw_register_gate(&pdev->dev, "test_gate", NULL, 0, NULL,
20				   0, 0, NULL);
21	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret);
22	KUNIT_EXPECT_STREQ(test, "test_gate", clk_hw_get_name(ret));
23	KUNIT_EXPECT_EQ(test, 0UL, clk_hw_get_flags(ret));
24
25	clk_hw_unregister_gate(ret);
26	platform_device_put(pdev);
27}
28
29static void clk_gate_register_test_parent_names(struct kunit *test)
30{
31	struct clk_hw *parent;
32	struct clk_hw *ret;
33
34	parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
35					    1000000);
36	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
37
38	ret = clk_hw_register_gate(NULL, "test_gate", "test_parent", 0, NULL,
39				   0, 0, NULL);
40	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret);
41	KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret));
42
43	clk_hw_unregister_gate(ret);
44	clk_hw_unregister_fixed_rate(parent);
45}
46
47static void clk_gate_register_test_parent_data(struct kunit *test)
48{
49	struct clk_hw *parent;
50	struct clk_hw *ret;
51	struct clk_parent_data pdata = { };
52
53	parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
54					    1000000);
55	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
56	pdata.hw = parent;
57
58	ret = clk_hw_register_gate_parent_data(NULL, "test_gate", &pdata, 0,
59					       NULL, 0, 0, NULL);
60	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret);
61	KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret));
62
63	clk_hw_unregister_gate(ret);
64	clk_hw_unregister_fixed_rate(parent);
65}
66
67static void clk_gate_register_test_parent_data_legacy(struct kunit *test)
68{
69	struct clk_hw *parent;
70	struct clk_hw *ret;
71	struct clk_parent_data pdata = { };
72
73	parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
74					    1000000);
75	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
76	pdata.name = "test_parent";
77
78	ret = clk_hw_register_gate_parent_data(NULL, "test_gate", &pdata, 0,
79					       NULL, 0, 0, NULL);
80	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret);
81	KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret));
82
83	clk_hw_unregister_gate(ret);
84	clk_hw_unregister_fixed_rate(parent);
85}
86
87static void clk_gate_register_test_parent_hw(struct kunit *test)
88{
89	struct clk_hw *parent;
90	struct clk_hw *ret;
91
92	parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
93					    1000000);
94	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
95
96	ret = clk_hw_register_gate_parent_hw(NULL, "test_gate", parent, 0, NULL,
97					     0, 0, NULL);
98	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret);
99	KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret));
100
101	clk_hw_unregister_gate(ret);
102	clk_hw_unregister_fixed_rate(parent);
103}
104
105static void clk_gate_register_test_hiword_invalid(struct kunit *test)
106{
107	struct clk_hw *ret;
108
109	ret = clk_hw_register_gate(NULL, "test_gate", NULL, 0, NULL,
110				   20, CLK_GATE_HIWORD_MASK, NULL);
111
112	KUNIT_EXPECT_TRUE(test, IS_ERR(ret));
113}
114
115static struct kunit_case clk_gate_register_test_cases[] = {
116	KUNIT_CASE(clk_gate_register_test_dev),
117	KUNIT_CASE(clk_gate_register_test_parent_names),
118	KUNIT_CASE(clk_gate_register_test_parent_data),
119	KUNIT_CASE(clk_gate_register_test_parent_data_legacy),
120	KUNIT_CASE(clk_gate_register_test_parent_hw),
121	KUNIT_CASE(clk_gate_register_test_hiword_invalid),
122	{}
123};
124
125static struct kunit_suite clk_gate_register_test_suite = {
126	.name = "clk-gate-register-test",
127	.test_cases = clk_gate_register_test_cases,
128};
129
130struct clk_gate_test_context {
131	void __iomem *fake_mem;
132	struct clk_hw *hw;
133	struct clk_hw *parent;
134	__le32 fake_reg; /* Keep at end, KASAN can detect out of bounds */
135};
136
137static struct clk_gate_test_context *clk_gate_test_alloc_ctx(struct kunit *test)
138{
139	struct clk_gate_test_context *ctx;
140
141	test->priv = ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
142	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
143	ctx->fake_mem = (void __force __iomem *)&ctx->fake_reg;
144
145	return ctx;
146}
147
148static void clk_gate_test_parent_rate(struct kunit *test)
149{
150	struct clk_gate_test_context *ctx = test->priv;
151	struct clk_hw *parent = ctx->parent;
152	struct clk_hw *hw = ctx->hw;
153	unsigned long prate = clk_hw_get_rate(parent);
154	unsigned long rate = clk_hw_get_rate(hw);
155
156	KUNIT_EXPECT_EQ(test, prate, rate);
157}
158
159static void clk_gate_test_enable(struct kunit *test)
160{
161	struct clk_gate_test_context *ctx = test->priv;
162	struct clk_hw *parent = ctx->parent;
163	struct clk_hw *hw = ctx->hw;
164	struct clk *clk = hw->clk;
165	u32 enable_val = BIT(5);
166
167	KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
168
169	KUNIT_EXPECT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg));
170	KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw));
171	KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw));
172	KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent));
173	KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(parent));
174}
175
176static void clk_gate_test_disable(struct kunit *test)
177{
178	struct clk_gate_test_context *ctx = test->priv;
179	struct clk_hw *parent = ctx->parent;
180	struct clk_hw *hw = ctx->hw;
181	struct clk *clk = hw->clk;
182	u32 enable_val = BIT(5);
183	u32 disable_val = 0;
184
185	KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
186	KUNIT_ASSERT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg));
187
188	clk_disable_unprepare(clk);
189	KUNIT_EXPECT_EQ(test, disable_val, le32_to_cpu(ctx->fake_reg));
190	KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw));
191	KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw));
192	KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent));
193	KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(parent));
194}
195
196static struct kunit_case clk_gate_test_cases[] = {
197	KUNIT_CASE(clk_gate_test_parent_rate),
198	KUNIT_CASE(clk_gate_test_enable),
199	KUNIT_CASE(clk_gate_test_disable),
200	{}
201};
202
203static int clk_gate_test_init(struct kunit *test)
204{
205	struct clk_hw *parent;
206	struct clk_hw *hw;
207	struct clk_gate_test_context *ctx;
208
209	ctx = clk_gate_test_alloc_ctx(test);
210	parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
211					    2000000);
212	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
213
214	hw = clk_hw_register_gate_parent_hw(NULL, "test_gate", parent, 0,
215					    ctx->fake_mem, 5, 0, NULL);
216	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
217
218	ctx->hw = hw;
219	ctx->parent = parent;
220
221	return 0;
222}
223
224static void clk_gate_test_exit(struct kunit *test)
225{
226	struct clk_gate_test_context *ctx = test->priv;
227
228	clk_hw_unregister_gate(ctx->hw);
229	clk_hw_unregister_fixed_rate(ctx->parent);
230}
231
232static struct kunit_suite clk_gate_test_suite = {
233	.name = "clk-gate-test",
234	.init = clk_gate_test_init,
235	.exit = clk_gate_test_exit,
236	.test_cases = clk_gate_test_cases,
237};
238
239static void clk_gate_test_invert_enable(struct kunit *test)
240{
241	struct clk_gate_test_context *ctx = test->priv;
242	struct clk_hw *parent = ctx->parent;
243	struct clk_hw *hw = ctx->hw;
244	struct clk *clk = hw->clk;
245	u32 enable_val = 0;
246
247	KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
248
249	KUNIT_EXPECT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg));
250	KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw));
251	KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw));
252	KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent));
253	KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(parent));
254}
255
256static void clk_gate_test_invert_disable(struct kunit *test)
257{
258	struct clk_gate_test_context *ctx = test->priv;
259	struct clk_hw *parent = ctx->parent;
260	struct clk_hw *hw = ctx->hw;
261	struct clk *clk = hw->clk;
262	u32 enable_val = 0;
263	u32 disable_val = BIT(15);
264
265	KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
266	KUNIT_ASSERT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg));
267
268	clk_disable_unprepare(clk);
269	KUNIT_EXPECT_EQ(test, disable_val, le32_to_cpu(ctx->fake_reg));
270	KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw));
271	KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw));
272	KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent));
273	KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(parent));
274}
275
276static struct kunit_case clk_gate_test_invert_cases[] = {
277	KUNIT_CASE(clk_gate_test_invert_enable),
278	KUNIT_CASE(clk_gate_test_invert_disable),
279	{}
280};
281
282static int clk_gate_test_invert_init(struct kunit *test)
283{
284	struct clk_hw *parent;
285	struct clk_hw *hw;
286	struct clk_gate_test_context *ctx;
287
288	ctx = clk_gate_test_alloc_ctx(test);
289	parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
290					    2000000);
291	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
292
293	ctx->fake_reg = cpu_to_le32(BIT(15)); /* Default to off */
294	hw = clk_hw_register_gate_parent_hw(NULL, "test_gate", parent, 0,
295					    ctx->fake_mem, 15,
296					    CLK_GATE_SET_TO_DISABLE, NULL);
297	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
298
299	ctx->hw = hw;
300	ctx->parent = parent;
301
302	return 0;
303}
304
305static struct kunit_suite clk_gate_test_invert_suite = {
306	.name = "clk-gate-invert-test",
307	.init = clk_gate_test_invert_init,
308	.exit = clk_gate_test_exit,
309	.test_cases = clk_gate_test_invert_cases,
310};
311
312static void clk_gate_test_hiword_enable(struct kunit *test)
313{
314	struct clk_gate_test_context *ctx = test->priv;
315	struct clk_hw *parent = ctx->parent;
316	struct clk_hw *hw = ctx->hw;
317	struct clk *clk = hw->clk;
318	u32 enable_val = BIT(9) | BIT(9 + 16);
319
320	KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
321
322	KUNIT_EXPECT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg));
323	KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw));
324	KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw));
325	KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent));
326	KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(parent));
327}
328
329static void clk_gate_test_hiword_disable(struct kunit *test)
330{
331	struct clk_gate_test_context *ctx = test->priv;
332	struct clk_hw *parent = ctx->parent;
333	struct clk_hw *hw = ctx->hw;
334	struct clk *clk = hw->clk;
335	u32 enable_val = BIT(9) | BIT(9 + 16);
336	u32 disable_val = BIT(9 + 16);
337
338	KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
339	KUNIT_ASSERT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg));
340
341	clk_disable_unprepare(clk);
342	KUNIT_EXPECT_EQ(test, disable_val, le32_to_cpu(ctx->fake_reg));
343	KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw));
344	KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw));
345	KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent));
346	KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(parent));
347}
348
349static struct kunit_case clk_gate_test_hiword_cases[] = {
350	KUNIT_CASE(clk_gate_test_hiword_enable),
351	KUNIT_CASE(clk_gate_test_hiword_disable),
352	{}
353};
354
355static int clk_gate_test_hiword_init(struct kunit *test)
356{
357	struct clk_hw *parent;
358	struct clk_hw *hw;
359	struct clk_gate_test_context *ctx;
360
361	ctx = clk_gate_test_alloc_ctx(test);
362	parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
363					    2000000);
364	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
365
366	hw = clk_hw_register_gate_parent_hw(NULL, "test_gate", parent, 0,
367					    ctx->fake_mem, 9,
368					    CLK_GATE_HIWORD_MASK, NULL);
369	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
370
371	ctx->hw = hw;
372	ctx->parent = parent;
373
374	return 0;
375}
376
377static struct kunit_suite clk_gate_test_hiword_suite = {
378	.name = "clk-gate-hiword-test",
379	.init = clk_gate_test_hiword_init,
380	.exit = clk_gate_test_exit,
381	.test_cases = clk_gate_test_hiword_cases,
382};
383
384static void clk_gate_test_is_enabled(struct kunit *test)
385{
386	struct clk_hw *hw;
387	struct clk_gate_test_context *ctx;
388
389	ctx = clk_gate_test_alloc_ctx(test);
390	ctx->fake_reg = cpu_to_le32(BIT(7));
391	hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 7,
392				  0, NULL);
393	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
394	KUNIT_ASSERT_TRUE(test, clk_hw_is_enabled(hw));
395
396	clk_hw_unregister_gate(hw);
397}
398
399static void clk_gate_test_is_disabled(struct kunit *test)
400{
401	struct clk_hw *hw;
402	struct clk_gate_test_context *ctx;
403
404	ctx = clk_gate_test_alloc_ctx(test);
405	ctx->fake_reg = cpu_to_le32(BIT(4));
406	hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 7,
407				  0, NULL);
408	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
409	KUNIT_ASSERT_FALSE(test, clk_hw_is_enabled(hw));
410
411	clk_hw_unregister_gate(hw);
412}
413
414static void clk_gate_test_is_enabled_inverted(struct kunit *test)
415{
416	struct clk_hw *hw;
417	struct clk_gate_test_context *ctx;
418
419	ctx = clk_gate_test_alloc_ctx(test);
420	ctx->fake_reg = cpu_to_le32(BIT(31));
421	hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 2,
422				  CLK_GATE_SET_TO_DISABLE, NULL);
423	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
424	KUNIT_ASSERT_TRUE(test, clk_hw_is_enabled(hw));
425
426	clk_hw_unregister_gate(hw);
427}
428
429static void clk_gate_test_is_disabled_inverted(struct kunit *test)
430{
431	struct clk_hw *hw;
432	struct clk_gate_test_context *ctx;
433
434	ctx = clk_gate_test_alloc_ctx(test);
435	ctx->fake_reg = cpu_to_le32(BIT(29));
436	hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 29,
437				  CLK_GATE_SET_TO_DISABLE, NULL);
438	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
439	KUNIT_ASSERT_FALSE(test, clk_hw_is_enabled(hw));
440
441	clk_hw_unregister_gate(hw);
442}
443
444static struct kunit_case clk_gate_test_enabled_cases[] = {
445	KUNIT_CASE(clk_gate_test_is_enabled),
446	KUNIT_CASE(clk_gate_test_is_disabled),
447	KUNIT_CASE(clk_gate_test_is_enabled_inverted),
448	KUNIT_CASE(clk_gate_test_is_disabled_inverted),
449	{}
450};
451
452static struct kunit_suite clk_gate_test_enabled_suite = {
453	.name = "clk-gate-is_enabled-test",
454	.test_cases = clk_gate_test_enabled_cases,
455};
456
457kunit_test_suites(
458	&clk_gate_register_test_suite,
459	&clk_gate_test_suite,
460	&clk_gate_test_invert_suite,
461	&clk_gate_test_hiword_suite,
462	&clk_gate_test_enabled_suite
463);
464MODULE_LICENSE("GPL v2");
465