1515#include <linux/module.h>
1616#include <linux/overflow.h>
1717#include <linux/pci_ids.h>
18+ #include <linux/property.h>
19+ #include <linux/seq_buf.h>
1820#include <linux/soundwire/sdw.h>
1921#include <sound/cs35l56.h>
2022#include <sound/cs-amp-lib.h>
2325KUNIT_DEFINE_ACTION_WRAPPER (faux_device_destroy_wrapper , faux_device_destroy ,
2426 struct faux_device * )
2527
28+ KUNIT_DEFINE_ACTION_WRAPPER (software_node_unregister_node_group_wrapper ,
29+ software_node_unregister_node_group ,
30+ const struct software_node * const * )
31+
32+ KUNIT_DEFINE_ACTION_WRAPPER (software_node_unregister_wrapper ,
33+ software_node_unregister ,
34+ const struct software_node * )
35+
36+ KUNIT_DEFINE_ACTION_WRAPPER (device_remove_software_node_wrapper ,
37+ device_remove_software_node ,
38+ struct device * )
39+
2640struct cs35l56_test_priv {
2741 struct faux_device * amp_dev ;
2842 struct cs35l56_private * cs35l56_priv ;
2943
3044 const char * ssidexv2 ;
45+
46+ bool read_onchip_spkid_called ;
47+ bool configure_onchip_spkid_pads_called ;
3148};
3249
3350struct cs35l56_test_param {
3451 u8 type ;
3552 u8 rev ;
53+
54+ s32 spkid_gpios [4 ];
55+ s32 spkid_pulls [4 ];
56+ };
57+
58+ static const struct software_node cs35l56_test_dev_sw_node =
59+ SOFTWARE_NODE ("SWD1" , NULL , NULL );
60+
61+ static const struct software_node cs35l56_test_af01_sw_node =
62+ SOFTWARE_NODE ("AF01" , NULL , & cs35l56_test_dev_sw_node );
63+
64+ static const struct software_node * cs35l56_test_dev_and_af01_node_group [ ] = {
65+ & cs35l56_test_dev_sw_node ,
66+ & cs35l56_test_af01_sw_node ,
67+ NULL
3668};
3769
3870static const char * cs35l56_test_devm_get_vendor_specific_variant_id_none (struct device * dev ,
@@ -232,6 +264,190 @@ static void cs35l56_test_l56_b0_ssidexv2_ignored_suffix_sdw(struct kunit *test)
232264 KUNIT_EXPECT_STREQ (test , cs35l56 -> fallback_fw_suffix , "l1u5" );
233265}
234266
267+ /*
268+ * Test that cs35l56_process_xu_properties() correctly parses the GPIO and
269+ * pull values from properties into the arrays in struct cs35l56_base.
270+ *
271+ * This test creates the node tree:
272+ *
273+ * Node("SWD1") { // top-level device node
274+ * Node("AF01") {
275+ * Node("mipi-sdca-function-expansion-subproperties") {
276+ * property: "01fa-spk-id-gpios-onchip"
277+ * property: 01fa-spk-id-gpios-onchip-pull
278+ * }
279+ * }
280+ * }
281+ *
282+ * Note that in ACPI "mipi-sdca-function-expansion-subproperties" is
283+ * a special _DSD property that points to a Device(EXT0) node but behaves
284+ * as an alias of the EXT0 node. The equivalent in software nodes is to
285+ * create a Node named "mipi-sdca-function-expansion-subproperties" with
286+ * the properties.
287+ *
288+ */
289+ static void cs35l56_test_parse_xu_onchip_spkid (struct kunit * test )
290+ {
291+ const struct cs35l56_test_param * param = test -> param_value ;
292+ struct cs35l56_test_priv * priv = test -> priv ;
293+ struct cs35l56_private * cs35l56 = priv -> cs35l56_priv ;
294+ struct software_node * ext0_node ;
295+ int num_gpios = 0 ;
296+ int num_pulls = 0 ;
297+ int i ;
298+
299+ for (i = 0 ; i < ARRAY_SIZE (param -> spkid_gpios ); i ++ , num_gpios ++ ) {
300+ if (param -> spkid_gpios [i ] < 0 )
301+ break ;
302+ }
303+ KUNIT_ASSERT_LE (test , num_gpios , ARRAY_SIZE (cs35l56 -> base .onchip_spkid_gpios ));
304+
305+ for (i = 0 ; i < ARRAY_SIZE (param -> spkid_pulls ); i ++ , num_pulls ++ ) {
306+ if (param -> spkid_pulls [i ] < 0 )
307+ break ;
308+ }
309+ KUNIT_ASSERT_LE (test , num_pulls , ARRAY_SIZE (cs35l56 -> base .onchip_spkid_pulls ));
310+
311+ const struct property_entry ext0_props [] = {
312+ PROPERTY_ENTRY_U32_ARRAY_LEN ("01fa-spk-id-gpios-onchip" ,
313+ param -> spkid_gpios , num_gpios ),
314+ PROPERTY_ENTRY_U32_ARRAY_LEN ("01fa-spk-id-gpios-onchip-pull" ,
315+ param -> spkid_pulls , num_pulls ),
316+ { }
317+ };
318+
319+ KUNIT_ASSERT_EQ (test ,
320+ software_node_register_node_group (cs35l56_test_dev_and_af01_node_group ),
321+ 0 );
322+ KUNIT_ASSERT_EQ (test ,
323+ kunit_add_action_or_reset (test ,
324+ software_node_unregister_node_group_wrapper ,
325+ cs35l56_test_dev_and_af01_node_group ),
326+ 0 );
327+
328+ ext0_node = kunit_kzalloc (test , sizeof (* ext0_node ), GFP_KERNEL );
329+ KUNIT_ASSERT_NOT_NULL (test , ext0_node );
330+ * ext0_node = SOFTWARE_NODE ("mipi-sdca-function-expansion-subproperties" ,
331+ ext0_props , & cs35l56_test_af01_sw_node );
332+
333+ KUNIT_ASSERT_EQ (test , software_node_register (ext0_node ), 0 );
334+ KUNIT_ASSERT_EQ (test ,
335+ kunit_add_action_or_reset (test ,
336+ software_node_unregister_wrapper ,
337+ ext0_node ),
338+ 0 );
339+
340+ KUNIT_ASSERT_EQ (test ,
341+ device_add_software_node (cs35l56 -> base .dev , & cs35l56_test_dev_sw_node ), 0 );
342+ KUNIT_ASSERT_EQ (test , 0 ,
343+ kunit_add_action_or_reset (test ,
344+ device_remove_software_node_wrapper ,
345+ cs35l56 -> base .dev ));
346+
347+ KUNIT_EXPECT_EQ (test , cs35l56_process_xu_properties (cs35l56 ), 0 );
348+
349+ KUNIT_EXPECT_EQ (test , cs35l56 -> base .num_onchip_spkid_gpios , num_gpios );
350+ KUNIT_EXPECT_EQ (test , cs35l56 -> base .num_onchip_spkid_pulls , num_pulls );
351+
352+ for (i = 0 ; i < ARRAY_SIZE (param -> spkid_gpios ); i ++ ) {
353+ if (param -> spkid_gpios [i ] < 0 )
354+ break ;
355+
356+ /*
357+ * cs35l56_process_xu_properties() stores the GPIO numbers
358+ * zero-based, which is one less than the value in the property.
359+ */
360+ KUNIT_EXPECT_EQ_MSG (test , cs35l56 -> base .onchip_spkid_gpios [i ],
361+ param -> spkid_gpios [i ] - 1 ,
362+ "i=%d" , i );
363+ }
364+
365+ for (i = 0 ; i < ARRAY_SIZE (param -> spkid_pulls ); i ++ ) {
366+ if (param -> spkid_pulls [i ] < 0 )
367+ break ;
368+
369+ KUNIT_EXPECT_EQ_MSG (test , cs35l56 -> base .onchip_spkid_pulls [i ],
370+ param -> spkid_pulls [i ], "i=%d" , i );
371+ }
372+ }
373+
374+ static int cs35l56_test_dummy_read_onchip_spkid (struct cs35l56_base * cs35l56_base )
375+ {
376+ struct kunit * test = kunit_get_current_test ();
377+ struct cs35l56_test_priv * priv = test -> priv ;
378+
379+ priv -> read_onchip_spkid_called = true;
380+
381+ return 4 ;
382+ }
383+
384+ static int cs35l56_test_dummy_configure_onchip_spkid_pads (struct cs35l56_base * cs35l56_base )
385+ {
386+ struct kunit * test = kunit_get_current_test ();
387+ struct cs35l56_test_priv * priv = test -> priv ;
388+
389+ priv -> configure_onchip_spkid_pads_called = true;
390+
391+ return 0 ;
392+ }
393+
394+ static void cs35l56_test_set_fw_name_reads_onchip_spkid (struct kunit * test )
395+ {
396+ struct cs35l56_test_priv * priv = test -> priv ;
397+ struct cs35l56_private * cs35l56 = priv -> cs35l56_priv ;
398+
399+ /* Provide some on-chip GPIOs for spkid */
400+ cs35l56 -> base .onchip_spkid_gpios [0 ] = 1 ;
401+ cs35l56 -> base .num_onchip_spkid_gpios = 1 ;
402+
403+ cs35l56 -> speaker_id = - ENOENT ;
404+
405+ kunit_activate_static_stub (test ,
406+ cs35l56_configure_onchip_spkid_pads ,
407+ cs35l56_test_dummy_configure_onchip_spkid_pads );
408+ kunit_activate_static_stub (test ,
409+ cs35l56_read_onchip_spkid ,
410+ cs35l56_test_dummy_read_onchip_spkid );
411+
412+ priv -> configure_onchip_spkid_pads_called = false;
413+ priv -> read_onchip_spkid_called = false;
414+ KUNIT_EXPECT_EQ (test , cs35l56_set_fw_name (cs35l56 -> component ), 0 );
415+ KUNIT_EXPECT_TRUE (test , priv -> configure_onchip_spkid_pads_called );
416+ KUNIT_EXPECT_TRUE (test , priv -> read_onchip_spkid_called );
417+ KUNIT_EXPECT_EQ (test , cs35l56 -> speaker_id ,
418+ cs35l56_test_dummy_read_onchip_spkid (& cs35l56 -> base ));
419+ }
420+
421+ static void cs35l56_test_set_fw_name_preserves_spkid_with_onchip_gpios (struct kunit * test )
422+ {
423+ struct cs35l56_test_priv * priv = test -> priv ;
424+ struct cs35l56_private * cs35l56 = priv -> cs35l56_priv ;
425+
426+ /* Provide some on-chip GPIOs for spkid */
427+ cs35l56 -> base .onchip_spkid_gpios [0 ] = 1 ;
428+ cs35l56 -> base .num_onchip_spkid_gpios = 1 ;
429+
430+ /* Simulate that the driver already got a spkid from somewhere */
431+ cs35l56 -> speaker_id = 15 ;
432+
433+ KUNIT_EXPECT_EQ (test , cs35l56_set_fw_name (cs35l56 -> component ), 0 );
434+ KUNIT_EXPECT_EQ (test , cs35l56 -> speaker_id , 15 );
435+ }
436+
437+ static void cs35l56_test_set_fw_name_preserves_spkid_without_onchip_gpios (struct kunit * test )
438+ {
439+ struct cs35l56_test_priv * priv = test -> priv ;
440+ struct cs35l56_private * cs35l56 = priv -> cs35l56_priv ;
441+
442+ cs35l56 -> base .num_onchip_spkid_gpios = 0 ;
443+
444+ /* Simulate that the driver already got a spkid from somewhere */
445+ cs35l56 -> speaker_id = 15 ;
446+
447+ KUNIT_EXPECT_EQ (test , cs35l56_set_fw_name (cs35l56 -> component ), 0 );
448+ KUNIT_EXPECT_EQ (test , cs35l56 -> speaker_id , 15 );
449+ }
450+
235451static int cs35l56_test_case_init_common (struct kunit * test )
236452{
237453 struct cs35l56_test_priv * priv ;
@@ -263,6 +479,7 @@ static int cs35l56_test_case_init_common(struct kunit *test)
263479 cs35l56 -> component = kunit_kzalloc (test , sizeof (* cs35l56 -> component ), GFP_KERNEL );
264480 KUNIT_ASSERT_NOT_NULL (test , cs35l56 -> component );
265481 cs35l56 -> component -> dev = cs35l56 -> base .dev ;
482+ snd_soc_component_set_drvdata (cs35l56 -> component , cs35l56 );
266483
267484 cs35l56 -> component -> card = kunit_kzalloc (test , sizeof (* cs35l56 -> component -> card ),
268485 GFP_KERNEL );
@@ -299,6 +516,50 @@ static int cs35l56_test_case_init_soundwire(struct kunit *test)
299516 return 0 ;
300517}
301518
519+ static void cs35l56_test_gpio_param_desc (const struct cs35l56_test_param * param , char * desc )
520+ {
521+ DECLARE_SEQ_BUF (gpios , 1 + (2 * ARRAY_SIZE (param -> spkid_gpios )));
522+ DECLARE_SEQ_BUF (pulls , 1 + (2 * ARRAY_SIZE (param -> spkid_pulls )));
523+ int i ;
524+
525+ for (i = 0 ; i < ARRAY_SIZE (param -> spkid_gpios ); i ++ ) {
526+ if (param -> spkid_gpios [i ] < 0 )
527+ break ;
528+
529+ seq_buf_printf (& gpios , "%s%d" , (i == 0 ) ? "" : "," , param -> spkid_gpios [i ]);
530+ }
531+
532+ for (i = 0 ; i < ARRAY_SIZE (param -> spkid_pulls ); i ++ ) {
533+ if (param -> spkid_pulls [i ] < 0 )
534+ break ;
535+
536+ seq_buf_printf (& pulls , "%s%d" , (i == 0 ) ? "" : "," , param -> spkid_pulls [i ]);
537+ }
538+
539+ snprintf (desc , KUNIT_PARAM_DESC_SIZE , "gpios:{%s} pulls:{%s}" ,
540+ seq_buf_str (& gpios ), seq_buf_str (& pulls ));
541+ }
542+
543+ static const struct cs35l56_test_param cs35l56_test_onchip_spkid_cases [] = {
544+ { .spkid_gpios = { 1 , -1 }, .spkid_pulls = { 1 , -1 }, },
545+ { .spkid_gpios = { 1 , -1 }, .spkid_pulls = { 2 , -1 }, },
546+
547+ { .spkid_gpios = { 7 , -1 }, .spkid_pulls = { 1 , -1 }, },
548+ { .spkid_gpios = { 7 , -1 }, .spkid_pulls = { 2 , -1 }, },
549+
550+ { .spkid_gpios = { 1 , 7 , -1 }, .spkid_pulls = { 1 , 1 , -1 }, },
551+ { .spkid_gpios = { 1 , 7 , -1 }, .spkid_pulls = { 2 , 2 , -1 }, },
552+
553+ { .spkid_gpios = { 7 , 1 , -1 }, .spkid_pulls = { 1 , 1 , -1 }, },
554+ { .spkid_gpios = { 7 , 1 , -1 }, .spkid_pulls = { 2 , 2 , -1 }, },
555+
556+ { .spkid_gpios = { 3 , 7 , 1 , -1 }, .spkid_pulls = { 1 , 1 , 1 , -1 }, },
557+ { .spkid_gpios = { 3 , 7 , 1 , -1 }, .spkid_pulls = { 2 , 2 , 2 , -1 }, },
558+ };
559+ KUNIT_ARRAY_PARAM (cs35l56_test_onchip_spkid ,
560+ cs35l56_test_onchip_spkid_cases ,
561+ cs35l56_test_gpio_param_desc );
562+
302563static void cs35l56_test_type_rev_param_desc (const struct cs35l56_test_param * param ,
303564 char * desc )
304565{
@@ -331,6 +592,13 @@ static struct kunit_case cs35l56_test_cases_soundwire[] = {
331592 cs35l56_test_type_rev_ex_b0_gen_params ),
332593 KUNIT_CASE (cs35l56_test_l56_b0_ssidexv2_ignored_suffix_sdw ),
333594
595+ KUNIT_CASE_PARAM (cs35l56_test_parse_xu_onchip_spkid ,
596+ cs35l56_test_onchip_spkid_gen_params ),
597+
598+ KUNIT_CASE (cs35l56_test_set_fw_name_reads_onchip_spkid ),
599+ KUNIT_CASE (cs35l56_test_set_fw_name_preserves_spkid_with_onchip_gpios ),
600+ KUNIT_CASE (cs35l56_test_set_fw_name_preserves_spkid_without_onchip_gpios ),
601+
334602 { } /* terminator */
335603};
336604
@@ -339,6 +607,10 @@ static struct kunit_case cs35l56_test_cases_not_soundwire[] = {
339607 KUNIT_CASE_PARAM (cs35l56_test_ssidexv2_suffix_i2cspi ,
340608 cs35l56_test_type_rev_all_gen_params ),
341609
610+ KUNIT_CASE (cs35l56_test_set_fw_name_reads_onchip_spkid ),
611+ KUNIT_CASE (cs35l56_test_set_fw_name_preserves_spkid_with_onchip_gpios ),
612+ KUNIT_CASE (cs35l56_test_set_fw_name_preserves_spkid_without_onchip_gpios ),
613+
342614 { } /* terminator */
343615};
344616
@@ -360,6 +632,7 @@ kunit_test_suites(
360632);
361633
362634MODULE_IMPORT_NS ("SND_SOC_CS_AMP_LIB" );
635+ MODULE_IMPORT_NS ("SND_SOC_CS35L56_SHARED" );
363636MODULE_IMPORT_NS ("EXPORTED_FOR_KUNIT_TESTING" );
364637MODULE_DESCRIPTION ("KUnit test for Cirrus Logic cs35l56 codec driver" );
365638MODULE_AUTHOR ("Richard Fitzgerald <rf@opensource.cirrus.com>" );
0 commit comments