linux/sound/soc/soc-ops-test.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2// Copyright (C) 2025 Cirrus Logic, Inc. and
   3//                    Cirrus Logic International Semiconductor Ltd.
   4
   5#include <kunit/device.h>
   6#include <kunit/test.h>
   7#include <linux/module.h>
   8#include <linux/regmap.h>
   9#include <linux/string.h>
  10#include <sound/asound.h>
  11#include <sound/control.h>
  12#include <sound/soc.h>
  13#include <sound/soc-component.h>
  14
  15enum soc_ops_test_control_layout {
  16        SOC_OPS_TEST_SINGLE,
  17        SOC_OPS_TEST_DOUBLE,
  18        SOC_OPS_TEST_DOUBLE_R,
  19};
  20
  21#define TEST_MC(clayout, xmin, xmax, xpmax, xsign, xinvert) \
  22        .mc = { \
  23                .min = xmin, .max = xmax, .platform_max = xpmax, \
  24                .reg = 0, .shift = 0, .sign_bit = xsign, .invert = xinvert, \
  25                .rreg = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE_R ? 1 : 0, \
  26                .rshift = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE ? 16 : 0, \
  27        }
  28
  29#define TEST_UINFO(clayout, ctype, cmin, cmax) \
  30        .uinfo = { \
  31                .type = SNDRV_CTL_ELEM_TYPE_##ctype, \
  32                .count = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_SINGLE ? 1 : 2, \
  33                .value.integer.min = cmin, \
  34                .value.integer.max = cmax, \
  35        }
  36
  37#define ITEST(cname, clayout, ctype, cfunc, cmin, cmax, \
  38              xmin, xmax, xpmax, xsign, xinvert) \
  39        { \
  40                .name = cname, \
  41                .func_name = #cfunc, \
  42                .layout = SOC_OPS_TEST_##clayout, \
  43                .info = snd_soc_info_##cfunc, \
  44                TEST_MC(clayout, xmin, xmax, xpmax, xsign, xinvert), \
  45                TEST_UINFO(clayout, ctype, cmin, cmax), \
  46        }
  47
  48#define ATEST(clayout, cfunc, cctl, cret, cinit, \
  49              xmask, xreg, xmin, xmax, xpmax, xsign, xinvert) \
  50        { \
  51                .func_name = #cfunc, \
  52                .layout = SOC_OPS_TEST_##clayout, \
  53                .put = snd_soc_put_##cfunc, \
  54                .get = snd_soc_get_##cfunc, \
  55                TEST_MC(clayout, xmin, xmax, xpmax, xsign, xinvert), \
  56                .lctl = cctl, .rctl = cctl, \
  57                .lmask = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE ? \
  58                                (xmask) | (xmask) << 16 : (xmask), \
  59                .rmask = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE_R ? (xmask) : 0, \
  60                .init = cinit ? 0xFFFFFFFF : 0x00000000, \
  61                .lreg = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE ? \
  62                                (xreg) | (xreg) << 16 : (xreg), \
  63                .rreg = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE_R ? (xreg) : 0, \
  64                .ret = cret, \
  65        }
  66
  67struct soc_ops_test_priv {
  68        struct kunit *test;
  69
  70        struct snd_soc_component component;
  71};
  72
  73struct info_test_param {
  74        const char * const name;
  75        const char * const func_name;
  76        enum soc_ops_test_control_layout layout;
  77        struct soc_mixer_control mc;
  78        int (*info)(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *info);
  79
  80        struct snd_ctl_elem_info uinfo;
  81};
  82
  83struct access_test_param {
  84        const char * const func_name;
  85        enum soc_ops_test_control_layout layout;
  86        struct soc_mixer_control mc;
  87        int (*put)(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *value);
  88        int (*get)(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *value);
  89
  90        unsigned int init;
  91        unsigned int lmask;
  92        unsigned int rmask;
  93        unsigned int lreg;
  94        unsigned int rreg;
  95        long lctl;
  96        long rctl;
  97        int ret;
  98};
  99
 100static const struct info_test_param all_info_test_params[] = {
 101        // Handling of volume control name for types
 102        ITEST("Test Control",        SINGLE,   BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 0),
 103        ITEST("Test Volume",         SINGLE,   INTEGER, volsw,    0,  1,   0,  1,  0, 0, 0),
 104        ITEST("Test Volume Control", SINGLE,   BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 0),
 105        ITEST("Test Control",        DOUBLE_R, BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 0),
 106        ITEST("Test Volume",         DOUBLE_R, INTEGER, volsw,    0,  1,   0,  1,  0, 0, 0),
 107        ITEST("Test Volume Control", DOUBLE_R, BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 0),
 108        ITEST("Test Control",        DOUBLE,   BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 0),
 109        ITEST("Test Volume",         DOUBLE,   INTEGER, volsw,    0,  1,   0,  1,  0, 0, 0),
 110        ITEST("Test Volume Control", DOUBLE,   BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 0),
 111        ITEST("Test Control",        SINGLE,   BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 1),
 112        ITEST("Test Volume",         SINGLE,   INTEGER, volsw,    0,  1,   0,  1,  0, 0, 1),
 113        ITEST("Test Volume Control", SINGLE,   BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 1),
 114        ITEST("Test Control",        DOUBLE,   BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 1),
 115        ITEST("Test Volume",         DOUBLE,   INTEGER, volsw,    0,  1,   0,  1,  0, 0, 1),
 116        ITEST("Test Volume Control", DOUBLE,   BOOLEAN, volsw,    0,  1,   0,  1,  0, 0, 1),
 117        ITEST("Test Control",        SINGLE,   INTEGER, volsw,    0,  2,   0,  2,  0, 0, 0),
 118        ITEST("Test Volume",         SINGLE,   INTEGER, volsw,    0,  2,   0,  2,  0, 0, 0),
 119        ITEST("Test Volume Control", SINGLE,   INTEGER, volsw,    0,  2,   0,  2,  0, 0, 0),
 120        ITEST("Test Control",        SINGLE,   INTEGER, volsw,    0,  1,   0,  2,  1, 0, 0),
 121        ITEST("Test Volume",         SINGLE,   INTEGER, volsw,    0,  1,   0,  2,  1, 0, 0),
 122        ITEST("Test Volume Control", SINGLE,   INTEGER, volsw,    0,  1,   0,  2,  1, 0, 0),
 123        // Negative minimums
 124        ITEST("Test Control",        SINGLE,   INTEGER, volsw,    0, 20, -10, 10,  0, 4, 0),
 125        ITEST("Test Control",        SINGLE,   INTEGER, volsw,    0, 15, -10, 10, 15, 4, 0),
 126        ITEST("Test Control",        SINGLE,   INTEGER, volsw,    0, 20, -10, 10,  0, 4, 1),
 127        ITEST("Test Control",        SINGLE,   INTEGER, volsw,    0, 15, -10, 10, 15, 4, 1),
 128        // SX control volume control naming
 129        ITEST("Test Control",        SINGLE,   BOOLEAN, volsw_sx, 0,  1, 0xF,  1,  0, 0, 0),
 130        ITEST("Test Volume",         SINGLE,   INTEGER, volsw_sx, 0,  1, 0xF,  1,  0, 0, 0),
 131        ITEST("Test Volume Control", SINGLE,   BOOLEAN, volsw_sx, 0,  1, 0xF,  1,  0, 0, 0),
 132        ITEST("Test Control",        SINGLE,   INTEGER, volsw_sx, 0,  4, 0xE,  4,  0, 0, 0),
 133        ITEST("Test Volume",         SINGLE,   INTEGER, volsw_sx, 0,  4, 0xE,  4,  0, 0, 0),
 134        ITEST("Test Volume Control", SINGLE,   INTEGER, volsw_sx, 0,  4, 0xE,  4,  0, 0, 0),
 135        ITEST("Test Control",        SINGLE,   INTEGER, volsw_sx, 0,  3, 0xE,  4,  3, 0, 0),
 136        ITEST("Test Volume",         SINGLE,   INTEGER, volsw_sx, 0,  3, 0xE,  4,  3, 0, 0),
 137        ITEST("Test Volume Control", SINGLE,   INTEGER, volsw_sx, 0,  3, 0xE,  4,  3, 0, 0),
 138};
 139
 140static const struct access_test_param all_access_test_params[] = {
 141        // Single positive value controls
 142        ATEST(SINGLE,   volsw,     10,   1, false, 0x1F, 0x0A,    0,  20,  0, 0, 0),
 143        ATEST(SINGLE,   volsw,      0,   0, false, 0x1F, 0x00,    0,  20,  0, 0, 0),
 144        ATEST(SINGLE,   volsw,     20,   1, false, 0x1F, 0x14,    0,  20,  0, 0, 0),
 145        ATEST(SINGLE,   volsw,     10,   1, false, 0x1F, 0x0A,    0,  20, 15, 0, 0),
 146        ATEST(SINGLE,   volsw,     25, -22, false, 0x1F, 0x00,    0,  20, 15, 0, 0),
 147        ATEST(SINGLE,   volsw,     15,   1, false, 0x1F, 0x0F,    0,  20, 15, 0, 0),
 148        // Inverted single positive value controls
 149        ATEST(SINGLE,   volsw,     10,   1, false, 0x1F, 0x0A,    0,  20,  0, 0, 1),
 150        ATEST(SINGLE,   volsw,      0,   1, false, 0x1F, 0x14,    0,  20,  0, 0, 1),
 151        ATEST(SINGLE,   volsw,     20,   0, false, 0x1F, 0x00,    0,  20,  0, 0, 1),
 152        ATEST(SINGLE,   volsw,     10,   1, false, 0x1F, 0x0A,    0,  20, 15, 0, 1),
 153        ATEST(SINGLE,   volsw,     25, -22, false, 0x1F, 0x00,    0,  20, 15, 0, 1),
 154        ATEST(SINGLE,   volsw,     15,   1, false, 0x1F, 0x05,    0,  20, 15, 0, 1),
 155        ATEST(SINGLE,   volsw,     10,   1, true,  0x1F, 0x0A,    0,  20,  0, 0, 0),
 156        ATEST(SINGLE,   volsw,      0,   1, true,  0x1F, 0x00,    0,  20,  0, 0, 0),
 157        ATEST(SINGLE,   volsw,     20,   1, true,  0x1F, 0x14,    0,  20,  0, 0, 0),
 158        ATEST(SINGLE,   volsw,     10,   1, true,  0x1F, 0x0A,    0,  20, 15, 0, 0),
 159        ATEST(SINGLE,   volsw,     25, -22, true,  0x1F, 0x00,    0,  20, 15, 0, 0),
 160        ATEST(SINGLE,   volsw,     15,   1, true,  0x1F, 0x0F,    0,  20, 15, 0, 0),
 161        // Single negative value controls
 162        ATEST(SINGLE,   volsw,     10,   0, false, 0x1F, 0x00,  -10,  10,  0, 4, 0),
 163        ATEST(SINGLE,   volsw,      0,   1, false, 0x1F, 0x16,  -10,  10,  0, 4, 0),
 164        ATEST(SINGLE,   volsw,     20,   1, false, 0x1F, 0x0A,  -10,  10,  0, 4, 0),
 165        ATEST(SINGLE,   volsw,     10,   0, false, 0x1F, 0x00,  -10,  10, 15, 4, 0),
 166        ATEST(SINGLE,   volsw,     25, -22, false, 0x1F, 0x00,  -10,  10, 15, 4, 0),
 167        ATEST(SINGLE,   volsw,     15,   1, false, 0x1F, 0x05,  -10,  10, 15, 4, 0),
 168        // Single non-zero minimum positive value controls
 169        ATEST(SINGLE,   volsw,     10,   1, false, 0x1F, 0x14,   10,  30,  0, 0, 0),
 170        ATEST(SINGLE,   volsw,      0,   1, false, 0x1F, 0x0A,   10,  30,  0, 0, 0),
 171        ATEST(SINGLE,   volsw,     20,   1, false, 0x1F, 0x1E,   10,  30,  0, 0, 0),
 172        ATEST(SINGLE,   volsw,     10,   1, false, 0x1F, 0x14,   10,  30, 15, 0, 0),
 173        ATEST(SINGLE,   volsw,     25, -22, false, 0x1F, 0x00,   10,  30, 15, 0, 0),
 174        ATEST(SINGLE,   volsw,     15,   1, false, 0x1F, 0x19,   10,  30, 15, 0, 0),
 175        // Inverted single non-zero minimum positive value controls
 176        ATEST(SINGLE,   volsw,     10,   1, false, 0x1F, 0x14,   10,  30,  0, 0, 1),
 177        ATEST(SINGLE,   volsw,      0,   1, false, 0x1F, 0x1E,   10,  30,  0, 0, 1),
 178        ATEST(SINGLE,   volsw,     20,   1, false, 0x1F, 0x0A,   10,  30,  0, 0, 1),
 179        ATEST(SINGLE,   volsw,     10,   1, false, 0x1F, 0x14,   10,  30, 15, 0, 1),
 180        ATEST(SINGLE,   volsw,     25, -22, false, 0x1F, 0x00,   10,  30, 15, 0, 1),
 181        ATEST(SINGLE,   volsw,     15,   1, false, 0x1F, 0x0F,   10,  30, 15, 0, 1),
 182        // Double register positive value controls
 183        ATEST(DOUBLE_R, volsw,     10,   1, false, 0x1F, 0x0A,    0,  20,  0, 0, 0),
 184        ATEST(DOUBLE_R, volsw,      0,   0, false, 0x1F, 0x00,    0,  20,  0, 0, 0),
 185        ATEST(DOUBLE_R, volsw,     20,   1, false, 0x1F, 0x14,    0,  20,  0, 0, 0),
 186        ATEST(DOUBLE_R, volsw,     10,   1, false, 0x1F, 0x0A,    0,  20, 15, 0, 0),
 187        ATEST(DOUBLE_R, volsw,     25, -22, false, 0x1F, 0x00,    0,  20, 15, 0, 0),
 188        ATEST(DOUBLE_R, volsw,     15,   1, false, 0x1F, 0x0F,    0,  20, 15, 0, 0),
 189        // Double register negative value controls
 190        ATEST(DOUBLE_R, volsw,     10,   0, false, 0x1F, 0x00,  -10,  10,  0, 4, 0),
 191        ATEST(DOUBLE_R, volsw,      0,   1, false, 0x1F, 0x16,  -10,  10,  0, 4, 0),
 192        ATEST(DOUBLE_R, volsw,     20,   1, false, 0x1F, 0x0A,  -10,  10,  0, 4, 0),
 193        ATEST(DOUBLE_R, volsw,     10,   0, false, 0x1F, 0x00,  -10,  10, 15, 4, 0),
 194        ATEST(DOUBLE_R, volsw,     25, -22, false, 0x1F, 0x00,  -10,  10, 15, 4, 0),
 195        ATEST(DOUBLE_R, volsw,     15,   1, false, 0x1F, 0x05,  -10,  10, 15, 4, 0),
 196        ATEST(DOUBLE_R, volsw,     10,   1, true,  0x1F, 0x00,  -10,  10,  0, 4, 0),
 197        ATEST(DOUBLE_R, volsw,      0,   1, true,  0x1F, 0x16,  -10,  10,  0, 4, 0),
 198        ATEST(DOUBLE_R, volsw,     20,   1, true,  0x1F, 0x0A,  -10,  10,  0, 4, 0),
 199        ATEST(DOUBLE_R, volsw,     10,   1, true,  0x1F, 0x00,  -10,  10, 15, 4, 0),
 200        ATEST(DOUBLE_R, volsw,     25, -22, true,  0x1F, 0x00,  -10,  10, 15, 4, 0),
 201        ATEST(DOUBLE_R, volsw,     15,   1, true,  0x1F, 0x05,  -10,  10, 15, 4, 0),
 202        // Inverted double register negative value controls
 203        ATEST(DOUBLE_R, volsw,     10,   1, true,  0x1F, 0x00,  -10,  10,  0, 4, 1),
 204        ATEST(DOUBLE_R, volsw,      0,   1, true,  0x1F, 0x0A,  -10,  10,  0, 4, 1),
 205        ATEST(DOUBLE_R, volsw,     20,   1, true,  0x1F, 0x16,  -10,  10,  0, 4, 1),
 206        ATEST(DOUBLE_R, volsw,     10,   1, true,  0x1F, 0x00,  -10,  10, 15, 4, 1),
 207        ATEST(DOUBLE_R, volsw,     25, -22, true,  0x1F, 0x00,  -10,  10, 15, 4, 1),
 208        ATEST(DOUBLE_R, volsw,     15,   1, true,  0x1F, 0x1B,  -10,  10, 15, 4, 1),
 209        // Double register non-zero minimum positive value controls
 210        ATEST(DOUBLE_R, volsw,     10,   1, false, 0x1F, 0x14,   10,  30,  0, 0, 0),
 211        ATEST(DOUBLE_R, volsw,      0,   1, false, 0x1F, 0x0A,   10,  30,  0, 0, 0),
 212        ATEST(DOUBLE_R, volsw,     20,   1, false, 0x1F, 0x1E,   10,  30,  0, 0, 0),
 213        ATEST(DOUBLE_R, volsw,     10,   1, false, 0x1F, 0x14,   10,  30, 15, 0, 0),
 214        ATEST(DOUBLE_R, volsw,     25, -22, false, 0x1F, 0x00,   10,  30, 15, 0, 0),
 215        ATEST(DOUBLE_R, volsw,     15,   1, false, 0x1F, 0x19,   10,  30, 15, 0, 0),
 216        // Double shift positive value controls
 217        ATEST(DOUBLE,   volsw,     10,   1, false, 0x1F, 0x0A,    0,  20,  0, 0, 0),
 218        ATEST(DOUBLE,   volsw,      0,   0, false, 0x1F, 0x00,    0,  20,  0, 0, 0),
 219        ATEST(DOUBLE,   volsw,     20,   1, false, 0x1F, 0x14,    0,  20,  0, 0, 0),
 220        ATEST(DOUBLE,   volsw,     10,   1, false, 0x1F, 0x0A,    0,  20, 15, 0, 0),
 221        ATEST(DOUBLE,   volsw,     25, -22, false, 0x1F, 0x00,    0,  20, 15, 0, 0),
 222        ATEST(DOUBLE,   volsw,     15,   1, false, 0x1F, 0x0F,    0,  20, 15, 0, 0),
 223        // Double shift negative value controls
 224        ATEST(DOUBLE,   volsw,     10,   0, false, 0x1F, 0x00,  -10,  10,  0, 4, 0),
 225        ATEST(DOUBLE,   volsw,      0,   1, false, 0x1F, 0x16,  -10,  10,  0, 4, 0),
 226        ATEST(DOUBLE,   volsw,     20,   1, false, 0x1F, 0x0A,  -10,  10,  0, 4, 0),
 227        ATEST(DOUBLE,   volsw,     10,   0, false, 0x1F, 0x00,  -10,  10, 15, 4, 0),
 228        ATEST(DOUBLE,   volsw,     25, -22, false, 0x1F, 0x00,  -10,  10, 15, 4, 0),
 229        ATEST(DOUBLE,   volsw,     15,   1, false, 0x1F, 0x05,  -10,  10, 15, 4, 0),
 230        // Inverted double shift negative value controls
 231        ATEST(DOUBLE,   volsw,     10,   0, false, 0x1F, 0x00,  -10,  10,  0, 4, 1),
 232        ATEST(DOUBLE,   volsw,      0,   1, false, 0x1F, 0x0A,  -10,  10,  0, 4, 1),
 233        ATEST(DOUBLE,   volsw,     20,   1, false, 0x1F, 0x16,  -10,  10,  0, 4, 1),
 234        ATEST(DOUBLE,   volsw,     10,   0, false, 0x1F, 0x00,  -10,  10, 15, 4, 1),
 235        ATEST(DOUBLE,   volsw,     25, -22, false, 0x1F, 0x00,  -10,  10, 15, 4, 1),
 236        ATEST(DOUBLE,   volsw,     15,   1, false, 0x1F, 0x1B,  -10,  10, 15, 4, 1),
 237        // Double shift non-zero minimum positive value controls
 238        ATEST(DOUBLE,   volsw,     10,   1, false, 0x1F, 0x14,   10,  30,  0, 0, 0),
 239        ATEST(DOUBLE,   volsw,      0,   1, false, 0x1F, 0x0A,   10,  30,  0, 0, 0),
 240        ATEST(DOUBLE,   volsw,     20,   1, false, 0x1F, 0x1E,   10,  30,  0, 0, 0),
 241        ATEST(DOUBLE,   volsw,     10,   1, false, 0x1F, 0x14,   10,  30, 15, 0, 0),
 242        ATEST(DOUBLE,   volsw,     25, -22, false, 0x1F, 0x00,   10,  30, 15, 0, 0),
 243        ATEST(DOUBLE,   volsw,     15,   1, false, 0x1F, 0x19,   10,  30, 15, 0, 0),
 244        ATEST(DOUBLE,   volsw,     10,   1, true,  0x1F, 0x14,   10,  30,  0, 0, 0),
 245        ATEST(DOUBLE,   volsw,      0,   1, true,  0x1F, 0x0A,   10,  30,  0, 0, 0),
 246        ATEST(DOUBLE,   volsw,     20,   1, true,  0x1F, 0x1E,   10,  30,  0, 0, 0),
 247        ATEST(DOUBLE,   volsw,     10,   1, true,  0x1F, 0x14,   10,  30, 15, 0, 0),
 248        ATEST(DOUBLE,   volsw,     25, -22, true,  0x1F, 0x00,   10,  30, 15, 0, 0),
 249        ATEST(DOUBLE,   volsw,     15,   1, true,  0x1F, 0x19,   10,  30, 15, 0, 0),
 250        // Single SX all values
 251        ATEST(SINGLE,   volsw_sx,   0,   1, false,  0xF, 0x0F, 0x0F,   4,  0, 0, 0),
 252        ATEST(SINGLE,   volsw_sx,   1,   0, false,  0xF, 0x00, 0x0F,   4,  0, 0, 0),
 253        ATEST(SINGLE,   volsw_sx,   2,   1, false,  0xF, 0x01, 0x0F,   4,  0, 0, 0),
 254        ATEST(SINGLE,   volsw_sx,   3,   1, false,  0xF, 0x02, 0x0F,   4,  0, 0, 0),
 255        ATEST(SINGLE,   volsw_sx,   4,   1, false,  0xF, 0x03, 0x0F,   4,  0, 0, 0),
 256        ATEST(SINGLE,   volsw_sx,   5, -22, false,  0xF, 0x00, 0x0F,   4,  0, 0, 0),
 257        ATEST(SINGLE,   volsw_sx,   0,   0, true,   0xF, 0x0F, 0x0F,   4,  0, 0, 0),
 258        ATEST(SINGLE,   volsw_sx,   1,   1, true,   0xF, 0x00, 0x0F,   4,  0, 0, 0),
 259        ATEST(SINGLE,   volsw_sx,   2,   1, true,   0xF, 0x01, 0x0F,   4,  0, 0, 0),
 260        ATEST(SINGLE,   volsw_sx,   3,   1, true,   0xF, 0x02, 0x0F,   4,  0, 0, 0),
 261        ATEST(SINGLE,   volsw_sx,   4,   1, true,   0xF, 0x03, 0x0F,   4,  0, 0, 0),
 262        ATEST(SINGLE,   volsw_sx,   5, -22, true,   0xF, 0x00, 0x0F,   4,  0, 0, 0),
 263        // Inverted single SX all values
 264        ATEST(SINGLE,   volsw_sx,   0,   1, false, 0x1F, 0x03, 0x0F,   4,  0, 0, 1),
 265        ATEST(SINGLE,   volsw_sx,   1,   1, false, 0x1F, 0x02, 0x0F,   4,  0, 0, 1),
 266        ATEST(SINGLE,   volsw_sx,   2,   1, false, 0x1F, 0x01, 0x0F,   4,  0, 0, 1),
 267        ATEST(SINGLE,   volsw_sx,   3,   0, false, 0x1F, 0x00, 0x0F,   4,  0, 0, 1),
 268        ATEST(SINGLE,   volsw_sx,   4,   1, false, 0x1F, 0x0F, 0x0F,   4,  0, 0, 1),
 269        ATEST(SINGLE,   volsw_sx,   5, -22, false, 0x1F, 0x00, 0x0F,   4,  0, 0, 1),
 270        // Single SX select values
 271        ATEST(SINGLE,   volsw_sx,   0,   1, false, 0xFF, 0x88, 0x88, 144,  0, 0, 0),
 272        ATEST(SINGLE,   volsw_sx,   1,   1, false, 0xFF, 0x89, 0x88, 144,  0, 0, 0),
 273        ATEST(SINGLE,   volsw_sx, 119,   1, false, 0xFF, 0xFF, 0x88, 144,  0, 0, 0),
 274        ATEST(SINGLE,   volsw_sx, 120,   0, false, 0xFF, 0x00, 0x88, 144,  0, 0, 0),
 275        ATEST(SINGLE,   volsw_sx, 121,   1, false, 0xFF, 0x01, 0x88, 144,  0, 0, 0),
 276        ATEST(SINGLE,   volsw_sx, 143,   1, false, 0xFF, 0x17, 0x88, 144,  0, 0, 0),
 277        ATEST(SINGLE,   volsw_sx, 144,   1, false, 0xFF, 0x18, 0x88, 144,  0, 0, 0),
 278        ATEST(SINGLE,   volsw_sx, 145, -22, false, 0xFF, 0x00, 0x88, 144,  0, 0, 0),
 279        ATEST(SINGLE,   volsw_sx,   0,   1, true,  0xFF, 0x88, 0x88, 144,  0, 0, 0),
 280        ATEST(SINGLE,   volsw_sx,   1,   1, true,  0xFF, 0x89, 0x88, 144,  0, 0, 0),
 281        ATEST(SINGLE,   volsw_sx, 119,   0, true,  0xFF, 0xFF, 0x88, 144,  0, 0, 0),
 282        ATEST(SINGLE,   volsw_sx, 120,   1, true,  0xFF, 0x00, 0x88, 144,  0, 0, 0),
 283        ATEST(SINGLE,   volsw_sx, 121,   1, true,  0xFF, 0x01, 0x88, 144,  0, 0, 0),
 284        ATEST(SINGLE,   volsw_sx, 143,   1, true,  0xFF, 0x17, 0x88, 144,  0, 0, 0),
 285        ATEST(SINGLE,   volsw_sx, 144,   1, true,  0xFF, 0x18, 0x88, 144,  0, 0, 0),
 286        ATEST(SINGLE,   volsw_sx, 145, -22, true,  0xFF, 0x00, 0x88, 144,  0, 0, 0),
 287        // Double shift SX select values
 288        ATEST(DOUBLE,   volsw_sx,   0,   1, true,  0xFF, 0x88, 0x88, 144,  0, 0, 0),
 289        ATEST(DOUBLE,   volsw_sx,   1,   1, true,  0xFF, 0x89, 0x88, 144,  0, 0, 0),
 290        ATEST(DOUBLE,   volsw_sx, 119,   0, true,  0xFF, 0xFF, 0x88, 144,  0, 0, 0),
 291        ATEST(DOUBLE,   volsw_sx, 120,   1, true,  0xFF, 0x00, 0x88, 144,  0, 0, 0),
 292        ATEST(DOUBLE,   volsw_sx, 121,   1, true,  0xFF, 0x01, 0x88, 144,  0, 0, 0),
 293        ATEST(DOUBLE,   volsw_sx, 143,   1, true,  0xFF, 0x17, 0x88, 144,  0, 0, 0),
 294        ATEST(DOUBLE,   volsw_sx, 144,   1, true,  0xFF, 0x18, 0x88, 144,  0, 0, 0),
 295        ATEST(DOUBLE,   volsw_sx, 145, -22, true,  0xFF, 0x00, 0x88, 144,  0, 0, 0),
 296        // Double register SX select values
 297        ATEST(DOUBLE_R, volsw_sx,   0,   1, true,  0xFF, 0x88, 0x88, 144,  0, 0, 0),
 298        ATEST(DOUBLE_R, volsw_sx,   1,   1, true,  0xFF, 0x89, 0x88, 144,  0, 0, 0),
 299        ATEST(DOUBLE_R, volsw_sx, 119,   0, true,  0xFF, 0xFF, 0x88, 144,  0, 0, 0),
 300        ATEST(DOUBLE_R, volsw_sx, 120,   1, true,  0xFF, 0x00, 0x88, 144,  0, 0, 0),
 301        ATEST(DOUBLE_R, volsw_sx, 121,   1, true,  0xFF, 0x01, 0x88, 144,  0, 0, 0),
 302        ATEST(DOUBLE_R, volsw_sx, 143,   1, true,  0xFF, 0x17, 0x88, 144,  0, 0, 0),
 303        ATEST(DOUBLE_R, volsw_sx, 144,   1, true,  0xFF, 0x18, 0x88, 144,  0, 0, 0),
 304        ATEST(DOUBLE_R, volsw_sx, 145, -22, true,  0xFF, 0x00, 0x88, 144,  0, 0, 0),
 305};
 306
 307static const char *control_type_str(const snd_ctl_elem_type_t type)
 308{
 309        switch (type) {
 310        case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
 311                return "bool";
 312        case SNDRV_CTL_ELEM_TYPE_INTEGER:
 313                return "int";
 314        default:
 315                return "unknown";
 316        }
 317}
 318
 319static const char *control_layout_str(const enum soc_ops_test_control_layout layout)
 320{
 321        switch (layout) {
 322        case SOC_OPS_TEST_SINGLE:
 323                return "single";
 324        case SOC_OPS_TEST_DOUBLE:
 325                return "double";
 326        case SOC_OPS_TEST_DOUBLE_R:
 327                return "double_r";
 328        default:
 329                return "unknown";
 330        }
 331};
 332
 333static int mock_regmap_read(void *context, const void *reg_buf,
 334                            const size_t reg_size, void *val_buf,
 335                            size_t val_size)
 336{
 337        struct soc_ops_test_priv *priv = context;
 338
 339        KUNIT_FAIL(priv->test, "Unexpected bus read");
 340
 341        return -EIO;
 342}
 343
 344static int mock_regmap_gather_write(void *context,
 345                                    const void *reg_buf, size_t reg_size,
 346                                    const void *val_buf, size_t val_size)
 347{
 348        struct soc_ops_test_priv *priv = context;
 349
 350        KUNIT_FAIL(priv->test, "Unexpected bus gather_write");
 351
 352        return -EIO;
 353}
 354
 355static int mock_regmap_write(void *context, const void *val_buf,
 356                             size_t val_size)
 357{
 358        struct soc_ops_test_priv *priv = context;
 359
 360        KUNIT_FAIL(priv->test, "Unexpected bus write");
 361
 362        return -EIO;
 363}
 364
 365static const struct regmap_bus mock_regmap_bus = {
 366        .read = mock_regmap_read,
 367        .write = mock_regmap_write,
 368        .gather_write = mock_regmap_gather_write,
 369        .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
 370        .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
 371};
 372
 373static const struct regmap_config mock_regmap_config = {
 374        .reg_bits = 32,
 375        .val_bits = 32,
 376        .reg_format_endian = REGMAP_ENDIAN_NATIVE,
 377        .val_format_endian = REGMAP_ENDIAN_NATIVE,
 378        .max_register = 0x1,
 379        .cache_type = REGCACHE_FLAT,
 380};
 381
 382static int soc_ops_test_init(struct kunit *test)
 383{
 384        struct soc_ops_test_priv *priv;
 385        struct regmap *regmap;
 386        struct device *dev;
 387
 388        priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
 389        if (!priv)
 390                return -ENOMEM;
 391
 392        priv->test = test;
 393
 394        dev = kunit_device_register(test, "soc_ops_test_drv");
 395        if (IS_ERR(dev))
 396                return PTR_ERR(dev);
 397
 398        regmap = devm_regmap_init(dev, &mock_regmap_bus, priv, &mock_regmap_config);
 399        if (IS_ERR(regmap))
 400                return PTR_ERR(regmap);
 401
 402        /* No actual hardware, we just use the cache */
 403        regcache_cache_only(regmap, true);
 404
 405        priv->component.dev = dev;
 406        priv->component.regmap = regmap;
 407        mutex_init(&priv->component.io_mutex);
 408
 409        test->priv = priv;
 410
 411        return 0;
 412}
 413
 414static void soc_ops_test_exit(struct kunit *test)
 415{
 416        struct soc_ops_test_priv *priv = test->priv;
 417
 418        kunit_device_unregister(test, priv->component.dev);
 419}
 420
 421static void info_test_desc(const struct info_test_param *param, char *desc)
 422{
 423        snprintf(desc, KUNIT_PARAM_DESC_SIZE,
 424                 "%s %s %s: ctl range: %ld->%ld, reg range: %d->%d(%d), sign: %d, inv: %d",
 425                 control_layout_str(param->layout), param->func_name,
 426                 control_type_str(param->uinfo.type),
 427                 param->uinfo.value.integer.min, param->uinfo.value.integer.max,
 428                 param->mc.min, param->mc.max, param->mc.platform_max,
 429                 param->mc.sign_bit, param->mc.invert);
 430}
 431
 432static void soc_ops_test_info(struct kunit *test)
 433{
 434        struct soc_ops_test_priv *priv = test->priv;
 435        const struct info_test_param *param = test->param_value;
 436        const struct snd_ctl_elem_info *target = &param->uinfo;
 437        struct snd_ctl_elem_info result;
 438        struct snd_kcontrol kctl = {
 439                .private_data = &priv->component,
 440                .private_value = (unsigned long)&param->mc,
 441        };
 442        int ret;
 443
 444        strscpy(kctl.id.name, param->name, sizeof(kctl.id.name));
 445
 446        ret = param->info(&kctl, &result);
 447        KUNIT_ASSERT_FALSE(test, ret);
 448
 449        KUNIT_EXPECT_EQ(test, result.count, target->count);
 450        KUNIT_EXPECT_EQ(test, result.type, target->type);
 451        KUNIT_EXPECT_EQ(test, result.value.integer.min, target->value.integer.min);
 452        KUNIT_EXPECT_EQ(test, result.value.integer.max, target->value.integer.max);
 453}
 454
 455static void access_test_desc(const struct access_test_param *param, char *desc)
 456{
 457        if (param->ret < 0) {
 458                snprintf(desc, KUNIT_PARAM_DESC_SIZE,
 459                         "%s %s: %ld,%ld -> range: %d->%d(%d), sign: %d, inv: %d -> err: %d",
 460                         control_layout_str(param->layout), param->func_name,
 461                         param->lctl, param->rctl,
 462                         param->mc.min, param->mc.max, param->mc.platform_max,
 463                         param->mc.sign_bit, param->mc.invert,
 464                         param->ret);
 465        } else {
 466                snprintf(desc, KUNIT_PARAM_DESC_SIZE,
 467                         "%s %s: %ld,%ld -> range: %d->%d(%d), sign: %d, inv: %d -> %#x,%#x",
 468                         control_layout_str(param->layout), param->func_name,
 469                         param->lctl, param->rctl,
 470                         param->mc.min, param->mc.max, param->mc.platform_max,
 471                         param->mc.sign_bit, param->mc.invert,
 472                         param->lreg, param->rreg);
 473        }
 474}
 475
 476static void soc_ops_test_access(struct kunit *test)
 477{
 478        struct soc_ops_test_priv *priv = test->priv;
 479        const struct access_test_param *param = test->param_value;
 480        struct snd_kcontrol kctl = {
 481                .private_data = &priv->component,
 482                .private_value = (unsigned long)&param->mc,
 483        };
 484        unsigned int val;
 485        int ret;
 486        /* it is too large struct. use kzalloc() */
 487        struct snd_ctl_elem_value *result;
 488
 489        result = kzalloc(sizeof(*result), GFP_KERNEL);
 490        if (!result)
 491                return;
 492
 493        ret = regmap_write(priv->component.regmap, 0x0, param->init);
 494        KUNIT_ASSERT_FALSE(test, ret);
 495        ret = regmap_write(priv->component.regmap, 0x1, param->init);
 496        KUNIT_ASSERT_FALSE(test, ret);
 497
 498        result->value.integer.value[0] = param->lctl;
 499        result->value.integer.value[1] = param->rctl;
 500
 501        ret = param->put(&kctl, result);
 502        KUNIT_ASSERT_EQ(test, ret, param->ret);
 503        if (ret < 0)
 504                goto end;
 505
 506        ret = regmap_read(priv->component.regmap, 0x0, &val);
 507        KUNIT_ASSERT_FALSE(test, ret);
 508        KUNIT_EXPECT_EQ(test, val, (param->init & ~param->lmask) | param->lreg);
 509
 510        ret = regmap_read(priv->component.regmap, 0x1, &val);
 511        KUNIT_ASSERT_FALSE(test, ret);
 512        KUNIT_EXPECT_EQ(test, val, (param->init & ~param->rmask) | param->rreg);
 513
 514        result->value.integer.value[0] = 0;
 515        result->value.integer.value[1] = 0;
 516
 517        ret = param->get(&kctl, result);
 518        KUNIT_ASSERT_GE(test, ret, 0);
 519
 520        KUNIT_EXPECT_EQ(test, result->value.integer.value[0], param->lctl);
 521        if (param->layout != SOC_OPS_TEST_SINGLE)
 522                KUNIT_EXPECT_EQ(test, result->value.integer.value[1], param->rctl);
 523        else
 524                KUNIT_EXPECT_EQ(test, result->value.integer.value[1], 0);
 525end:
 526        kfree(result);
 527}
 528
 529KUNIT_ARRAY_PARAM(all_info_tests, all_info_test_params, info_test_desc);
 530KUNIT_ARRAY_PARAM(all_access_tests, all_access_test_params, access_test_desc);
 531
 532static struct kunit_case soc_ops_test_cases[] = {
 533        KUNIT_CASE_PARAM(soc_ops_test_info, all_info_tests_gen_params),
 534        KUNIT_CASE_PARAM(soc_ops_test_access, all_access_tests_gen_params),
 535        {}
 536};
 537
 538static struct kunit_suite soc_ops_test_suite = {
 539        .name = "soc-ops",
 540        .init = soc_ops_test_init,
 541        .exit = soc_ops_test_exit,
 542        .test_cases = soc_ops_test_cases,
 543};
 544
 545kunit_test_suites(&soc_ops_test_suite);
 546
 547MODULE_DESCRIPTION("ASoC soc-ops kunit test");
 548MODULE_LICENSE("GPL");
 549