~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/pci/hda/cirrus_scodec_test.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 //
  3 // KUnit test for the Cirrus side-codec library.
  4 //
  5 // Copyright (C) 2023 Cirrus Logic, Inc. and
  6 //                    Cirrus Logic International Semiconductor Ltd.
  7 
  8 #include <kunit/test.h>
  9 #include <linux/gpio/driver.h>
 10 #include <linux/module.h>
 11 #include <linux/platform_device.h>
 12 
 13 #include "cirrus_scodec.h"
 14 
 15 struct cirrus_scodec_test_gpio {
 16         unsigned int pin_state;
 17         struct gpio_chip chip;
 18 };
 19 
 20 struct cirrus_scodec_test_priv {
 21         struct platform_device amp_pdev;
 22         struct platform_device *gpio_pdev;
 23         struct cirrus_scodec_test_gpio *gpio_priv;
 24 };
 25 
 26 static int cirrus_scodec_test_gpio_get_direction(struct gpio_chip *chip,
 27                                                  unsigned int offset)
 28 {
 29         return GPIO_LINE_DIRECTION_IN;
 30 }
 31 
 32 static int cirrus_scodec_test_gpio_direction_in(struct gpio_chip *chip,
 33                                                 unsigned int offset)
 34 {
 35         return 0;
 36 }
 37 
 38 static int cirrus_scodec_test_gpio_get(struct gpio_chip *chip, unsigned int offset)
 39 {
 40         struct cirrus_scodec_test_gpio *gpio_priv = gpiochip_get_data(chip);
 41 
 42         return !!(gpio_priv->pin_state & BIT(offset));
 43 }
 44 
 45 static int cirrus_scodec_test_gpio_direction_out(struct gpio_chip *chip,
 46                                                  unsigned int offset, int value)
 47 {
 48         return -EOPNOTSUPP;
 49 }
 50 
 51 static void cirrus_scodec_test_gpio_set(struct gpio_chip *chip, unsigned int offset,
 52                                         int value)
 53 {
 54 }
 55 
 56 static int cirrus_scodec_test_gpio_set_config(struct gpio_chip *gc,
 57                                               unsigned int offset,
 58                                               unsigned long config)
 59 {
 60         switch (pinconf_to_config_param(config)) {
 61         case PIN_CONFIG_OUTPUT:
 62         case PIN_CONFIG_OUTPUT_ENABLE:
 63                 return -EOPNOTSUPP;
 64         default:
 65                 return 0;
 66         }
 67 }
 68 
 69 static const struct gpio_chip cirrus_scodec_test_gpio_chip = {
 70         .label                  = "cirrus_scodec_test_gpio",
 71         .owner                  = THIS_MODULE,
 72         .request                = gpiochip_generic_request,
 73         .free                   = gpiochip_generic_free,
 74         .get_direction          = cirrus_scodec_test_gpio_get_direction,
 75         .direction_input        = cirrus_scodec_test_gpio_direction_in,
 76         .get                    = cirrus_scodec_test_gpio_get,
 77         .direction_output       = cirrus_scodec_test_gpio_direction_out,
 78         .set                    = cirrus_scodec_test_gpio_set,
 79         .set_config             = cirrus_scodec_test_gpio_set_config,
 80         .base                   = -1,
 81         .ngpio                  = 32,
 82 };
 83 
 84 static int cirrus_scodec_test_gpio_probe(struct platform_device *pdev)
 85 {
 86         struct cirrus_scodec_test_gpio *gpio_priv;
 87         int ret;
 88 
 89         gpio_priv = devm_kzalloc(&pdev->dev, sizeof(*gpio_priv), GFP_KERNEL);
 90         if (!gpio_priv)
 91                 return -ENOMEM;
 92 
 93         /* GPIO core modifies our struct gpio_chip so use a copy */
 94         gpio_priv->chip = cirrus_scodec_test_gpio_chip;
 95         ret = devm_gpiochip_add_data(&pdev->dev, &gpio_priv->chip, gpio_priv);
 96         if (ret)
 97                 return dev_err_probe(&pdev->dev, ret, "Failed to add gpiochip\n");
 98 
 99         dev_set_drvdata(&pdev->dev, gpio_priv);
100 
101         return 0;
102 }
103 
104 static struct platform_driver cirrus_scodec_test_gpio_driver = {
105         .driver.name    = "cirrus_scodec_test_gpio_drv",
106         .probe          = cirrus_scodec_test_gpio_probe,
107 };
108 
109 /* software_node referencing the gpio driver */
110 static const struct software_node cirrus_scodec_test_gpio_swnode = {
111         .name = "cirrus_scodec_test_gpio",
112 };
113 
114 static int cirrus_scodec_test_create_gpio(struct kunit *test)
115 {
116         struct cirrus_scodec_test_priv *priv = test->priv;
117         int ret;
118 
119         priv->gpio_pdev = platform_device_alloc(cirrus_scodec_test_gpio_driver.driver.name, -1);
120         if (!priv->gpio_pdev)
121                 return -ENOMEM;
122 
123         ret = device_add_software_node(&priv->gpio_pdev->dev, &cirrus_scodec_test_gpio_swnode);
124         if (ret) {
125                 platform_device_put(priv->gpio_pdev);
126                 KUNIT_FAIL(test, "Failed to add swnode to gpio: %d\n", ret);
127                 return ret;
128         }
129 
130         ret = platform_device_add(priv->gpio_pdev);
131         if (ret) {
132                 platform_device_put(priv->gpio_pdev);
133                 KUNIT_FAIL(test, "Failed to add gpio platform device: %d\n", ret);
134                 return ret;
135         }
136 
137         priv->gpio_priv = dev_get_drvdata(&priv->gpio_pdev->dev);
138         if (!priv->gpio_priv) {
139                 platform_device_put(priv->gpio_pdev);
140                 KUNIT_FAIL(test, "Failed to get gpio private data\n");
141                 return -EINVAL;
142         }
143 
144         return 0;
145 }
146 
147 static void cirrus_scodec_test_set_gpio_ref_arg(struct software_node_ref_args *arg,
148                                                 int gpio_num)
149 {
150         struct software_node_ref_args template =
151                 SOFTWARE_NODE_REFERENCE(&cirrus_scodec_test_gpio_swnode, gpio_num, 0);
152 
153         *arg = template;
154 }
155 
156 static int cirrus_scodec_test_set_spkid_swnode(struct kunit *test,
157                                                struct device *dev,
158                                                struct software_node_ref_args *args,
159                                                int num_args)
160 {
161         const struct property_entry props_template[] = {
162                 PROPERTY_ENTRY_REF_ARRAY_LEN("spk-id-gpios", args, num_args),
163                 { }
164         };
165         struct property_entry *props;
166         struct software_node *node;
167 
168         node = kunit_kzalloc(test, sizeof(*node), GFP_KERNEL);
169         if (!node)
170                 return -ENOMEM;
171 
172         props = kunit_kzalloc(test, sizeof(props_template), GFP_KERNEL);
173         if (!props)
174                 return -ENOMEM;
175 
176         memcpy(props, props_template, sizeof(props_template));
177         node->properties = props;
178 
179         return device_add_software_node(dev, node);
180 }
181 
182 struct cirrus_scodec_test_spkid_param {
183         int num_amps;
184         int gpios_per_amp;
185         int num_amps_sharing;
186 };
187 
188 static void cirrus_scodec_test_spkid_parse(struct kunit *test)
189 {
190         struct cirrus_scodec_test_priv *priv = test->priv;
191         const struct cirrus_scodec_test_spkid_param *param = test->param_value;
192         int num_spk_id_refs = param->num_amps * param->gpios_per_amp;
193         struct software_node_ref_args *refs;
194         struct device *dev = &priv->amp_pdev.dev;
195         unsigned int v;
196         int i, ret;
197 
198         refs = kunit_kcalloc(test, num_spk_id_refs, sizeof(*refs), GFP_KERNEL);
199         KUNIT_ASSERT_NOT_NULL(test, refs);
200 
201         for (i = 0, v = 0; i < num_spk_id_refs; ) {
202                 cirrus_scodec_test_set_gpio_ref_arg(&refs[i++], v++);
203 
204                 /*
205                  * If amps are sharing GPIOs repeat the last set of
206                  * GPIOs until we've done that number of amps.
207                  * We have done all GPIOs for an amp when i is a multiple
208                  * of gpios_per_amp.
209                  * We have done all amps sharing the same GPIOs when i is
210                  * a multiple of (gpios_per_amp * num_amps_sharing).
211                  */
212                 if (!(i % param->gpios_per_amp) &&
213                     (i % (param->gpios_per_amp * param->num_amps_sharing)))
214                         v -= param->gpios_per_amp;
215         }
216 
217         ret = cirrus_scodec_test_set_spkid_swnode(test, dev, refs, num_spk_id_refs);
218         KUNIT_EXPECT_EQ_MSG(test, ret, 0, "Failed to add swnode\n");
219 
220         for (i = 0; i < param->num_amps; ++i) {
221                 for (v = 0; v < (1 << param->gpios_per_amp); ++v) {
222                         /* Set only the GPIO bits used by this amp */
223                         priv->gpio_priv->pin_state =
224                                 v << (param->gpios_per_amp * (i / param->num_amps_sharing));
225 
226                         ret = cirrus_scodec_get_speaker_id(dev, i, param->num_amps, -1);
227                         KUNIT_EXPECT_EQ_MSG(test, ret, v,
228                                             "get_speaker_id failed amp:%d pin_state:%#x\n",
229                                             i, priv->gpio_priv->pin_state);
230                 }
231         }
232 }
233 
234 static void cirrus_scodec_test_no_spkid(struct kunit *test)
235 {
236         struct cirrus_scodec_test_priv *priv = test->priv;
237         struct device *dev = &priv->amp_pdev.dev;
238         int ret;
239 
240         ret = cirrus_scodec_get_speaker_id(dev, 0, 4, -1);
241         KUNIT_EXPECT_EQ(test, ret, -ENOENT);
242 }
243 
244 static void cirrus_scodec_test_dev_release(struct device *dev)
245 {
246 }
247 
248 static int cirrus_scodec_test_case_init(struct kunit *test)
249 {
250         struct cirrus_scodec_test_priv *priv;
251         int ret;
252 
253         priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
254         if (!priv)
255                 return -ENOMEM;
256 
257         test->priv = priv;
258 
259         /* Create dummy GPIO */
260         ret = cirrus_scodec_test_create_gpio(test);
261         if (ret < 0)
262                 return ret;
263 
264         /* Create dummy amp driver dev */
265         priv->amp_pdev.name = "cirrus_scodec_test_amp_drv";
266         priv->amp_pdev.id = -1;
267         priv->amp_pdev.dev.release = cirrus_scodec_test_dev_release;
268         ret = platform_device_register(&priv->amp_pdev);
269         KUNIT_ASSERT_GE_MSG(test, ret, 0, "Failed to register amp platform device\n");
270 
271         return 0;
272 }
273 
274 static void cirrus_scodec_test_case_exit(struct kunit *test)
275 {
276         struct cirrus_scodec_test_priv *priv = test->priv;
277 
278         if (priv->amp_pdev.name)
279                 platform_device_unregister(&priv->amp_pdev);
280 
281         if (priv->gpio_pdev) {
282                 device_remove_software_node(&priv->gpio_pdev->dev);
283                 platform_device_unregister(priv->gpio_pdev);
284         }
285 }
286 
287 static int cirrus_scodec_test_suite_init(struct kunit_suite *suite)
288 {
289         int ret;
290 
291         /* Register mock GPIO driver */
292         ret = platform_driver_register(&cirrus_scodec_test_gpio_driver);
293         if (ret < 0) {
294                 kunit_err(suite, "Failed to register gpio platform driver, %d\n", ret);
295                 return ret;
296         }
297 
298         return 0;
299 }
300 
301 static void cirrus_scodec_test_suite_exit(struct kunit_suite *suite)
302 {
303         platform_driver_unregister(&cirrus_scodec_test_gpio_driver);
304 }
305 
306 static const struct cirrus_scodec_test_spkid_param cirrus_scodec_test_spkid_param_cases[] = {
307         { .num_amps = 2, .gpios_per_amp = 1, .num_amps_sharing = 1 },
308         { .num_amps = 2, .gpios_per_amp = 2, .num_amps_sharing = 1 },
309         { .num_amps = 2, .gpios_per_amp = 3, .num_amps_sharing = 1 },
310         { .num_amps = 2, .gpios_per_amp = 4, .num_amps_sharing = 1 },
311         { .num_amps = 3, .gpios_per_amp = 1, .num_amps_sharing = 1 },
312         { .num_amps = 3, .gpios_per_amp = 2, .num_amps_sharing = 1 },
313         { .num_amps = 3, .gpios_per_amp = 3, .num_amps_sharing = 1 },
314         { .num_amps = 3, .gpios_per_amp = 4, .num_amps_sharing = 1 },
315         { .num_amps = 4, .gpios_per_amp = 1, .num_amps_sharing = 1 },
316         { .num_amps = 4, .gpios_per_amp = 2, .num_amps_sharing = 1 },
317         { .num_amps = 4, .gpios_per_amp = 3, .num_amps_sharing = 1 },
318         { .num_amps = 4, .gpios_per_amp = 4, .num_amps_sharing = 1 },
319 
320         /* Same GPIO shared by all amps */
321         { .num_amps = 2, .gpios_per_amp = 1, .num_amps_sharing = 2 },
322         { .num_amps = 2, .gpios_per_amp = 2, .num_amps_sharing = 2 },
323         { .num_amps = 2, .gpios_per_amp = 3, .num_amps_sharing = 2 },
324         { .num_amps = 2, .gpios_per_amp = 4, .num_amps_sharing = 2 },
325         { .num_amps = 3, .gpios_per_amp = 1, .num_amps_sharing = 3 },
326         { .num_amps = 3, .gpios_per_amp = 2, .num_amps_sharing = 3 },
327         { .num_amps = 3, .gpios_per_amp = 3, .num_amps_sharing = 3 },
328         { .num_amps = 3, .gpios_per_amp = 4, .num_amps_sharing = 3 },
329         { .num_amps = 4, .gpios_per_amp = 1, .num_amps_sharing = 4 },
330         { .num_amps = 4, .gpios_per_amp = 2, .num_amps_sharing = 4 },
331         { .num_amps = 4, .gpios_per_amp = 3, .num_amps_sharing = 4 },
332         { .num_amps = 4, .gpios_per_amp = 4, .num_amps_sharing = 4 },
333 
334         /* Two sets of shared GPIOs */
335         { .num_amps = 4, .gpios_per_amp = 1, .num_amps_sharing = 2 },
336         { .num_amps = 4, .gpios_per_amp = 2, .num_amps_sharing = 2 },
337         { .num_amps = 4, .gpios_per_amp = 3, .num_amps_sharing = 2 },
338         { .num_amps = 4, .gpios_per_amp = 4, .num_amps_sharing = 2 },
339 };
340 
341 static void cirrus_scodec_test_spkid_param_desc(const struct cirrus_scodec_test_spkid_param *param,
342                                                 char *desc)
343 {
344         snprintf(desc, KUNIT_PARAM_DESC_SIZE, "amps:%d gpios_per_amp:%d num_amps_sharing:%d",
345                  param->num_amps, param->gpios_per_amp, param->num_amps_sharing);
346 }
347 
348 KUNIT_ARRAY_PARAM(cirrus_scodec_test_spkid, cirrus_scodec_test_spkid_param_cases,
349                   cirrus_scodec_test_spkid_param_desc);
350 
351 static struct kunit_case cirrus_scodec_test_cases[] = {
352         KUNIT_CASE_PARAM(cirrus_scodec_test_spkid_parse, cirrus_scodec_test_spkid_gen_params),
353         KUNIT_CASE(cirrus_scodec_test_no_spkid),
354         { } /* terminator */
355 };
356 
357 static struct kunit_suite cirrus_scodec_test_suite = {
358         .name = "snd-hda-scodec-cs35l56-test",
359         .suite_init = cirrus_scodec_test_suite_init,
360         .suite_exit = cirrus_scodec_test_suite_exit,
361         .init = cirrus_scodec_test_case_init,
362         .exit = cirrus_scodec_test_case_exit,
363         .test_cases = cirrus_scodec_test_cases,
364 };
365 
366 kunit_test_suite(cirrus_scodec_test_suite);
367 
368 MODULE_IMPORT_NS(SND_HDA_CIRRUS_SCODEC);
369 MODULE_DESCRIPTION("KUnit test for the Cirrus side-codec library");
370 MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
371 MODULE_LICENSE("GPL");
372 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php