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