Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1// SPDX-License-Identifier: GPL-2.0-only
  2//
  3// KUnit test for the Cirrus common amplifier library.
  4//
  5// Copyright (C) 2024 Cirrus Logic, Inc. and
  6//                    Cirrus Logic International Semiconductor Ltd.
  7
  8#include <kunit/test.h>
  9#include <kunit/static_stub.h>
 10#include <linux/firmware/cirrus/cs_dsp.h>
 11#include <linux/firmware/cirrus/wmfw.h>
 12#include <linux/gpio/driver.h>
 13#include <linux/list.h>
 14#include <linux/module.h>
 15#include <linux/platform_device.h>
 16#include <linux/random.h>
 17#include <sound/cs-amp-lib.h>
 18
 19struct cs_amp_lib_test_priv {
 20	struct platform_device amp_pdev;
 21
 22	struct cirrus_amp_efi_data *cal_blob;
 23	struct list_head ctl_write_list;
 24};
 25
 26struct cs_amp_lib_test_ctl_write_entry {
 27	struct list_head list;
 28	unsigned int value;
 29	char name[16];
 30};
 31
 32struct cs_amp_lib_test_param {
 33	int num_amps;
 34	int amp_index;
 35};
 36
 37static void cs_amp_lib_test_init_dummy_cal_blob(struct kunit *test, int num_amps)
 38{
 39	struct cs_amp_lib_test_priv *priv = test->priv;
 40	unsigned int blob_size;
 41	int i;
 42
 43	blob_size = offsetof(struct cirrus_amp_efi_data, data) +
 44		    sizeof(struct cirrus_amp_cal_data) * num_amps;
 45
 46	priv->cal_blob = kunit_kzalloc(test, blob_size, GFP_KERNEL);
 47	KUNIT_ASSERT_NOT_NULL(test, priv->cal_blob);
 48
 49	priv->cal_blob->size = blob_size;
 50	priv->cal_blob->count = num_amps;
 51
 52	get_random_bytes(priv->cal_blob->data, sizeof(struct cirrus_amp_cal_data) * num_amps);
 53
 54	/* Ensure all timestamps are non-zero to mark the entry valid. */
 55	for (i = 0; i < num_amps; i++)
 56		priv->cal_blob->data[i].calTime[0] |= 1;
 57
 58	/* Ensure that all UIDs are non-zero and unique. */
 59	for (i = 0; i < num_amps; i++)
 60		*(u8 *)&priv->cal_blob->data[i].calTarget[0] = i + 1;
 61}
 62
 63static u64 cs_amp_lib_test_get_target_uid(struct kunit *test)
 64{
 65	struct cs_amp_lib_test_priv *priv = test->priv;
 66	const struct cs_amp_lib_test_param *param = test->param_value;
 67	u64 uid;
 68
 69	uid = priv->cal_blob->data[param->amp_index].calTarget[1];
 70	uid <<= 32;
 71	uid |= priv->cal_blob->data[param->amp_index].calTarget[0];
 72
 73	return uid;
 74}
 75
 76/* Redirected get_efi_variable to simulate that the file is too short */
 77static efi_status_t cs_amp_lib_test_get_efi_variable_nohead(efi_char16_t *name,
 78							    efi_guid_t *guid,
 79							    unsigned long *size,
 80							    void *buf)
 81{
 82	if (!buf) {
 83		*size = offsetof(struct cirrus_amp_efi_data, data) - 1;
 84		return EFI_BUFFER_TOO_SMALL;
 85	}
 86
 87	return EFI_NOT_FOUND;
 88}
 89
 90/* Should return -EOVERFLOW if the header is larger than the EFI data */
 91static void cs_amp_lib_test_cal_data_too_short_test(struct kunit *test)
 92{
 93	struct cs_amp_lib_test_priv *priv = test->priv;
 94	struct cirrus_amp_cal_data result_data;
 95	int ret;
 96
 97	/* Redirect calls to get EFI data */
 98	kunit_activate_static_stub(test,
 99				   cs_amp_test_hooks->get_efi_variable,
100				   cs_amp_lib_test_get_efi_variable_nohead);
101
102	ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, 0, 0, &result_data);
103	KUNIT_EXPECT_EQ(test, ret, -EOVERFLOW);
104
105	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
106}
107
108/* Redirected get_efi_variable to simulate that the count is larger than the file */
109static efi_status_t cs_amp_lib_test_get_efi_variable_bad_count(efi_char16_t *name,
110							       efi_guid_t *guid,
111							       unsigned long *size,
112							       void *buf)
113{
114	struct kunit *test = kunit_get_current_test();
115	struct cs_amp_lib_test_priv *priv = test->priv;
116
117	if (!buf) {
118		/*
119		 * Return a size that is shorter than required for the
120		 * declared number of entries.
121		 */
122		*size = priv->cal_blob->size - 1;
123		return EFI_BUFFER_TOO_SMALL;
124	}
125
126	memcpy(buf, priv->cal_blob, priv->cal_blob->size - 1);
127
128	return EFI_SUCCESS;
129}
130
131/* Should return -EOVERFLOW if the entry count is larger than the EFI data */
132static void cs_amp_lib_test_cal_count_too_big_test(struct kunit *test)
133{
134	struct cs_amp_lib_test_priv *priv = test->priv;
135	struct cirrus_amp_cal_data result_data;
136	int ret;
137
138	cs_amp_lib_test_init_dummy_cal_blob(test, 8);
139
140	/* Redirect calls to get EFI data */
141	kunit_activate_static_stub(test,
142				   cs_amp_test_hooks->get_efi_variable,
143				   cs_amp_lib_test_get_efi_variable_bad_count);
144
145	ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, 0, 0, &result_data);
146	KUNIT_EXPECT_EQ(test, ret, -EOVERFLOW);
147
148	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
149}
150
151/* Redirected get_efi_variable to simulate that the variable not found */
152static efi_status_t cs_amp_lib_test_get_efi_variable_none(efi_char16_t *name,
153							  efi_guid_t *guid,
154							  unsigned long *size,
155							  void *buf)
156{
157	return EFI_NOT_FOUND;
158}
159
160/* If EFI doesn't contain a cal data variable the result should be -ENOENT */
161static void cs_amp_lib_test_no_cal_data_test(struct kunit *test)
162{
163	struct cs_amp_lib_test_priv *priv = test->priv;
164	struct cirrus_amp_cal_data result_data;
165	int ret;
166
167	/* Redirect calls to get EFI data */
168	kunit_activate_static_stub(test,
169				   cs_amp_test_hooks->get_efi_variable,
170				   cs_amp_lib_test_get_efi_variable_none);
171
172	ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, 0, 0, &result_data);
173	KUNIT_EXPECT_EQ(test, ret, -ENOENT);
174
175	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
176}
177
178/* Redirected get_efi_variable to simulate reading a cal data blob */
179static efi_status_t cs_amp_lib_test_get_efi_variable(efi_char16_t *name,
180						     efi_guid_t *guid,
181						     unsigned long *size,
182						     void *buf)
183{
184	static const efi_char16_t expected_name[] = L"CirrusSmartAmpCalibrationData";
185	static const efi_guid_t expected_guid =
186		EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3);
187	struct kunit *test = kunit_get_current_test();
188	struct cs_amp_lib_test_priv *priv = test->priv;
189
190	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, name);
191	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, guid);
192	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, size);
193
194	KUNIT_EXPECT_MEMEQ(test, name, expected_name, sizeof(expected_name));
195	KUNIT_EXPECT_MEMEQ(test, guid, &expected_guid, sizeof(expected_guid));
196
197	if (!buf) {
198		*size = priv->cal_blob->size;
199		return EFI_BUFFER_TOO_SMALL;
200	}
201
202	KUNIT_ASSERT_GE_MSG(test, ksize(buf), priv->cal_blob->size, "Buffer to small");
203
204	memcpy(buf, priv->cal_blob, priv->cal_blob->size);
205
206	return EFI_SUCCESS;
207}
208
209/* Get cal data block for a given amp, matched by target UID. */
210static void cs_amp_lib_test_get_efi_cal_by_uid_test(struct kunit *test)
211{
212	struct cs_amp_lib_test_priv *priv = test->priv;
213	const struct cs_amp_lib_test_param *param = test->param_value;
214	struct cirrus_amp_cal_data result_data;
215	u64 target_uid;
216	int ret;
217
218	cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
219
220	/* Redirect calls to get EFI data */
221	kunit_activate_static_stub(test,
222				   cs_amp_test_hooks->get_efi_variable,
223				   cs_amp_lib_test_get_efi_variable);
224
225	target_uid = cs_amp_lib_test_get_target_uid(test);
226	ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, target_uid, -1, &result_data);
227	KUNIT_EXPECT_EQ(test, ret, 0);
228
229	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
230
231	KUNIT_EXPECT_EQ(test, result_data.calTarget[0], target_uid & 0xFFFFFFFFULL);
232	KUNIT_EXPECT_EQ(test, result_data.calTarget[1], target_uid >> 32);
233	KUNIT_EXPECT_EQ(test, result_data.calTime[0],
234			      priv->cal_blob->data[param->amp_index].calTime[0]);
235	KUNIT_EXPECT_EQ(test, result_data.calTime[1],
236			      priv->cal_blob->data[param->amp_index].calTime[1]);
237	KUNIT_EXPECT_EQ(test, result_data.calAmbient,
238			      priv->cal_blob->data[param->amp_index].calAmbient);
239	KUNIT_EXPECT_EQ(test, result_data.calStatus,
240			      priv->cal_blob->data[param->amp_index].calStatus);
241	KUNIT_EXPECT_EQ(test, result_data.calR,
242			      priv->cal_blob->data[param->amp_index].calR);
243}
244
245/* Get cal data block for a given amp index without checking target UID. */
246static void cs_amp_lib_test_get_efi_cal_by_index_unchecked_test(struct kunit *test)
247{
248	struct cs_amp_lib_test_priv *priv = test->priv;
249	const struct cs_amp_lib_test_param *param = test->param_value;
250	struct cirrus_amp_cal_data result_data;
251	int ret;
252
253	cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
254
255	/* Redirect calls to get EFI data */
256	kunit_activate_static_stub(test,
257				   cs_amp_test_hooks->get_efi_variable,
258				   cs_amp_lib_test_get_efi_variable);
259
260	ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, 0,
261					      param->amp_index, &result_data);
262	KUNIT_EXPECT_EQ(test, ret, 0);
263
264	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
265
266	KUNIT_EXPECT_EQ(test, result_data.calTime[0],
267			      priv->cal_blob->data[param->amp_index].calTime[0]);
268	KUNIT_EXPECT_EQ(test, result_data.calTime[1],
269			      priv->cal_blob->data[param->amp_index].calTime[1]);
270	KUNIT_EXPECT_EQ(test, result_data.calAmbient,
271			      priv->cal_blob->data[param->amp_index].calAmbient);
272	KUNIT_EXPECT_EQ(test, result_data.calStatus,
273			      priv->cal_blob->data[param->amp_index].calStatus);
274	KUNIT_EXPECT_EQ(test, result_data.calR,
275			      priv->cal_blob->data[param->amp_index].calR);
276}
277
278/* Get cal data block for a given amp index with checked target UID. */
279static void cs_amp_lib_test_get_efi_cal_by_index_checked_test(struct kunit *test)
280{
281	struct cs_amp_lib_test_priv *priv = test->priv;
282	const struct cs_amp_lib_test_param *param = test->param_value;
283	struct cirrus_amp_cal_data result_data;
284	u64 target_uid;
285	int ret;
286
287	cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
288
289	/* Redirect calls to get EFI data */
290	kunit_activate_static_stub(test,
291				   cs_amp_test_hooks->get_efi_variable,
292				   cs_amp_lib_test_get_efi_variable);
293
294	target_uid = cs_amp_lib_test_get_target_uid(test);
295	ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, target_uid,
296					      param->amp_index, &result_data);
297	KUNIT_EXPECT_EQ(test, ret, 0);
298
299	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
300
301	KUNIT_EXPECT_EQ(test, result_data.calTime[0],
302			      priv->cal_blob->data[param->amp_index].calTime[0]);
303	KUNIT_EXPECT_EQ(test, result_data.calTime[1],
304			      priv->cal_blob->data[param->amp_index].calTime[1]);
305	KUNIT_EXPECT_EQ(test, result_data.calAmbient,
306			      priv->cal_blob->data[param->amp_index].calAmbient);
307	KUNIT_EXPECT_EQ(test, result_data.calStatus,
308			      priv->cal_blob->data[param->amp_index].calStatus);
309	KUNIT_EXPECT_EQ(test, result_data.calR,
310			      priv->cal_blob->data[param->amp_index].calR);
311}
312
313/*
314 * Get cal data block for a given amp index with checked target UID.
315 * The UID does not match so the result should be -ENOENT.
316 */
317static void cs_amp_lib_test_get_efi_cal_by_index_uid_mismatch_test(struct kunit *test)
318{
319	struct cs_amp_lib_test_priv *priv = test->priv;
320	const struct cs_amp_lib_test_param *param = test->param_value;
321	struct cirrus_amp_cal_data result_data;
322	u64 target_uid;
323	int ret;
324
325	cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
326
327	/* Redirect calls to get EFI data */
328	kunit_activate_static_stub(test,
329				   cs_amp_test_hooks->get_efi_variable,
330				   cs_amp_lib_test_get_efi_variable);
331
332	/* Get a target UID that won't match the entry */
333	target_uid = ~cs_amp_lib_test_get_target_uid(test);
334	ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, target_uid,
335					      param->amp_index, &result_data);
336	KUNIT_EXPECT_EQ(test, ret, -ENOENT);
337
338	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
339}
340
341/*
342 * Get cal data block for a given amp, where the cal data does not
343 * specify calTarget so the lookup falls back to using the index
344 */
345static void cs_amp_lib_test_get_efi_cal_by_index_fallback_test(struct kunit *test)
346{
347	struct cs_amp_lib_test_priv *priv = test->priv;
348	const struct cs_amp_lib_test_param *param = test->param_value;
349	struct cirrus_amp_cal_data result_data;
350	static const u64 bad_target_uid = 0xBADCA100BABABABAULL;
351	int i, ret;
352
353	cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
354
355	/* Make all the target values zero so they are ignored */
356	for (i = 0; i < priv->cal_blob->count; ++i) {
357		priv->cal_blob->data[i].calTarget[0] = 0;
358		priv->cal_blob->data[i].calTarget[1] = 0;
359	}
360
361	/* Redirect calls to get EFI data */
362	kunit_activate_static_stub(test,
363				   cs_amp_test_hooks->get_efi_variable,
364				   cs_amp_lib_test_get_efi_variable);
365
366	ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, bad_target_uid,
367					      param->amp_index, &result_data);
368	KUNIT_EXPECT_EQ(test, ret, 0);
369
370	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
371
372	KUNIT_EXPECT_EQ(test, result_data.calTime[0],
373			      priv->cal_blob->data[param->amp_index].calTime[0]);
374	KUNIT_EXPECT_EQ(test, result_data.calTime[1],
375			      priv->cal_blob->data[param->amp_index].calTime[1]);
376	KUNIT_EXPECT_EQ(test, result_data.calAmbient,
377			      priv->cal_blob->data[param->amp_index].calAmbient);
378	KUNIT_EXPECT_EQ(test, result_data.calStatus,
379			      priv->cal_blob->data[param->amp_index].calStatus);
380	KUNIT_EXPECT_EQ(test, result_data.calR,
381			      priv->cal_blob->data[param->amp_index].calR);
382}
383
384/*
385 * If the target UID isn't present in the cal data, and there isn't an
386 * index to fall back do, the result should be -ENOENT.
387 */
388static void cs_amp_lib_test_get_efi_cal_uid_not_found_noindex_test(struct kunit *test)
389{
390	struct cs_amp_lib_test_priv *priv = test->priv;
391	struct cirrus_amp_cal_data result_data;
392	static const u64 bad_target_uid = 0xBADCA100BABABABAULL;
393	int i, ret;
394
395	cs_amp_lib_test_init_dummy_cal_blob(test, 8);
396
397	/* Make all the target values != bad_target_uid */
398	for (i = 0; i < priv->cal_blob->count; ++i) {
399		priv->cal_blob->data[i].calTarget[0] &= ~(bad_target_uid & 0xFFFFFFFFULL);
400		priv->cal_blob->data[i].calTarget[1] &= ~(bad_target_uid >> 32);
401	}
402
403	/* Redirect calls to get EFI data */
404	kunit_activate_static_stub(test,
405				   cs_amp_test_hooks->get_efi_variable,
406				   cs_amp_lib_test_get_efi_variable);
407
408	ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, bad_target_uid, -1,
409					      &result_data);
410	KUNIT_EXPECT_EQ(test, ret, -ENOENT);
411
412	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
413}
414
415/*
416 * If the target UID isn't present in the cal data, and the index is
417 * out of range, the result should be -ENOENT.
418 */
419static void cs_amp_lib_test_get_efi_cal_uid_not_found_index_not_found_test(struct kunit *test)
420{
421	struct cs_amp_lib_test_priv *priv = test->priv;
422	struct cirrus_amp_cal_data result_data;
423	static const u64 bad_target_uid = 0xBADCA100BABABABAULL;
424	int i, ret;
425
426	cs_amp_lib_test_init_dummy_cal_blob(test, 8);
427
428	/* Make all the target values != bad_target_uid */
429	for (i = 0; i < priv->cal_blob->count; ++i) {
430		priv->cal_blob->data[i].calTarget[0] &= ~(bad_target_uid & 0xFFFFFFFFULL);
431		priv->cal_blob->data[i].calTarget[1] &= ~(bad_target_uid >> 32);
432	}
433
434	/* Redirect calls to get EFI data */
435	kunit_activate_static_stub(test,
436				   cs_amp_test_hooks->get_efi_variable,
437				   cs_amp_lib_test_get_efi_variable);
438
439	ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, bad_target_uid, 99,
440					      &result_data);
441	KUNIT_EXPECT_EQ(test, ret, -ENOENT);
442
443	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
444}
445
446/*
447 * If the target UID isn't given, and the index is out of range, the
448 * result should be -ENOENT.
449 */
450static void cs_amp_lib_test_get_efi_cal_no_uid_index_not_found_test(struct kunit *test)
451{
452	struct cs_amp_lib_test_priv *priv = test->priv;
453	struct cirrus_amp_cal_data result_data;
454	int ret;
455
456	cs_amp_lib_test_init_dummy_cal_blob(test, 8);
457
458	/* Redirect calls to get EFI data */
459	kunit_activate_static_stub(test,
460				   cs_amp_test_hooks->get_efi_variable,
461				   cs_amp_lib_test_get_efi_variable);
462
463	ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, 0, 99, &result_data);
464	KUNIT_EXPECT_EQ(test, ret, -ENOENT);
465
466	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
467}
468
469/* If neither the target UID or the index is given the result should be -ENOENT. */
470static void cs_amp_lib_test_get_efi_cal_no_uid_no_index_test(struct kunit *test)
471{
472	struct cs_amp_lib_test_priv *priv = test->priv;
473	struct cirrus_amp_cal_data result_data;
474	int ret;
475
476	cs_amp_lib_test_init_dummy_cal_blob(test, 8);
477
478	/* Redirect calls to get EFI data */
479	kunit_activate_static_stub(test,
480				   cs_amp_test_hooks->get_efi_variable,
481				   cs_amp_lib_test_get_efi_variable);
482
483	ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, 0, -1, &result_data);
484	KUNIT_EXPECT_EQ(test, ret, -ENOENT);
485
486	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
487}
488
489/*
490 * If the UID is passed as 0 this must not match an entry with an
491 * unpopulated calTarget
492 */
493static void cs_amp_lib_test_get_efi_cal_zero_not_matched_test(struct kunit *test)
494{
495	struct cs_amp_lib_test_priv *priv = test->priv;
496	struct cirrus_amp_cal_data result_data;
497	int i, ret;
498
499	cs_amp_lib_test_init_dummy_cal_blob(test, 8);
500
501	/* Make all the target values zero so they are ignored */
502	for (i = 0; i < priv->cal_blob->count; ++i) {
503		priv->cal_blob->data[i].calTarget[0] = 0;
504		priv->cal_blob->data[i].calTarget[1] = 0;
505	}
506
507	/* Redirect calls to get EFI data */
508	kunit_activate_static_stub(test,
509				   cs_amp_test_hooks->get_efi_variable,
510				   cs_amp_lib_test_get_efi_variable);
511
512	ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, 0, -1, &result_data);
513	KUNIT_EXPECT_EQ(test, ret, -ENOENT);
514
515	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
516}
517
518/*
519 * If an entry has a timestamp of 0 it should be ignored even if it has
520 * a matching target UID.
521 */
522static void cs_amp_lib_test_get_efi_cal_empty_entry_test(struct kunit *test)
523{
524	struct cs_amp_lib_test_priv *priv = test->priv;
525	struct cirrus_amp_cal_data result_data;
526	u64 uid;
527
528	cs_amp_lib_test_init_dummy_cal_blob(test, 8);
529
530	/* Mark the 3rd entry invalid by zeroing calTime */
531	priv->cal_blob->data[2].calTime[0] = 0;
532	priv->cal_blob->data[2].calTime[1] = 0;
533
534	/* Get the UID value of the 3rd entry */
535	uid = priv->cal_blob->data[2].calTarget[1];
536	uid <<= 32;
537	uid |= priv->cal_blob->data[2].calTarget[0];
538
539	/* Redirect calls to get EFI data */
540	kunit_activate_static_stub(test,
541				   cs_amp_test_hooks->get_efi_variable,
542				   cs_amp_lib_test_get_efi_variable);
543
544	/* Lookup by UID should not find it */
545	KUNIT_EXPECT_EQ(test,
546			cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev,
547							uid, -1,
548							&result_data),
549			-ENOENT);
550
551	/* Get by index should ignore it */
552	KUNIT_EXPECT_EQ(test,
553			cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev,
554							0, 2,
555							&result_data),
556			-ENOENT);
557
558	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
559}
560
561static const struct cirrus_amp_cal_controls cs_amp_lib_test_calibration_controls = {
562	.alg_id =	0x9f210,
563	.mem_region =	WMFW_ADSP2_YM,
564	.ambient =	"CAL_AMBIENT",
565	.calr =		"CAL_R",
566	.status =	"CAL_STATUS",
567	.checksum =	"CAL_CHECKSUM",
568};
569
570static int cs_amp_lib_test_write_cal_coeff(struct cs_dsp *dsp,
571					   const struct cirrus_amp_cal_controls *controls,
572					   const char *ctl_name, u32 val)
573{
574	struct kunit *test = kunit_get_current_test();
575	struct cs_amp_lib_test_priv *priv = test->priv;
576	struct cs_amp_lib_test_ctl_write_entry *entry;
577
578	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctl_name);
579	KUNIT_EXPECT_PTR_EQ(test, controls, &cs_amp_lib_test_calibration_controls);
580
581	entry = kunit_kzalloc(test, sizeof(*entry), GFP_KERNEL);
582	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, entry);
583
584	INIT_LIST_HEAD(&entry->list);
585	strscpy(entry->name, ctl_name, sizeof(entry->name));
586	entry->value = val;
587
588	list_add_tail(&entry->list, &priv->ctl_write_list);
589
590	return 0;
591}
592
593static void cs_amp_lib_test_write_cal_data_test(struct kunit *test)
594{
595	struct cs_amp_lib_test_priv *priv = test->priv;
596	struct cs_amp_lib_test_ctl_write_entry *entry;
597	struct cirrus_amp_cal_data data;
598	struct cs_dsp *dsp;
599	int ret;
600
601	dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL);
602	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dsp);
603	dsp->dev = &priv->amp_pdev.dev;
604
605	get_random_bytes(&data, sizeof(data));
606
607	/* Redirect calls to write firmware controls */
608	kunit_activate_static_stub(test,
609				   cs_amp_test_hooks->write_cal_coeff,
610				   cs_amp_lib_test_write_cal_coeff);
611
612	ret = cs_amp_write_cal_coeffs(dsp, &cs_amp_lib_test_calibration_controls, &data);
613	KUNIT_EXPECT_EQ(test, ret, 0);
614
615	kunit_deactivate_static_stub(test, cs_amp_test_hooks->write_cal_coeff);
616
617	KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->ctl_write_list), 4);
618
619	/* Checksum control must be written last */
620	entry = list_last_entry(&priv->ctl_write_list, typeof(*entry), list);
621	KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.checksum);
622	KUNIT_EXPECT_EQ(test, entry->value, data.calR + 1);
623	list_del(&entry->list);
624
625	entry = list_first_entry(&priv->ctl_write_list, typeof(*entry), list);
626	KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.ambient);
627	KUNIT_EXPECT_EQ(test, entry->value, data.calAmbient);
628	list_del(&entry->list);
629
630	entry = list_first_entry(&priv->ctl_write_list, typeof(*entry), list);
631	KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.calr);
632	KUNIT_EXPECT_EQ(test, entry->value, data.calR);
633	list_del(&entry->list);
634
635	entry = list_first_entry(&priv->ctl_write_list, typeof(*entry), list);
636	KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.status);
637	KUNIT_EXPECT_EQ(test, entry->value, data.calStatus);
638}
639
640static void cs_amp_lib_test_dev_release(struct device *dev)
641{
642}
643
644static int cs_amp_lib_test_case_init(struct kunit *test)
645{
646	struct cs_amp_lib_test_priv *priv;
647	int ret;
648
649	KUNIT_ASSERT_NOT_NULL(test, cs_amp_test_hooks);
650
651	priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
652	if (!priv)
653		return -ENOMEM;
654
655	test->priv = priv;
656	INIT_LIST_HEAD(&priv->ctl_write_list);
657
658	/* Create dummy amp driver dev */
659	priv->amp_pdev.name = "cs_amp_lib_test_drv";
660	priv->amp_pdev.id = -1;
661	priv->amp_pdev.dev.release = cs_amp_lib_test_dev_release;
662	ret = platform_device_register(&priv->amp_pdev);
663	KUNIT_ASSERT_GE_MSG(test, ret, 0, "Failed to register amp platform device\n");
664
665	return 0;
666}
667
668static void cs_amp_lib_test_case_exit(struct kunit *test)
669{
670	struct cs_amp_lib_test_priv *priv = test->priv;
671
672	if (priv->amp_pdev.name)
673		platform_device_unregister(&priv->amp_pdev);
674}
675
676static const struct cs_amp_lib_test_param cs_amp_lib_test_get_cal_param_cases[] = {
677	{ .num_amps = 2, .amp_index = 0 },
678	{ .num_amps = 2, .amp_index = 1 },
679
680	{ .num_amps = 3, .amp_index = 0 },
681	{ .num_amps = 3, .amp_index = 1 },
682	{ .num_amps = 3, .amp_index = 2 },
683
684	{ .num_amps = 4, .amp_index = 0 },
685	{ .num_amps = 4, .amp_index = 1 },
686	{ .num_amps = 4, .amp_index = 2 },
687	{ .num_amps = 4, .amp_index = 3 },
688
689	{ .num_amps = 5, .amp_index = 0 },
690	{ .num_amps = 5, .amp_index = 1 },
691	{ .num_amps = 5, .amp_index = 2 },
692	{ .num_amps = 5, .amp_index = 3 },
693	{ .num_amps = 5, .amp_index = 4 },
694
695	{ .num_amps = 6, .amp_index = 0 },
696	{ .num_amps = 6, .amp_index = 1 },
697	{ .num_amps = 6, .amp_index = 2 },
698	{ .num_amps = 6, .amp_index = 3 },
699	{ .num_amps = 6, .amp_index = 4 },
700	{ .num_amps = 6, .amp_index = 5 },
701
702	{ .num_amps = 8, .amp_index = 0 },
703	{ .num_amps = 8, .amp_index = 1 },
704	{ .num_amps = 8, .amp_index = 2 },
705	{ .num_amps = 8, .amp_index = 3 },
706	{ .num_amps = 8, .amp_index = 4 },
707	{ .num_amps = 8, .amp_index = 5 },
708	{ .num_amps = 8, .amp_index = 6 },
709	{ .num_amps = 8, .amp_index = 7 },
710};
711
712static void cs_amp_lib_test_get_cal_param_desc(const struct cs_amp_lib_test_param *param,
713					       char *desc)
714{
715	snprintf(desc, KUNIT_PARAM_DESC_SIZE, "num_amps:%d amp_index:%d",
716		 param->num_amps, param->amp_index);
717}
718
719KUNIT_ARRAY_PARAM(cs_amp_lib_test_get_cal, cs_amp_lib_test_get_cal_param_cases,
720		  cs_amp_lib_test_get_cal_param_desc);
721
722static struct kunit_case cs_amp_lib_test_cases[] = {
723	/* Tests for getting calibration data from EFI */
724	KUNIT_CASE(cs_amp_lib_test_cal_data_too_short_test),
725	KUNIT_CASE(cs_amp_lib_test_cal_count_too_big_test),
726	KUNIT_CASE(cs_amp_lib_test_no_cal_data_test),
727	KUNIT_CASE(cs_amp_lib_test_get_efi_cal_uid_not_found_noindex_test),
728	KUNIT_CASE(cs_amp_lib_test_get_efi_cal_uid_not_found_index_not_found_test),
729	KUNIT_CASE(cs_amp_lib_test_get_efi_cal_no_uid_index_not_found_test),
730	KUNIT_CASE(cs_amp_lib_test_get_efi_cal_no_uid_no_index_test),
731	KUNIT_CASE(cs_amp_lib_test_get_efi_cal_zero_not_matched_test),
732	KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_uid_test,
733			 cs_amp_lib_test_get_cal_gen_params),
734	KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_unchecked_test,
735			 cs_amp_lib_test_get_cal_gen_params),
736	KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_checked_test,
737			 cs_amp_lib_test_get_cal_gen_params),
738	KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_uid_mismatch_test,
739			 cs_amp_lib_test_get_cal_gen_params),
740	KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_fallback_test,
741			 cs_amp_lib_test_get_cal_gen_params),
742	KUNIT_CASE(cs_amp_lib_test_get_efi_cal_empty_entry_test),
743
744	/* Tests for writing calibration data */
745	KUNIT_CASE(cs_amp_lib_test_write_cal_data_test),
746
747	{ } /* terminator */
748};
749
750static struct kunit_suite cs_amp_lib_test_suite = {
751	.name = "snd-soc-cs-amp-lib-test",
752	.init = cs_amp_lib_test_case_init,
753	.exit = cs_amp_lib_test_case_exit,
754	.test_cases = cs_amp_lib_test_cases,
755};
756
757kunit_test_suite(cs_amp_lib_test_suite);
758
759MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB");
760MODULE_DESCRIPTION("KUnit test for Cirrus Logic amplifier library");
761MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
762MODULE_LICENSE("GPL");