162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci// Copyright (C) 2022 Cirrus Logic, Inc. and
362306a36Sopenharmony_ci//                    Cirrus Logic International Semiconductor Ltd.
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <kunit/test.h>
662306a36Sopenharmony_ci#include <linux/module.h>
762306a36Sopenharmony_ci#include <sound/pcm.h>
862306a36Sopenharmony_ci#include <sound/pcm_params.h>
962306a36Sopenharmony_ci#include <sound/soc.h>
1062306a36Sopenharmony_ci#include <uapi/sound/asound.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_cistatic const struct {
1362306a36Sopenharmony_ci	u32 rate;
1462306a36Sopenharmony_ci	snd_pcm_format_t fmt;
1562306a36Sopenharmony_ci	u8 channels;
1662306a36Sopenharmony_ci	u8 tdm_width;
1762306a36Sopenharmony_ci	u8 tdm_slots;
1862306a36Sopenharmony_ci	u8 slot_multiple;
1962306a36Sopenharmony_ci	u32 bclk;
2062306a36Sopenharmony_ci} tdm_params_to_bclk_cases[] = {
2162306a36Sopenharmony_ci	/* rate		fmt	   channels tdm_width tdm_slots slot_multiple bclk */
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	/* From params only */
2462306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 1,	0,	0,	0,	  128000 },
2562306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 2,	0,	0,	0,	  256000 },
2662306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S24_LE, 1,	0,	0,	0,	  192000 },
2762306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S24_LE, 2,	0,	0,	0,	  384000 },
2862306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 1,	0,	0,	0,	  256000 },
2962306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 2,	0,	0,	0,	  512000 },
3062306a36Sopenharmony_ci	{  44100,  SNDRV_PCM_FORMAT_S16_LE, 1,	0,	0,	0,	  705600 },
3162306a36Sopenharmony_ci	{  44100,  SNDRV_PCM_FORMAT_S16_LE, 2,	0,	0,	0,	 1411200 },
3262306a36Sopenharmony_ci	{  44100,  SNDRV_PCM_FORMAT_S24_LE, 1,	0,	0,	0,	 1058400 },
3362306a36Sopenharmony_ci	{  44100,  SNDRV_PCM_FORMAT_S24_LE, 2,	0,	0,	0,	 2116800 },
3462306a36Sopenharmony_ci	{  44100,  SNDRV_PCM_FORMAT_S32_LE, 1,	0,	0,	0,	 1411200 },
3562306a36Sopenharmony_ci	{  44100,  SNDRV_PCM_FORMAT_S32_LE, 2,	0,	0,	0,	 2822400 },
3662306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 1,	0,	0,	0,	 6144000 },
3762306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 2,	0,	0,	0,	12288000 },
3862306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S24_LE, 1,	0,	0,	0,	 9216000 },
3962306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S24_LE, 2,	0,	0,	0,	18432000 },
4062306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 1,	0,	0,	0,	12288000 },
4162306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 2,	0,	0,	0,	24576000 },
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	/* I2S from params */
4462306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 1,	0,	0,	2,	  256000 },
4562306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 2,	0,	0,	2,	  256000 },
4662306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S24_LE, 1,	0,	0,	2,	  384000 },
4762306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S24_LE, 2,	0,	0,	2,	  384000 },
4862306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 1,	0,	0,	2,	  512000 },
4962306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 2,	0,	0,	2,	  512000 },
5062306a36Sopenharmony_ci	{  44100,  SNDRV_PCM_FORMAT_S16_LE, 1,	0,	0,	2,	 1411200 },
5162306a36Sopenharmony_ci	{  44100,  SNDRV_PCM_FORMAT_S16_LE, 2,	0,	0,	2,	 1411200 },
5262306a36Sopenharmony_ci	{  44100,  SNDRV_PCM_FORMAT_S24_LE, 1,	0,	0,	2,	 2116800 },
5362306a36Sopenharmony_ci	{  44100,  SNDRV_PCM_FORMAT_S24_LE, 2,	0,	0,	2,	 2116800 },
5462306a36Sopenharmony_ci	{  44100,  SNDRV_PCM_FORMAT_S32_LE, 1,	0,	0,	2,	 2822400 },
5562306a36Sopenharmony_ci	{  44100,  SNDRV_PCM_FORMAT_S32_LE, 2,	0,	0,	2,	 2822400 },
5662306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 1,	0,	0,	2,	12288000 },
5762306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 2,	0,	0,	2,	12288000 },
5862306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S24_LE, 1,	0,	0,	2,	18432000 },
5962306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S24_LE, 2,	0,	0,	2,	18432000 },
6062306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 1,	0,	0,	2,	24576000 },
6162306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 2,	0,	0,	2,	24576000 },
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	/* Fixed 8-slot TDM, other values from params */
6462306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 1,	0,	8,	0,	 1024000 },
6562306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 2,	0,	8,	0,	 1024000 },
6662306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 3,	0,	8,	0,	 1024000 },
6762306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 4,	0,	8,	0,	 1024000 },
6862306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 1,	0,	8,	0,	 2048000 },
6962306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 2,	0,	8,	0,	 2048000 },
7062306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 3,	0,	8,	0,	 2048000 },
7162306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 4,	0,	8,	0,	 2048000 },
7262306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 1,	0,	8,	0,	49152000 },
7362306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 2,	0,	8,	0,	49152000 },
7462306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 3,	0,	8,	0,	49152000 },
7562306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 4,	0,	8,	0,	49152000 },
7662306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 1,	0,	8,	0,	98304000 },
7762306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 2,	0,	8,	0,	98304000 },
7862306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 3,	0,	8,	0,	98304000 },
7962306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 4,	0,	8,	0,	98304000 },
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	/* Fixed 32-bit TDM, other values from params */
8262306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 1,	32,	0,	0,	  256000 },
8362306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 2,	32,	0,	0,	  512000 },
8462306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 3,	32,	0,	0,	  768000 },
8562306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 4,	32,	0,	0,	 1024000 },
8662306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 1,	32,	0,	0,	  256000 },
8762306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 2,	32,	0,	0,	  512000 },
8862306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 3,	32,	0,	0,	  768000 },
8962306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S32_LE, 4,	32,	0,	0,	 1024000 },
9062306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 1,	32,	0,	0,	12288000 },
9162306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 2,	32,	0,	0,	24576000 },
9262306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 3,	32,	0,	0,	36864000 },
9362306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S16_LE, 4,	32,	0,	0,	49152000 },
9462306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 1,	32,	0,	0,	12288000 },
9562306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 2,	32,	0,	0,	24576000 },
9662306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 3,	32,	0,	0,	36864000 },
9762306a36Sopenharmony_ci	{ 384000,  SNDRV_PCM_FORMAT_S32_LE, 4,	32,	0,	0,	49152000 },
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	/* Fixed 6-slot 24-bit TDM, other values from params */
10062306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 1,	24,	6,	0,	 1152000 },
10162306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 2,	24,	6,	0,	 1152000 },
10262306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 3,	24,	6,	0,	 1152000 },
10362306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S16_LE, 4,	24,	6,	0,	 1152000 },
10462306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S24_LE, 1,	24,	6,	0,	 1152000 },
10562306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S24_LE, 2,	24,	6,	0,	 1152000 },
10662306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S24_LE, 3,	24,	6,	0,	 1152000 },
10762306a36Sopenharmony_ci	{   8000,  SNDRV_PCM_FORMAT_S24_LE, 4,	24,	6,	0,	 1152000 },
10862306a36Sopenharmony_ci	{ 192000,  SNDRV_PCM_FORMAT_S16_LE, 1,	24,	6,	0,	27648000 },
10962306a36Sopenharmony_ci	{ 192000,  SNDRV_PCM_FORMAT_S16_LE, 2,	24,	6,	0,	27648000 },
11062306a36Sopenharmony_ci	{ 192000,  SNDRV_PCM_FORMAT_S16_LE, 3,	24,	6,	0,	27648000 },
11162306a36Sopenharmony_ci	{ 192000,  SNDRV_PCM_FORMAT_S16_LE, 4,	24,	6,	0,	27648000 },
11262306a36Sopenharmony_ci	{ 192000,  SNDRV_PCM_FORMAT_S24_LE, 1,	24,	6,	0,	27648000 },
11362306a36Sopenharmony_ci	{ 192000,  SNDRV_PCM_FORMAT_S24_LE, 2,	24,	6,	0,	27648000 },
11462306a36Sopenharmony_ci	{ 192000,  SNDRV_PCM_FORMAT_S24_LE, 3,	24,	6,	0,	27648000 },
11562306a36Sopenharmony_ci	{ 192000,  SNDRV_PCM_FORMAT_S24_LE, 4,	24,	6,	0,	27648000 },
11662306a36Sopenharmony_ci};
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic void test_tdm_params_to_bclk_one(struct kunit *test,
11962306a36Sopenharmony_ci					unsigned int rate, snd_pcm_format_t fmt,
12062306a36Sopenharmony_ci					unsigned int channels,
12162306a36Sopenharmony_ci					unsigned int tdm_width, unsigned int tdm_slots,
12262306a36Sopenharmony_ci					unsigned int slot_multiple,
12362306a36Sopenharmony_ci					unsigned int expected_bclk)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	struct snd_pcm_hw_params params;
12662306a36Sopenharmony_ci	int got_bclk;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	_snd_pcm_hw_params_any(&params);
12962306a36Sopenharmony_ci	snd_mask_none(hw_param_mask(&params, SNDRV_PCM_HW_PARAM_FORMAT));
13062306a36Sopenharmony_ci	hw_param_interval(&params, SNDRV_PCM_HW_PARAM_RATE)->min = rate;
13162306a36Sopenharmony_ci	hw_param_interval(&params, SNDRV_PCM_HW_PARAM_RATE)->max = rate;
13262306a36Sopenharmony_ci	hw_param_interval(&params, SNDRV_PCM_HW_PARAM_CHANNELS)->min = channels;
13362306a36Sopenharmony_ci	hw_param_interval(&params, SNDRV_PCM_HW_PARAM_CHANNELS)->max = channels;
13462306a36Sopenharmony_ci	params_set_format(&params, fmt);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	got_bclk = snd_soc_tdm_params_to_bclk(&params, tdm_width, tdm_slots, slot_multiple);
13762306a36Sopenharmony_ci	pr_debug("%s: r=%u sb=%u ch=%u tw=%u ts=%u sm=%u expected=%u got=%d\n",
13862306a36Sopenharmony_ci		 __func__,
13962306a36Sopenharmony_ci		 rate, params_width(&params), channels, tdm_width, tdm_slots, slot_multiple,
14062306a36Sopenharmony_ci		 expected_bclk, got_bclk);
14162306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, expected_bclk, (unsigned int)got_bclk);
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic void test_tdm_params_to_bclk(struct kunit *test)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	int i;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tdm_params_to_bclk_cases); ++i) {
14962306a36Sopenharmony_ci		test_tdm_params_to_bclk_one(test,
15062306a36Sopenharmony_ci					    tdm_params_to_bclk_cases[i].rate,
15162306a36Sopenharmony_ci					    tdm_params_to_bclk_cases[i].fmt,
15262306a36Sopenharmony_ci					    tdm_params_to_bclk_cases[i].channels,
15362306a36Sopenharmony_ci					    tdm_params_to_bclk_cases[i].tdm_width,
15462306a36Sopenharmony_ci					    tdm_params_to_bclk_cases[i].tdm_slots,
15562306a36Sopenharmony_ci					    tdm_params_to_bclk_cases[i].slot_multiple,
15662306a36Sopenharmony_ci					    tdm_params_to_bclk_cases[i].bclk);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci		if (tdm_params_to_bclk_cases[i].slot_multiple > 0)
15962306a36Sopenharmony_ci			continue;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci		/* Slot multiple 1 should have the same effect as multiple 0 */
16262306a36Sopenharmony_ci		test_tdm_params_to_bclk_one(test,
16362306a36Sopenharmony_ci					    tdm_params_to_bclk_cases[i].rate,
16462306a36Sopenharmony_ci					    tdm_params_to_bclk_cases[i].fmt,
16562306a36Sopenharmony_ci					    tdm_params_to_bclk_cases[i].channels,
16662306a36Sopenharmony_ci					    tdm_params_to_bclk_cases[i].tdm_width,
16762306a36Sopenharmony_ci					    tdm_params_to_bclk_cases[i].tdm_slots,
16862306a36Sopenharmony_ci					    1,
16962306a36Sopenharmony_ci					    tdm_params_to_bclk_cases[i].bclk);
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic void test_snd_soc_params_to_bclk_one(struct kunit *test,
17462306a36Sopenharmony_ci					    unsigned int rate, snd_pcm_format_t fmt,
17562306a36Sopenharmony_ci					    unsigned int channels,
17662306a36Sopenharmony_ci					    unsigned int expected_bclk)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	struct snd_pcm_hw_params params;
17962306a36Sopenharmony_ci	int got_bclk;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	_snd_pcm_hw_params_any(&params);
18262306a36Sopenharmony_ci	snd_mask_none(hw_param_mask(&params, SNDRV_PCM_HW_PARAM_FORMAT));
18362306a36Sopenharmony_ci	hw_param_interval(&params, SNDRV_PCM_HW_PARAM_RATE)->min = rate;
18462306a36Sopenharmony_ci	hw_param_interval(&params, SNDRV_PCM_HW_PARAM_RATE)->max = rate;
18562306a36Sopenharmony_ci	hw_param_interval(&params, SNDRV_PCM_HW_PARAM_CHANNELS)->min = channels;
18662306a36Sopenharmony_ci	hw_param_interval(&params, SNDRV_PCM_HW_PARAM_CHANNELS)->max = channels;
18762306a36Sopenharmony_ci	params_set_format(&params, fmt);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	got_bclk = snd_soc_params_to_bclk(&params);
19062306a36Sopenharmony_ci	pr_debug("%s: r=%u sb=%u ch=%u expected=%u got=%d\n",
19162306a36Sopenharmony_ci		 __func__,
19262306a36Sopenharmony_ci		 rate, params_width(&params), channels, expected_bclk, got_bclk);
19362306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, expected_bclk, (unsigned int)got_bclk);
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic void test_snd_soc_params_to_bclk(struct kunit *test)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	int i;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tdm_params_to_bclk_cases); ++i) {
20162306a36Sopenharmony_ci		/*
20262306a36Sopenharmony_ci		 * snd_soc_params_to_bclk() is all the test cases where
20362306a36Sopenharmony_ci		 * snd_pcm_hw_params values are not overridden.
20462306a36Sopenharmony_ci		 */
20562306a36Sopenharmony_ci		if (tdm_params_to_bclk_cases[i].tdm_width |
20662306a36Sopenharmony_ci		    tdm_params_to_bclk_cases[i].tdm_slots |
20762306a36Sopenharmony_ci		    tdm_params_to_bclk_cases[i].slot_multiple)
20862306a36Sopenharmony_ci			continue;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci		test_snd_soc_params_to_bclk_one(test,
21162306a36Sopenharmony_ci						tdm_params_to_bclk_cases[i].rate,
21262306a36Sopenharmony_ci						tdm_params_to_bclk_cases[i].fmt,
21362306a36Sopenharmony_ci						tdm_params_to_bclk_cases[i].channels,
21462306a36Sopenharmony_ci						tdm_params_to_bclk_cases[i].bclk);
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic struct kunit_case soc_utils_test_cases[] = {
21962306a36Sopenharmony_ci	KUNIT_CASE(test_tdm_params_to_bclk),
22062306a36Sopenharmony_ci	KUNIT_CASE(test_snd_soc_params_to_bclk),
22162306a36Sopenharmony_ci	{}
22262306a36Sopenharmony_ci};
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic struct kunit_suite soc_utils_test_suite = {
22562306a36Sopenharmony_ci	.name = "soc-utils",
22662306a36Sopenharmony_ci	.test_cases = soc_utils_test_cases,
22762306a36Sopenharmony_ci};
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cikunit_test_suites(&soc_utils_test_suite);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC soc-utils kunit test");
23262306a36Sopenharmony_ciMODULE_LICENSE("GPL");
233