ASoC: soc-utils: Add kunit test for snd_soc_tdm_params_to_bclk()

Create a new kunit test for soc-utils and use it to test
snd_soc_tdm_params_to_bclk().

The test uses a table of values to avoid the possibility that an
on-the-fly generator contains the same algorithmic error as the
function-under-test and so fails to detect a bug.

There is no need to test every possible combination of values.
Enough test cases are included to give confidence that the function
is producing the correct results.

Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20220405135419.1230088-4-rf@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Richard Fitzgerald 2022-04-05 14:54:17 +01:00 committed by Mark Brown
parent 1ef34dd2b9
commit 89342fa38b
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
3 changed files with 199 additions and 1 deletions

View File

@ -14,7 +14,7 @@ menuconfig SND_SOC
If you want ASoC support, you should say Y here and also to the
specific driver for your SoC platform below.
ASoC provides power efficient ALSA support for embedded battery powered
SoC based systems like PDA's, Phones and Personal Media Players.
@ -55,6 +55,13 @@ config SND_SOC_TOPOLOGY_KUNIT_TEST
userspace applications such as pulseaudio, to prevent unnecessary
problems.
config SND_SOC_UTILS_KUNIT_TEST
tristate "KUnit tests for SoC utils"
depends on KUNIT
default KUNIT_ALL_TESTS
help
If you want to perform tests on ALSA SoC utils library say Y here.
config SND_SOC_ACPI
tristate

View File

@ -12,6 +12,11 @@ ifneq ($(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST),)
obj-$(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST) := soc-topology-test.o
endif
ifneq ($(CONFIG_SND_SOC_UTILS_KUNIT_TEST),)
# snd-soc-test-objs := soc-utils-test.o
obj-$(CONFIG_SND_SOC_UTILS_KUNIT_TEST) := soc-utils-test.o
endif
ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
snd-soc-core-objs += soc-generic-dmaengine-pcm.o
endif

186
sound/soc/soc-utils-test.c Normal file
View File

@ -0,0 +1,186 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2022 Cirrus Logic, Inc. and
// Cirrus Logic International Semiconductor Ltd.
#include <kunit/test.h>
#include <linux/module.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <uapi/sound/asound.h>
static const struct {
u32 rate;
snd_pcm_format_t fmt;
u8 channels;
u8 tdm_width;
u8 tdm_slots;
u8 slot_multiple;
u32 bclk;
} tdm_params_to_bclk_cases[] = {
/* rate fmt channels tdm_width tdm_slots slot_multiple bclk */
/* From params only */
{ 8000, SNDRV_PCM_FORMAT_S16_LE, 1, 0, 0, 0, 128000 },
{ 8000, SNDRV_PCM_FORMAT_S16_LE, 2, 0, 0, 0, 256000 },
{ 8000, SNDRV_PCM_FORMAT_S24_LE, 1, 0, 0, 0, 192000 },
{ 8000, SNDRV_PCM_FORMAT_S24_LE, 2, 0, 0, 0, 384000 },
{ 8000, SNDRV_PCM_FORMAT_S32_LE, 1, 0, 0, 0, 256000 },
{ 8000, SNDRV_PCM_FORMAT_S32_LE, 2, 0, 0, 0, 512000 },
{ 44100, SNDRV_PCM_FORMAT_S16_LE, 1, 0, 0, 0, 705600 },
{ 44100, SNDRV_PCM_FORMAT_S16_LE, 2, 0, 0, 0, 1411200 },
{ 44100, SNDRV_PCM_FORMAT_S24_LE, 1, 0, 0, 0, 1058400 },
{ 44100, SNDRV_PCM_FORMAT_S24_LE, 2, 0, 0, 0, 2116800 },
{ 44100, SNDRV_PCM_FORMAT_S32_LE, 1, 0, 0, 0, 1411200 },
{ 44100, SNDRV_PCM_FORMAT_S32_LE, 2, 0, 0, 0, 2822400 },
{ 384000, SNDRV_PCM_FORMAT_S16_LE, 1, 0, 0, 0, 6144000 },
{ 384000, SNDRV_PCM_FORMAT_S16_LE, 2, 0, 0, 0, 12288000 },
{ 384000, SNDRV_PCM_FORMAT_S24_LE, 1, 0, 0, 0, 9216000 },
{ 384000, SNDRV_PCM_FORMAT_S24_LE, 2, 0, 0, 0, 18432000 },
{ 384000, SNDRV_PCM_FORMAT_S32_LE, 1, 0, 0, 0, 12288000 },
{ 384000, SNDRV_PCM_FORMAT_S32_LE, 2, 0, 0, 0, 24576000 },
/* I2S from params */
{ 8000, SNDRV_PCM_FORMAT_S16_LE, 1, 0, 0, 2, 256000 },
{ 8000, SNDRV_PCM_FORMAT_S16_LE, 2, 0, 0, 2, 256000 },
{ 8000, SNDRV_PCM_FORMAT_S24_LE, 1, 0, 0, 2, 384000 },
{ 8000, SNDRV_PCM_FORMAT_S24_LE, 2, 0, 0, 2, 384000 },
{ 8000, SNDRV_PCM_FORMAT_S32_LE, 1, 0, 0, 2, 512000 },
{ 8000, SNDRV_PCM_FORMAT_S32_LE, 2, 0, 0, 2, 512000 },
{ 44100, SNDRV_PCM_FORMAT_S16_LE, 1, 0, 0, 2, 1411200 },
{ 44100, SNDRV_PCM_FORMAT_S16_LE, 2, 0, 0, 2, 1411200 },
{ 44100, SNDRV_PCM_FORMAT_S24_LE, 1, 0, 0, 2, 2116800 },
{ 44100, SNDRV_PCM_FORMAT_S24_LE, 2, 0, 0, 2, 2116800 },
{ 44100, SNDRV_PCM_FORMAT_S32_LE, 1, 0, 0, 2, 2822400 },
{ 44100, SNDRV_PCM_FORMAT_S32_LE, 2, 0, 0, 2, 2822400 },
{ 384000, SNDRV_PCM_FORMAT_S16_LE, 1, 0, 0, 2, 12288000 },
{ 384000, SNDRV_PCM_FORMAT_S16_LE, 2, 0, 0, 2, 12288000 },
{ 384000, SNDRV_PCM_FORMAT_S24_LE, 1, 0, 0, 2, 18432000 },
{ 384000, SNDRV_PCM_FORMAT_S24_LE, 2, 0, 0, 2, 18432000 },
{ 384000, SNDRV_PCM_FORMAT_S32_LE, 1, 0, 0, 2, 24576000 },
{ 384000, SNDRV_PCM_FORMAT_S32_LE, 2, 0, 0, 2, 24576000 },
/* Fixed 8-slot TDM, other values from params */
{ 8000, SNDRV_PCM_FORMAT_S16_LE, 1, 0, 8, 0, 1024000 },
{ 8000, SNDRV_PCM_FORMAT_S16_LE, 2, 0, 8, 0, 1024000 },
{ 8000, SNDRV_PCM_FORMAT_S16_LE, 3, 0, 8, 0, 1024000 },
{ 8000, SNDRV_PCM_FORMAT_S16_LE, 4, 0, 8, 0, 1024000 },
{ 8000, SNDRV_PCM_FORMAT_S32_LE, 1, 0, 8, 0, 2048000 },
{ 8000, SNDRV_PCM_FORMAT_S32_LE, 2, 0, 8, 0, 2048000 },
{ 8000, SNDRV_PCM_FORMAT_S32_LE, 3, 0, 8, 0, 2048000 },
{ 8000, SNDRV_PCM_FORMAT_S32_LE, 4, 0, 8, 0, 2048000 },
{ 384000, SNDRV_PCM_FORMAT_S16_LE, 1, 0, 8, 0, 49152000 },
{ 384000, SNDRV_PCM_FORMAT_S16_LE, 2, 0, 8, 0, 49152000 },
{ 384000, SNDRV_PCM_FORMAT_S16_LE, 3, 0, 8, 0, 49152000 },
{ 384000, SNDRV_PCM_FORMAT_S16_LE, 4, 0, 8, 0, 49152000 },
{ 384000, SNDRV_PCM_FORMAT_S32_LE, 1, 0, 8, 0, 98304000 },
{ 384000, SNDRV_PCM_FORMAT_S32_LE, 2, 0, 8, 0, 98304000 },
{ 384000, SNDRV_PCM_FORMAT_S32_LE, 3, 0, 8, 0, 98304000 },
{ 384000, SNDRV_PCM_FORMAT_S32_LE, 4, 0, 8, 0, 98304000 },
/* Fixed 32-bit TDM, other values from params */
{ 8000, SNDRV_PCM_FORMAT_S16_LE, 1, 32, 0, 0, 256000 },
{ 8000, SNDRV_PCM_FORMAT_S16_LE, 2, 32, 0, 0, 512000 },
{ 8000, SNDRV_PCM_FORMAT_S16_LE, 3, 32, 0, 0, 768000 },
{ 8000, SNDRV_PCM_FORMAT_S16_LE, 4, 32, 0, 0, 1024000 },
{ 8000, SNDRV_PCM_FORMAT_S32_LE, 1, 32, 0, 0, 256000 },
{ 8000, SNDRV_PCM_FORMAT_S32_LE, 2, 32, 0, 0, 512000 },
{ 8000, SNDRV_PCM_FORMAT_S32_LE, 3, 32, 0, 0, 768000 },
{ 8000, SNDRV_PCM_FORMAT_S32_LE, 4, 32, 0, 0, 1024000 },
{ 384000, SNDRV_PCM_FORMAT_S16_LE, 1, 32, 0, 0, 12288000 },
{ 384000, SNDRV_PCM_FORMAT_S16_LE, 2, 32, 0, 0, 24576000 },
{ 384000, SNDRV_PCM_FORMAT_S16_LE, 3, 32, 0, 0, 36864000 },
{ 384000, SNDRV_PCM_FORMAT_S16_LE, 4, 32, 0, 0, 49152000 },
{ 384000, SNDRV_PCM_FORMAT_S32_LE, 1, 32, 0, 0, 12288000 },
{ 384000, SNDRV_PCM_FORMAT_S32_LE, 2, 32, 0, 0, 24576000 },
{ 384000, SNDRV_PCM_FORMAT_S32_LE, 3, 32, 0, 0, 36864000 },
{ 384000, SNDRV_PCM_FORMAT_S32_LE, 4, 32, 0, 0, 49152000 },
/* Fixed 6-slot 24-bit TDM, other values from params */
{ 8000, SNDRV_PCM_FORMAT_S16_LE, 1, 24, 6, 0, 1152000 },
{ 8000, SNDRV_PCM_FORMAT_S16_LE, 2, 24, 6, 0, 1152000 },
{ 8000, SNDRV_PCM_FORMAT_S16_LE, 3, 24, 6, 0, 1152000 },
{ 8000, SNDRV_PCM_FORMAT_S16_LE, 4, 24, 6, 0, 1152000 },
{ 8000, SNDRV_PCM_FORMAT_S24_LE, 1, 24, 6, 0, 1152000 },
{ 8000, SNDRV_PCM_FORMAT_S24_LE, 2, 24, 6, 0, 1152000 },
{ 8000, SNDRV_PCM_FORMAT_S24_LE, 3, 24, 6, 0, 1152000 },
{ 8000, SNDRV_PCM_FORMAT_S24_LE, 4, 24, 6, 0, 1152000 },
{ 192000, SNDRV_PCM_FORMAT_S16_LE, 1, 24, 6, 0, 27648000 },
{ 192000, SNDRV_PCM_FORMAT_S16_LE, 2, 24, 6, 0, 27648000 },
{ 192000, SNDRV_PCM_FORMAT_S16_LE, 3, 24, 6, 0, 27648000 },
{ 192000, SNDRV_PCM_FORMAT_S16_LE, 4, 24, 6, 0, 27648000 },
{ 192000, SNDRV_PCM_FORMAT_S24_LE, 1, 24, 6, 0, 27648000 },
{ 192000, SNDRV_PCM_FORMAT_S24_LE, 2, 24, 6, 0, 27648000 },
{ 192000, SNDRV_PCM_FORMAT_S24_LE, 3, 24, 6, 0, 27648000 },
{ 192000, SNDRV_PCM_FORMAT_S24_LE, 4, 24, 6, 0, 27648000 },
};
static void test_tdm_params_to_bclk_one(struct kunit *test,
unsigned int rate, snd_pcm_format_t fmt,
unsigned int channels,
unsigned int tdm_width, unsigned int tdm_slots,
unsigned int slot_multiple,
unsigned int expected_bclk)
{
struct snd_pcm_hw_params params;
int got_bclk;
_snd_pcm_hw_params_any(&params);
snd_mask_none(hw_param_mask(&params, SNDRV_PCM_HW_PARAM_FORMAT));
hw_param_interval(&params, SNDRV_PCM_HW_PARAM_RATE)->min = rate;
hw_param_interval(&params, SNDRV_PCM_HW_PARAM_RATE)->max = rate;
hw_param_interval(&params, SNDRV_PCM_HW_PARAM_CHANNELS)->min = channels;
hw_param_interval(&params, SNDRV_PCM_HW_PARAM_CHANNELS)->max = channels;
params_set_format(&params, fmt);
got_bclk = snd_soc_tdm_params_to_bclk(&params, tdm_width, tdm_slots, slot_multiple);
pr_debug("%s: r=%u sb=%u ch=%u tw=%u ts=%u sm=%u expected=%u got=%d\n",
__func__,
rate, params_width(&params), channels, tdm_width, tdm_slots, slot_multiple,
expected_bclk, got_bclk);
KUNIT_ASSERT_EQ(test, expected_bclk, (unsigned int)got_bclk);
}
static void test_tdm_params_to_bclk(struct kunit *test)
{
int i;
for (i = 0; i < ARRAY_SIZE(tdm_params_to_bclk_cases); ++i) {
test_tdm_params_to_bclk_one(test,
tdm_params_to_bclk_cases[i].rate,
tdm_params_to_bclk_cases[i].fmt,
tdm_params_to_bclk_cases[i].channels,
tdm_params_to_bclk_cases[i].tdm_width,
tdm_params_to_bclk_cases[i].tdm_slots,
tdm_params_to_bclk_cases[i].slot_multiple,
tdm_params_to_bclk_cases[i].bclk);
if (tdm_params_to_bclk_cases[i].slot_multiple > 0)
continue;
/* Slot multiple 1 should have the same effect as multiple 0 */
test_tdm_params_to_bclk_one(test,
tdm_params_to_bclk_cases[i].rate,
tdm_params_to_bclk_cases[i].fmt,
tdm_params_to_bclk_cases[i].channels,
tdm_params_to_bclk_cases[i].tdm_width,
tdm_params_to_bclk_cases[i].tdm_slots,
1,
tdm_params_to_bclk_cases[i].bclk);
}
}
static struct kunit_case soc_utils_test_cases[] = {
KUNIT_CASE(test_tdm_params_to_bclk),
{}
};
static struct kunit_suite soc_utils_test_suite = {
.name = "soc-utils",
.test_cases = soc_utils_test_cases,
};
kunit_test_suites(&soc_utils_test_suite);
MODULE_DESCRIPTION("ASoC soc-utils kunit test");
MODULE_LICENSE("GPL");