1 // SPDX-License-Identifier: GPL-2.0+ 2 // 3 // soc-util.c -- ALSA SoC Audio Layer utility functions 4 // 5 // Copyright 2009 Wolfson Microelectronics PLC. 6 // 7 // Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 8 // Liam Girdwood <lrg@slimlogic.co.uk> 9 10 #include <linux/device/faux.h> 11 #include <linux/export.h> 12 #include <linux/math.h> 13 #include <sound/core.h> 14 #include <sound/pcm.h> 15 #include <sound/pcm_params.h> 16 #include <sound/soc.h> 17 18 int snd_soc_ret(const struct device *dev, int ret, const char *fmt, ...) 19 { 20 struct va_format vaf; 21 va_list args; 22 23 /* Positive, Zero values are not errors */ 24 if (ret >= 0) 25 return ret; 26 27 /* Negative values might be errors */ 28 switch (ret) { 29 case -EPROBE_DEFER: 30 case -ENOTSUPP: 31 case -EOPNOTSUPP: 32 break; 33 default: 34 va_start(args, fmt); 35 vaf.fmt = fmt; 36 vaf.va = &args; 37 38 dev_err(dev, "ASoC error (%d): %pV", ret, &vaf); 39 va_end(args); 40 } 41 42 return ret; 43 } 44 EXPORT_SYMBOL_GPL(snd_soc_ret); 45 46 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots) 47 { 48 return sample_size * channels * tdm_slots; 49 } 50 EXPORT_SYMBOL_GPL(snd_soc_calc_frame_size); 51 52 int snd_soc_params_to_frame_size(const struct snd_pcm_hw_params *params) 53 { 54 int sample_size; 55 56 sample_size = snd_pcm_format_width(params_format(params)); 57 if (sample_size < 0) 58 return sample_size; 59 60 return snd_soc_calc_frame_size(sample_size, params_channels(params), 61 1); 62 } 63 EXPORT_SYMBOL_GPL(snd_soc_params_to_frame_size); 64 65 int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots) 66 { 67 return fs * snd_soc_calc_frame_size(sample_size, channels, tdm_slots); 68 } 69 EXPORT_SYMBOL_GPL(snd_soc_calc_bclk); 70 71 int snd_soc_params_to_bclk(const struct snd_pcm_hw_params *params) 72 { 73 int ret; 74 75 ret = snd_soc_params_to_frame_size(params); 76 77 if (ret > 0) 78 return ret * params_rate(params); 79 else 80 return ret; 81 } 82 EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk); 83 84 /** 85 * snd_soc_tdm_params_to_bclk - calculate bclk from params and tdm slot info. 86 * 87 * Calculate the bclk from the params sample rate, the tdm slot count and the 88 * tdm slot width. Optionally round-up the slot count to a given multiple. 89 * Either or both of tdm_width and tdm_slots can be 0. 90 * 91 * If tdm_width == 0: use params_width() as the slot width. 92 * If tdm_slots == 0: use params_channels() as the slot count. 93 * 94 * If slot_multiple > 1 the slot count (or params_channels() if tdm_slots == 0) 95 * will be rounded up to a multiple of slot_multiple. This is mainly useful for 96 * I2S mode, which has a left and right phase so the number of slots is always 97 * a multiple of 2. 98 * 99 * If tdm_width == 0 && tdm_slots == 0 && slot_multiple < 2, this is equivalent 100 * to calling snd_soc_params_to_bclk(). 101 * 102 * @params: Pointer to struct_pcm_hw_params. 103 * @tdm_width: Width in bits of the tdm slots. Must be >= 0. 104 * @tdm_slots: Number of tdm slots per frame. Must be >= 0. 105 * @slot_multiple: If >1 roundup slot count to a multiple of this value. 106 * 107 * Return: bclk frequency in Hz, else a negative error code if params format 108 * is invalid. 109 */ 110 int snd_soc_tdm_params_to_bclk(const struct snd_pcm_hw_params *params, 111 int tdm_width, int tdm_slots, int slot_multiple) 112 { 113 if (!tdm_slots) 114 tdm_slots = params_channels(params); 115 116 if (slot_multiple > 1) 117 tdm_slots = roundup(tdm_slots, slot_multiple); 118 119 if (!tdm_width) { 120 tdm_width = snd_pcm_format_width(params_format(params)); 121 if (tdm_width < 0) 122 return tdm_width; 123 } 124 125 return snd_soc_calc_bclk(params_rate(params), tdm_width, 1, tdm_slots); 126 } 127 EXPORT_SYMBOL_GPL(snd_soc_tdm_params_to_bclk); 128 129 static const struct snd_pcm_hardware dummy_dma_hardware = { 130 /* Random values to keep userspace happy when checking constraints */ 131 .info = SNDRV_PCM_INFO_INTERLEAVED | 132 SNDRV_PCM_INFO_BLOCK_TRANSFER, 133 .buffer_bytes_max = 128*1024, 134 .period_bytes_min = 4096, 135 .period_bytes_max = 4096*2, 136 .periods_min = 2, 137 .periods_max = 128, 138 }; 139 140 141 static const struct snd_soc_component_driver dummy_platform; 142 143 static int dummy_dma_open(struct snd_soc_component *component, 144 struct snd_pcm_substream *substream) 145 { 146 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 147 int i; 148 149 /* 150 * If there are other components associated with rtd, we shouldn't 151 * override their hwparams 152 */ 153 for_each_rtd_components(rtd, i, component) { 154 if (component->driver == &dummy_platform) 155 return 0; 156 } 157 158 /* BE's dont need dummy params */ 159 if (!rtd->dai_link->no_pcm) 160 snd_soc_set_runtime_hwparams(substream, &dummy_dma_hardware); 161 162 return 0; 163 } 164 165 static const struct snd_soc_component_driver dummy_platform = { 166 .open = dummy_dma_open, 167 }; 168 169 static const struct snd_soc_component_driver dummy_codec = { 170 .idle_bias_on = 1, 171 .use_pmdown_time = 1, 172 .endianness = 1, 173 }; 174 175 #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ 176 SNDRV_PCM_FMTBIT_U8 | \ 177 SNDRV_PCM_FMTBIT_S16_LE | \ 178 SNDRV_PCM_FMTBIT_U16_LE | \ 179 SNDRV_PCM_FMTBIT_S24_LE | \ 180 SNDRV_PCM_FMTBIT_S24_3LE | \ 181 SNDRV_PCM_FMTBIT_U24_LE | \ 182 SNDRV_PCM_FMTBIT_S32_LE | \ 183 SNDRV_PCM_FMTBIT_U32_LE | \ 184 SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) 185 186 static const u64 dummy_dai_formats = 187 SND_SOC_POSSIBLE_DAIFMT_I2S | 188 SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | 189 SND_SOC_POSSIBLE_DAIFMT_LEFT_J | 190 SND_SOC_POSSIBLE_DAIFMT_DSP_A | 191 SND_SOC_POSSIBLE_DAIFMT_DSP_B | 192 SND_SOC_POSSIBLE_DAIFMT_AC97 | 193 SND_SOC_POSSIBLE_DAIFMT_PDM | 194 SND_SOC_POSSIBLE_DAIFMT_GATED | 195 SND_SOC_POSSIBLE_DAIFMT_CONT | 196 SND_SOC_POSSIBLE_DAIFMT_NB_NF | 197 SND_SOC_POSSIBLE_DAIFMT_NB_IF | 198 SND_SOC_POSSIBLE_DAIFMT_IB_NF | 199 SND_SOC_POSSIBLE_DAIFMT_IB_IF; 200 201 static const struct snd_soc_dai_ops dummy_dai_ops = { 202 .auto_selectable_formats = &dummy_dai_formats, 203 .num_auto_selectable_formats = 1, 204 }; 205 206 /* 207 * The dummy CODEC is only meant to be used in situations where there is no 208 * actual hardware. 209 * 210 * If there is actual hardware even if it does not have a control bus 211 * the hardware will still have constraints like supported samplerates, etc. 212 * which should be modelled. And the data flow graph also should be modelled 213 * using DAPM. 214 */ 215 static struct snd_soc_dai_driver dummy_dai = { 216 .name = "snd-soc-dummy-dai", 217 .playback = { 218 .stream_name = "Playback", 219 .channels_min = 1, 220 .channels_max = 384, 221 .rates = SNDRV_PCM_RATE_CONTINUOUS, 222 .rate_min = 5512, 223 .rate_max = 768000, 224 .formats = STUB_FORMATS, 225 }, 226 .capture = { 227 .stream_name = "Capture", 228 .channels_min = 1, 229 .channels_max = 384, 230 .rates = SNDRV_PCM_RATE_CONTINUOUS, 231 .rate_min = 5512, 232 .rate_max = 768000, 233 .formats = STUB_FORMATS, 234 }, 235 .ops = &dummy_dai_ops, 236 }; 237 238 int snd_soc_dai_is_dummy(const struct snd_soc_dai *dai) 239 { 240 if (dai->driver == &dummy_dai) 241 return 1; 242 return 0; 243 } 244 EXPORT_SYMBOL_GPL(snd_soc_dai_is_dummy); 245 246 int snd_soc_component_is_dummy(struct snd_soc_component *component) 247 { 248 return ((component->driver == &dummy_platform) || 249 (component->driver == &dummy_codec)); 250 } 251 252 struct snd_soc_dai_link_component snd_soc_dummy_dlc = { 253 .of_node = NULL, 254 .dai_name = "snd-soc-dummy-dai", 255 .name = "snd-soc-dummy", 256 }; 257 EXPORT_SYMBOL_GPL(snd_soc_dummy_dlc); 258 259 int snd_soc_dlc_is_dummy(struct snd_soc_dai_link_component *dlc) 260 { 261 if (dlc == &snd_soc_dummy_dlc) 262 return true; 263 264 if ((dlc->name && strcmp(dlc->name, snd_soc_dummy_dlc.name) == 0) || 265 (dlc->dai_name && strcmp(dlc->dai_name, snd_soc_dummy_dlc.dai_name) == 0)) 266 return true; 267 268 return false; 269 } 270 EXPORT_SYMBOL_GPL(snd_soc_dlc_is_dummy); 271 272 static int snd_soc_dummy_probe(struct faux_device *fdev) 273 { 274 int ret; 275 276 ret = devm_snd_soc_register_component(&fdev->dev, 277 &dummy_codec, &dummy_dai, 1); 278 if (ret < 0) 279 return ret; 280 281 ret = devm_snd_soc_register_component(&fdev->dev, &dummy_platform, 282 NULL, 0); 283 284 return ret; 285 } 286 287 static struct faux_device_ops soc_dummy_ops = { 288 .probe = snd_soc_dummy_probe, 289 }; 290 291 static struct faux_device *soc_dummy_dev; 292 293 int __init snd_soc_util_init(void) 294 { 295 soc_dummy_dev = faux_device_create("snd-soc-dummy", NULL, 296 &soc_dummy_ops); 297 if (!soc_dummy_dev) 298 return -ENODEV; 299 300 return 0; 301 } 302 303 void snd_soc_util_exit(void) 304 { 305 faux_device_destroy(soc_dummy_dev); 306 } 307