1 // SPDX-License-Identifier: GPL-2.0-only 2 // Copyright (C) 2024 Cirrus Logic, Inc. and 3 // Cirrus Logic International Semiconductor Ltd. 4 5 #include <kunit/device.h> 6 #include <kunit/test.h> 7 #include <linux/module.h> 8 #include <sound/control.h> 9 #include <sound/soc.h> 10 #include <sound/soc-card.h> 11 12 struct soc_card_test_priv { 13 struct device *card_dev; 14 struct snd_soc_card *card; 15 }; 16 17 static const struct snd_kcontrol_new test_card_controls[] = { 18 SOC_SINGLE("Fee", SND_SOC_NOPM, 0, 1, 0), 19 SOC_SINGLE("Fi", SND_SOC_NOPM, 1, 1, 0), 20 SOC_SINGLE("Fo", SND_SOC_NOPM, 2, 1, 0), 21 SOC_SINGLE("Fum", SND_SOC_NOPM, 3, 1, 0), 22 SOC_SINGLE("Left Fee", SND_SOC_NOPM, 4, 1, 0), 23 SOC_SINGLE("Right Fee", SND_SOC_NOPM, 5, 1, 0), 24 SOC_SINGLE("Left Fi", SND_SOC_NOPM, 6, 1, 0), 25 SOC_SINGLE("Right Fi", SND_SOC_NOPM, 7, 1, 0), 26 SOC_SINGLE("Left Fo", SND_SOC_NOPM, 8, 1, 0), 27 SOC_SINGLE("Right Fo", SND_SOC_NOPM, 9, 1, 0), 28 SOC_SINGLE("Left Fum", SND_SOC_NOPM, 10, 1, 0), 29 SOC_SINGLE("Right Fum", SND_SOC_NOPM, 11, 1, 0), 30 }; 31 32 static void test_snd_soc_card_get_kcontrol(struct kunit *test) 33 { 34 struct soc_card_test_priv *priv = test->priv; 35 struct snd_soc_card *card = priv->card; 36 struct snd_kcontrol *kc; 37 struct soc_mixer_control *mc; 38 int i, ret; 39 40 ret = snd_soc_add_card_controls(card, test_card_controls, ARRAY_SIZE(test_card_controls)); 41 KUNIT_ASSERT_EQ(test, ret, 0); 42 43 /* Look up every control */ 44 for (i = 0; i < ARRAY_SIZE(test_card_controls); ++i) { 45 kc = snd_soc_card_get_kcontrol(card, test_card_controls[i].name); 46 KUNIT_EXPECT_NOT_ERR_OR_NULL_MSG(test, kc, "Failed to find '%s'\n", 47 test_card_controls[i].name); 48 if (!kc) 49 continue; 50 51 /* Test that it is the correct control */ 52 mc = (struct soc_mixer_control *)kc->private_value; 53 KUNIT_EXPECT_EQ_MSG(test, mc->shift, i, "For '%s'\n", test_card_controls[i].name); 54 } 55 56 /* Test some names that should not be found */ 57 kc = snd_soc_card_get_kcontrol(card, "None"); 58 KUNIT_EXPECT_NULL(test, kc); 59 60 kc = snd_soc_card_get_kcontrol(card, "Left None"); 61 KUNIT_EXPECT_NULL(test, kc); 62 63 kc = snd_soc_card_get_kcontrol(card, "Left"); 64 KUNIT_EXPECT_NULL(test, kc); 65 66 kc = snd_soc_card_get_kcontrol(card, NULL); 67 KUNIT_EXPECT_NULL(test, kc); 68 } 69 70 static void test_snd_soc_card_get_kcontrol_locked(struct kunit *test) 71 { 72 struct soc_card_test_priv *priv = test->priv; 73 struct snd_soc_card *card = priv->card; 74 struct snd_kcontrol *kc, *kcw; 75 struct soc_mixer_control *mc; 76 int i, ret; 77 78 ret = snd_soc_add_card_controls(card, test_card_controls, ARRAY_SIZE(test_card_controls)); 79 KUNIT_ASSERT_EQ(test, ret, 0); 80 81 /* Look up every control */ 82 for (i = 0; i < ARRAY_SIZE(test_card_controls); ++i) { 83 down_read(&card->snd_card->controls_rwsem); 84 kc = snd_soc_card_get_kcontrol_locked(card, test_card_controls[i].name); 85 up_read(&card->snd_card->controls_rwsem); 86 KUNIT_EXPECT_NOT_ERR_OR_NULL_MSG(test, kc, "Failed to find '%s'\n", 87 test_card_controls[i].name); 88 if (!kc) 89 continue; 90 91 /* Test that it is the correct control */ 92 mc = (struct soc_mixer_control *)kc->private_value; 93 KUNIT_EXPECT_EQ_MSG(test, mc->shift, i, "For '%s'\n", test_card_controls[i].name); 94 95 down_write(&card->snd_card->controls_rwsem); 96 kcw = snd_soc_card_get_kcontrol_locked(card, test_card_controls[i].name); 97 up_write(&card->snd_card->controls_rwsem); 98 KUNIT_EXPECT_NOT_ERR_OR_NULL_MSG(test, kcw, "Failed to find '%s'\n", 99 test_card_controls[i].name); 100 101 KUNIT_EXPECT_PTR_EQ(test, kc, kcw); 102 } 103 104 /* Test some names that should not be found */ 105 down_read(&card->snd_card->controls_rwsem); 106 kc = snd_soc_card_get_kcontrol_locked(card, "None"); 107 up_read(&card->snd_card->controls_rwsem); 108 KUNIT_EXPECT_NULL(test, kc); 109 110 down_read(&card->snd_card->controls_rwsem); 111 kc = snd_soc_card_get_kcontrol_locked(card, "Left None"); 112 up_read(&card->snd_card->controls_rwsem); 113 KUNIT_EXPECT_NULL(test, kc); 114 115 down_read(&card->snd_card->controls_rwsem); 116 kc = snd_soc_card_get_kcontrol_locked(card, "Left"); 117 up_read(&card->snd_card->controls_rwsem); 118 KUNIT_EXPECT_NULL(test, kc); 119 120 down_read(&card->snd_card->controls_rwsem); 121 kc = snd_soc_card_get_kcontrol_locked(card, NULL); 122 up_read(&card->snd_card->controls_rwsem); 123 KUNIT_EXPECT_NULL(test, kc); 124 } 125 126 static int soc_card_test_case_init(struct kunit *test) 127 { 128 struct soc_card_test_priv *priv; 129 int ret; 130 131 priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); 132 if (!priv) 133 return -ENOMEM; 134 135 test->priv = priv; 136 137 priv->card = kunit_kzalloc(test, sizeof(*priv->card), GFP_KERNEL); 138 if (!priv->card) 139 return -ENOMEM; 140 141 priv->card_dev = kunit_device_register(test, "sound-soc-card-test"); 142 priv->card_dev = get_device(priv->card_dev); 143 if (!priv->card_dev) 144 return -ENODEV; 145 146 priv->card->name = "soc-card-test"; 147 priv->card->dev = priv->card_dev; 148 priv->card->owner = THIS_MODULE; 149 150 ret = snd_soc_register_card(priv->card); 151 if (ret) { 152 put_device(priv->card_dev); 153 return ret; 154 } 155 156 return 0; 157 } 158 159 static void soc_card_test_case_exit(struct kunit *test) 160 { 161 struct soc_card_test_priv *priv = test->priv; 162 163 if (priv->card) 164 snd_soc_unregister_card(priv->card); 165 166 if (priv->card_dev) 167 put_device(priv->card_dev); 168 } 169 170 static struct kunit_case soc_card_test_cases[] = { 171 KUNIT_CASE(test_snd_soc_card_get_kcontrol), 172 KUNIT_CASE(test_snd_soc_card_get_kcontrol_locked), 173 {} 174 }; 175 176 static struct kunit_suite soc_card_test_suite = { 177 .name = "soc-card", 178 .test_cases = soc_card_test_cases, 179 .init = soc_card_test_case_init, 180 .exit = soc_card_test_case_exit, 181 }; 182 183 kunit_test_suites(&soc_card_test_suite); 184 185 MODULE_DESCRIPTION("ASoC soc-card KUnit test"); 186 MODULE_LICENSE("GPL"); 187