@@ -2239,10 +2239,166 @@ static struct kunit_suite clk_leaf_mux_set_rate_parent_test_suite = {
2239
2239
.test_cases = clk_leaf_mux_set_rate_parent_test_cases ,
2240
2240
};
2241
2241
2242
+ struct clk_mux_notifier_rate_change {
2243
+ bool done ;
2244
+ unsigned long old_rate ;
2245
+ unsigned long new_rate ;
2246
+ wait_queue_head_t wq ;
2247
+ };
2248
+
2249
+ struct clk_mux_notifier_ctx {
2250
+ struct clk_multiple_parent_ctx mux_ctx ;
2251
+ struct clk * clk ;
2252
+ struct notifier_block clk_nb ;
2253
+ struct clk_mux_notifier_rate_change pre_rate_change ;
2254
+ struct clk_mux_notifier_rate_change post_rate_change ;
2255
+ };
2256
+
2257
+ #define NOTIFIER_TIMEOUT_MS 100
2258
+
2259
+ static int clk_mux_notifier_callback (struct notifier_block * nb ,
2260
+ unsigned long action , void * data )
2261
+ {
2262
+ struct clk_notifier_data * clk_data = data ;
2263
+ struct clk_mux_notifier_ctx * ctx = container_of (nb ,
2264
+ struct clk_mux_notifier_ctx ,
2265
+ clk_nb );
2266
+
2267
+ if (action & PRE_RATE_CHANGE ) {
2268
+ ctx -> pre_rate_change .old_rate = clk_data -> old_rate ;
2269
+ ctx -> pre_rate_change .new_rate = clk_data -> new_rate ;
2270
+ ctx -> pre_rate_change .done = true;
2271
+ wake_up_interruptible (& ctx -> pre_rate_change .wq );
2272
+ }
2273
+
2274
+ if (action & POST_RATE_CHANGE ) {
2275
+ ctx -> post_rate_change .old_rate = clk_data -> old_rate ;
2276
+ ctx -> post_rate_change .new_rate = clk_data -> new_rate ;
2277
+ ctx -> post_rate_change .done = true;
2278
+ wake_up_interruptible (& ctx -> post_rate_change .wq );
2279
+ }
2280
+
2281
+ return 0 ;
2282
+ }
2283
+
2284
+ static int clk_mux_notifier_test_init (struct kunit * test )
2285
+ {
2286
+ struct clk_mux_notifier_ctx * ctx ;
2287
+ const char * top_parents [2 ] = { "parent-0" , "parent-1" };
2288
+ int ret ;
2289
+
2290
+ ctx = kunit_kzalloc (test , sizeof (* ctx ), GFP_KERNEL );
2291
+ if (!ctx )
2292
+ return - ENOMEM ;
2293
+ test -> priv = ctx ;
2294
+ ctx -> clk_nb .notifier_call = clk_mux_notifier_callback ;
2295
+ init_waitqueue_head (& ctx -> pre_rate_change .wq );
2296
+ init_waitqueue_head (& ctx -> post_rate_change .wq );
2297
+
2298
+ ctx -> mux_ctx .parents_ctx [0 ].hw .init = CLK_HW_INIT_NO_PARENT ("parent-0" ,
2299
+ & clk_dummy_rate_ops ,
2300
+ 0 );
2301
+ ctx -> mux_ctx .parents_ctx [0 ].rate = DUMMY_CLOCK_RATE_1 ;
2302
+ ret = clk_hw_register (NULL , & ctx -> mux_ctx .parents_ctx [0 ].hw );
2303
+ if (ret )
2304
+ return ret ;
2305
+
2306
+ ctx -> mux_ctx .parents_ctx [1 ].hw .init = CLK_HW_INIT_NO_PARENT ("parent-1" ,
2307
+ & clk_dummy_rate_ops ,
2308
+ 0 );
2309
+ ctx -> mux_ctx .parents_ctx [1 ].rate = DUMMY_CLOCK_RATE_2 ;
2310
+ ret = clk_hw_register (NULL , & ctx -> mux_ctx .parents_ctx [1 ].hw );
2311
+ if (ret )
2312
+ return ret ;
2313
+
2314
+ ctx -> mux_ctx .current_parent = 0 ;
2315
+ ctx -> mux_ctx .hw .init = CLK_HW_INIT_PARENTS ("test-mux" , top_parents ,
2316
+ & clk_multiple_parents_mux_ops ,
2317
+ 0 );
2318
+ ret = clk_hw_register (NULL , & ctx -> mux_ctx .hw );
2319
+ if (ret )
2320
+ return ret ;
2321
+
2322
+ ctx -> clk = clk_hw_get_clk (& ctx -> mux_ctx .hw , NULL );
2323
+ ret = clk_notifier_register (ctx -> clk , & ctx -> clk_nb );
2324
+ if (ret )
2325
+ return ret ;
2326
+
2327
+ return 0 ;
2328
+ }
2329
+
2330
+ static void clk_mux_notifier_test_exit (struct kunit * test )
2331
+ {
2332
+ struct clk_mux_notifier_ctx * ctx = test -> priv ;
2333
+ struct clk * clk = ctx -> clk ;
2334
+
2335
+ clk_notifier_unregister (clk , & ctx -> clk_nb );
2336
+ clk_put (clk );
2337
+
2338
+ clk_hw_unregister (& ctx -> mux_ctx .hw );
2339
+ clk_hw_unregister (& ctx -> mux_ctx .parents_ctx [0 ].hw );
2340
+ clk_hw_unregister (& ctx -> mux_ctx .parents_ctx [1 ].hw );
2341
+ }
2342
+
2343
+ /*
2344
+ * Test that if the we have a notifier registered on a mux, the core
2345
+ * will notify us when we switch to another parent, and with the proper
2346
+ * old and new rates.
2347
+ */
2348
+ static void clk_mux_notifier_set_parent_test (struct kunit * test )
2349
+ {
2350
+ struct clk_mux_notifier_ctx * ctx = test -> priv ;
2351
+ struct clk_hw * hw = & ctx -> mux_ctx .hw ;
2352
+ struct clk * clk = clk_hw_get_clk (hw , NULL );
2353
+ struct clk * new_parent = clk_hw_get_clk (& ctx -> mux_ctx .parents_ctx [1 ].hw , NULL );
2354
+ int ret ;
2355
+
2356
+ ret = clk_set_parent (clk , new_parent );
2357
+ KUNIT_ASSERT_EQ (test , ret , 0 );
2358
+
2359
+ ret = wait_event_interruptible_timeout (ctx -> pre_rate_change .wq ,
2360
+ ctx -> pre_rate_change .done ,
2361
+ msecs_to_jiffies (NOTIFIER_TIMEOUT_MS ));
2362
+ KUNIT_ASSERT_GT (test , ret , 0 );
2363
+
2364
+ KUNIT_EXPECT_EQ (test , ctx -> pre_rate_change .old_rate , DUMMY_CLOCK_RATE_1 );
2365
+ KUNIT_EXPECT_EQ (test , ctx -> pre_rate_change .new_rate , DUMMY_CLOCK_RATE_2 );
2366
+
2367
+ ret = wait_event_interruptible_timeout (ctx -> post_rate_change .wq ,
2368
+ ctx -> post_rate_change .done ,
2369
+ msecs_to_jiffies (NOTIFIER_TIMEOUT_MS ));
2370
+ KUNIT_ASSERT_GT (test , ret , 0 );
2371
+
2372
+ KUNIT_EXPECT_EQ (test , ctx -> post_rate_change .old_rate , DUMMY_CLOCK_RATE_1 );
2373
+ KUNIT_EXPECT_EQ (test , ctx -> post_rate_change .new_rate , DUMMY_CLOCK_RATE_2 );
2374
+
2375
+ clk_put (new_parent );
2376
+ clk_put (clk );
2377
+ }
2378
+
2379
+ static struct kunit_case clk_mux_notifier_test_cases [] = {
2380
+ KUNIT_CASE (clk_mux_notifier_set_parent_test ),
2381
+ {}
2382
+ };
2383
+
2384
+ /*
2385
+ * Test suite for a mux with multiple parents, and a notifier registered
2386
+ * on the mux.
2387
+ *
2388
+ * These tests exercise the behaviour of notifiers.
2389
+ */
2390
+ static struct kunit_suite clk_mux_notifier_test_suite = {
2391
+ .name = "clk-mux-notifier" ,
2392
+ .init = clk_mux_notifier_test_init ,
2393
+ .exit = clk_mux_notifier_test_exit ,
2394
+ .test_cases = clk_mux_notifier_test_cases ,
2395
+ };
2396
+
2242
2397
kunit_test_suites (
2243
2398
& clk_leaf_mux_set_rate_parent_test_suite ,
2244
2399
& clk_test_suite ,
2245
2400
& clk_multiple_parents_mux_test_suite ,
2401
+ & clk_mux_notifier_test_suite ,
2246
2402
& clk_orphan_transparent_multiple_parent_mux_test_suite ,
2247
2403
& clk_orphan_transparent_single_parent_test_suite ,
2248
2404
& clk_orphan_two_level_root_last_test_suite ,
0 commit comments