Commit | Line | Data |
---|---|---|
a992acbb SB |
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 | ||
11 | static 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 | ||
29 | static 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 | ||
47 | static 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 | ||
67 | static 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 | ||
87 | static 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 | ||
105 | static 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 | ||
115 | static 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 | ||
125 | static struct kunit_suite clk_gate_register_test_suite = { | |
126 | .name = "clk-gate-register-test", | |
127 | .test_cases = clk_gate_register_test_cases, | |
128 | }; | |
129 | ||
130 | struct clk_gate_test_context { | |
131 | void __iomem *fake_mem; | |
132 | struct clk_hw *hw; | |
133 | struct clk_hw *parent; | |
134 | u32 fake_reg; /* Keep at end, KASAN can detect out of bounds */ | |
135 | }; | |
136 | ||
137 | static 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 | ||
148 | static 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 | ||
159 | static 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, 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 | ||
176 | static 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, ctx->fake_reg); | |
187 | ||
188 | clk_disable_unprepare(clk); | |
189 | KUNIT_EXPECT_EQ(test, disable_val, 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 | ||
196 | static 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 | ||
203 | static 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 | ||
224 | static 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 | ||
232 | static 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 | ||
239 | static 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, 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 | ||
256 | static 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, ctx->fake_reg); | |
267 | ||
268 | clk_disable_unprepare(clk); | |
269 | KUNIT_EXPECT_EQ(test, disable_val, 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 | ||
276 | static 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 | ||
282 | static 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 = 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 | ||
305 | static 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 | ||
312 | static 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, 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 | ||
329 | static 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, ctx->fake_reg); | |
340 | ||
341 | clk_disable_unprepare(clk); | |
342 | KUNIT_EXPECT_EQ(test, disable_val, 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 | ||
349 | static 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 | ||
355 | static 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 | ||
377 | static 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 | ||
384 | static 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 = 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 | ||
399 | static 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 = 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 | ||
414 | static 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 = 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 | ||
429 | static 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 = 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 | ||
444 | static 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 | ||
452 | static 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 | ||
457 | kunit_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 | ); | |
464 | MODULE_LICENSE("GPL v2"); |