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 /* 187 * Select these from Sound Card Manually 188 * SND_SOC_POSSIBLE_DAIFMT_CBP_CFP 189 * SND_SOC_POSSIBLE_DAIFMT_CBP_CFC 190 * SND_SOC_POSSIBLE_DAIFMT_CBC_CFP 191 * SND_SOC_POSSIBLE_DAIFMT_CBC_CFC 192 */ 193 static const u64 dummy_dai_formats = 194 SND_SOC_POSSIBLE_DAIFMT_I2S | 195 SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | 196 SND_SOC_POSSIBLE_DAIFMT_LEFT_J | 197 SND_SOC_POSSIBLE_DAIFMT_DSP_A | 198 SND_SOC_POSSIBLE_DAIFMT_DSP_B | 199 SND_SOC_POSSIBLE_DAIFMT_AC97 | 200 SND_SOC_POSSIBLE_DAIFMT_PDM | 201 SND_SOC_POSSIBLE_DAIFMT_GATED | 202 SND_SOC_POSSIBLE_DAIFMT_CONT | 203 SND_SOC_POSSIBLE_DAIFMT_NB_NF | 204 SND_SOC_POSSIBLE_DAIFMT_NB_IF | 205 SND_SOC_POSSIBLE_DAIFMT_IB_NF | 206 SND_SOC_POSSIBLE_DAIFMT_IB_IF; 207 208 static const struct snd_soc_dai_ops dummy_dai_ops = { 209 .auto_selectable_formats = &dummy_dai_formats, 210 .num_auto_selectable_formats = 1, 211 }; 212 213 /* 214 * The dummy CODEC is only meant to be used in situations where there is no 215 * actual hardware. 216 * 217 * If there is actual hardware even if it does not have a control bus 218 * the hardware will still have constraints like supported samplerates, etc. 219 * which should be modelled. And the data flow graph also should be modelled 220 * using DAPM. 221 */ 222 static struct snd_soc_dai_driver dummy_dai = { 223 .name = "snd-soc-dummy-dai", 224 .playback = { 225 .stream_name = "Playback", 226 .channels_min = 1, 227 .channels_max = 384, 228 .rates = SNDRV_PCM_RATE_CONTINUOUS, 229 .rate_min = 5512, 230 .rate_max = 768000, 231 .formats = STUB_FORMATS, 232 }, 233 .capture = { 234 .stream_name = "Capture", 235 .channels_min = 1, 236 .channels_max = 384, 237 .rates = SNDRV_PCM_RATE_CONTINUOUS, 238 .rate_min = 5512, 239 .rate_max = 768000, 240 .formats = STUB_FORMATS, 241 }, 242 .ops = &dummy_dai_ops, 243 }; 244 245 int snd_soc_dai_is_dummy(const struct snd_soc_dai *dai) 246 { 247 if (dai->driver == &dummy_dai) 248 return 1; 249 return 0; 250 } 251 EXPORT_SYMBOL_GPL(snd_soc_dai_is_dummy); 252 253 int snd_soc_component_is_dummy(struct snd_soc_component *component) 254 { 255 return ((component->driver == &dummy_platform) || 256 (component->driver == &dummy_codec)); 257 } 258 259 struct snd_soc_dai_link_component snd_soc_dummy_dlc = { 260 .of_node = NULL, 261 .dai_name = "snd-soc-dummy-dai", 262 .name = "snd-soc-dummy", 263 }; 264 EXPORT_SYMBOL_GPL(snd_soc_dummy_dlc); 265 266 int snd_soc_dlc_is_dummy(struct snd_soc_dai_link_component *dlc) 267 { 268 if (dlc == &snd_soc_dummy_dlc) 269 return true; 270 271 if ((dlc->name && strcmp(dlc->name, snd_soc_dummy_dlc.name) == 0) || 272 (dlc->dai_name && strcmp(dlc->dai_name, snd_soc_dummy_dlc.dai_name) == 0)) 273 return true; 274 275 return false; 276 } 277 EXPORT_SYMBOL_GPL(snd_soc_dlc_is_dummy); 278 279 static int snd_soc_dummy_probe(struct faux_device *fdev) 280 { 281 int ret; 282 283 ret = devm_snd_soc_register_component(&fdev->dev, 284 &dummy_codec, &dummy_dai, 1); 285 if (ret < 0) 286 return ret; 287 288 ret = devm_snd_soc_register_component(&fdev->dev, &dummy_platform, 289 NULL, 0); 290 291 return ret; 292 } 293 294 static struct faux_device_ops soc_dummy_ops = { 295 .probe = snd_soc_dummy_probe, 296 }; 297 298 static struct faux_device *soc_dummy_dev; 299 300 int __init snd_soc_util_init(void) 301 { 302 soc_dummy_dev = faux_device_create("snd-soc-dummy", NULL, 303 &soc_dummy_ops); 304 if (!soc_dummy_dev) 305 return -ENODEV; 306 307 return 0; 308 } 309 310 void snd_soc_util_exit(void) 311 { 312 faux_device_destroy(soc_dummy_dev); 313 } 314