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/platform_device.h> 11 #include <linux/export.h> 12 #include <sound/core.h> 13 #include <sound/pcm.h> 14 #include <sound/pcm_params.h> 15 #include <sound/soc.h> 16 17 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots) 18 { 19 return sample_size * channels * tdm_slots; 20 } 21 EXPORT_SYMBOL_GPL(snd_soc_calc_frame_size); 22 23 int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params) 24 { 25 int sample_size; 26 27 sample_size = snd_pcm_format_width(params_format(params)); 28 if (sample_size < 0) 29 return sample_size; 30 31 return snd_soc_calc_frame_size(sample_size, params_channels(params), 32 1); 33 } 34 EXPORT_SYMBOL_GPL(snd_soc_params_to_frame_size); 35 36 int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots) 37 { 38 return fs * snd_soc_calc_frame_size(sample_size, channels, tdm_slots); 39 } 40 EXPORT_SYMBOL_GPL(snd_soc_calc_bclk); 41 42 int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params) 43 { 44 int ret; 45 46 ret = snd_soc_params_to_frame_size(params); 47 48 if (ret > 0) 49 return ret * params_rate(params); 50 else 51 return ret; 52 } 53 EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk); 54 55 int snd_soc_component_enable_pin(struct snd_soc_component *component, 56 const char *pin) 57 { 58 struct snd_soc_dapm_context *dapm = 59 snd_soc_component_get_dapm(component); 60 char *full_name; 61 int ret; 62 63 if (!component->name_prefix) 64 return snd_soc_dapm_enable_pin(dapm, pin); 65 66 full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); 67 if (!full_name) 68 return -ENOMEM; 69 70 ret = snd_soc_dapm_enable_pin(dapm, full_name); 71 kfree(full_name); 72 73 return ret; 74 } 75 EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin); 76 77 int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component, 78 const char *pin) 79 { 80 struct snd_soc_dapm_context *dapm = 81 snd_soc_component_get_dapm(component); 82 char *full_name; 83 int ret; 84 85 if (!component->name_prefix) 86 return snd_soc_dapm_enable_pin_unlocked(dapm, pin); 87 88 full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); 89 if (!full_name) 90 return -ENOMEM; 91 92 ret = snd_soc_dapm_enable_pin_unlocked(dapm, full_name); 93 kfree(full_name); 94 95 return ret; 96 } 97 EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin_unlocked); 98 99 int snd_soc_component_disable_pin(struct snd_soc_component *component, 100 const char *pin) 101 { 102 struct snd_soc_dapm_context *dapm = 103 snd_soc_component_get_dapm(component); 104 char *full_name; 105 int ret; 106 107 if (!component->name_prefix) 108 return snd_soc_dapm_disable_pin(dapm, pin); 109 110 full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); 111 if (!full_name) 112 return -ENOMEM; 113 114 ret = snd_soc_dapm_disable_pin(dapm, full_name); 115 kfree(full_name); 116 117 return ret; 118 } 119 EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin); 120 121 int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component, 122 const char *pin) 123 { 124 struct snd_soc_dapm_context *dapm = 125 snd_soc_component_get_dapm(component); 126 char *full_name; 127 int ret; 128 129 if (!component->name_prefix) 130 return snd_soc_dapm_disable_pin_unlocked(dapm, pin); 131 132 full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); 133 if (!full_name) 134 return -ENOMEM; 135 136 ret = snd_soc_dapm_disable_pin_unlocked(dapm, full_name); 137 kfree(full_name); 138 139 return ret; 140 } 141 EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin_unlocked); 142 143 int snd_soc_component_nc_pin(struct snd_soc_component *component, 144 const char *pin) 145 { 146 struct snd_soc_dapm_context *dapm = 147 snd_soc_component_get_dapm(component); 148 char *full_name; 149 int ret; 150 151 if (!component->name_prefix) 152 return snd_soc_dapm_nc_pin(dapm, pin); 153 154 full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); 155 if (!full_name) 156 return -ENOMEM; 157 158 ret = snd_soc_dapm_nc_pin(dapm, full_name); 159 kfree(full_name); 160 161 return ret; 162 } 163 EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin); 164 165 int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component, 166 const char *pin) 167 { 168 struct snd_soc_dapm_context *dapm = 169 snd_soc_component_get_dapm(component); 170 char *full_name; 171 int ret; 172 173 if (!component->name_prefix) 174 return snd_soc_dapm_nc_pin_unlocked(dapm, pin); 175 176 full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); 177 if (!full_name) 178 return -ENOMEM; 179 180 ret = snd_soc_dapm_nc_pin_unlocked(dapm, full_name); 181 kfree(full_name); 182 183 return ret; 184 } 185 EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin_unlocked); 186 187 int snd_soc_component_get_pin_status(struct snd_soc_component *component, 188 const char *pin) 189 { 190 struct snd_soc_dapm_context *dapm = 191 snd_soc_component_get_dapm(component); 192 char *full_name; 193 int ret; 194 195 if (!component->name_prefix) 196 return snd_soc_dapm_get_pin_status(dapm, pin); 197 198 full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); 199 if (!full_name) 200 return -ENOMEM; 201 202 ret = snd_soc_dapm_get_pin_status(dapm, full_name); 203 kfree(full_name); 204 205 return ret; 206 } 207 EXPORT_SYMBOL_GPL(snd_soc_component_get_pin_status); 208 209 int snd_soc_component_force_enable_pin(struct snd_soc_component *component, 210 const char *pin) 211 { 212 struct snd_soc_dapm_context *dapm = 213 snd_soc_component_get_dapm(component); 214 char *full_name; 215 int ret; 216 217 if (!component->name_prefix) 218 return snd_soc_dapm_force_enable_pin(dapm, pin); 219 220 full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); 221 if (!full_name) 222 return -ENOMEM; 223 224 ret = snd_soc_dapm_force_enable_pin(dapm, full_name); 225 kfree(full_name); 226 227 return ret; 228 } 229 EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin); 230 231 int snd_soc_component_force_enable_pin_unlocked( 232 struct snd_soc_component *component, 233 const char *pin) 234 { 235 struct snd_soc_dapm_context *dapm = 236 snd_soc_component_get_dapm(component); 237 char *full_name; 238 int ret; 239 240 if (!component->name_prefix) 241 return snd_soc_dapm_force_enable_pin_unlocked(dapm, pin); 242 243 full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); 244 if (!full_name) 245 return -ENOMEM; 246 247 ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, full_name); 248 kfree(full_name); 249 250 return ret; 251 } 252 EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin_unlocked); 253 254 static const struct snd_pcm_hardware dummy_dma_hardware = { 255 /* Random values to keep userspace happy when checking constraints */ 256 .info = SNDRV_PCM_INFO_INTERLEAVED | 257 SNDRV_PCM_INFO_BLOCK_TRANSFER, 258 .buffer_bytes_max = 128*1024, 259 .period_bytes_min = PAGE_SIZE, 260 .period_bytes_max = PAGE_SIZE*2, 261 .periods_min = 2, 262 .periods_max = 128, 263 }; 264 265 static int dummy_dma_open(struct snd_pcm_substream *substream) 266 { 267 struct snd_soc_pcm_runtime *rtd = substream->private_data; 268 269 /* BE's dont need dummy params */ 270 if (!rtd->dai_link->no_pcm) 271 snd_soc_set_runtime_hwparams(substream, &dummy_dma_hardware); 272 273 return 0; 274 } 275 276 static const struct snd_pcm_ops dummy_dma_ops = { 277 .open = dummy_dma_open, 278 .ioctl = snd_pcm_lib_ioctl, 279 }; 280 281 static const struct snd_soc_component_driver dummy_platform = { 282 .ops = &dummy_dma_ops, 283 }; 284 285 static const struct snd_soc_component_driver dummy_codec = { 286 .idle_bias_on = 1, 287 .use_pmdown_time = 1, 288 .endianness = 1, 289 .non_legacy_dai_naming = 1, 290 }; 291 292 #define STUB_RATES SNDRV_PCM_RATE_8000_192000 293 #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ 294 SNDRV_PCM_FMTBIT_U8 | \ 295 SNDRV_PCM_FMTBIT_S16_LE | \ 296 SNDRV_PCM_FMTBIT_U16_LE | \ 297 SNDRV_PCM_FMTBIT_S24_LE | \ 298 SNDRV_PCM_FMTBIT_U24_LE | \ 299 SNDRV_PCM_FMTBIT_S32_LE | \ 300 SNDRV_PCM_FMTBIT_U32_LE | \ 301 SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) 302 /* 303 * The dummy CODEC is only meant to be used in situations where there is no 304 * actual hardware. 305 * 306 * If there is actual hardware even if it does not have a control bus 307 * the hardware will still have constraints like supported samplerates, etc. 308 * which should be modelled. And the data flow graph also should be modelled 309 * using DAPM. 310 */ 311 static struct snd_soc_dai_driver dummy_dai = { 312 .name = "snd-soc-dummy-dai", 313 .playback = { 314 .stream_name = "Playback", 315 .channels_min = 1, 316 .channels_max = 384, 317 .rates = STUB_RATES, 318 .formats = STUB_FORMATS, 319 }, 320 .capture = { 321 .stream_name = "Capture", 322 .channels_min = 1, 323 .channels_max = 384, 324 .rates = STUB_RATES, 325 .formats = STUB_FORMATS, 326 }, 327 }; 328 329 int snd_soc_dai_is_dummy(struct snd_soc_dai *dai) 330 { 331 if (dai->driver == &dummy_dai) 332 return 1; 333 return 0; 334 } 335 336 static int snd_soc_dummy_probe(struct platform_device *pdev) 337 { 338 int ret; 339 340 ret = devm_snd_soc_register_component(&pdev->dev, 341 &dummy_codec, &dummy_dai, 1); 342 if (ret < 0) 343 return ret; 344 345 ret = devm_snd_soc_register_component(&pdev->dev, &dummy_platform, 346 NULL, 0); 347 348 return ret; 349 } 350 351 static struct platform_driver soc_dummy_driver = { 352 .driver = { 353 .name = "snd-soc-dummy", 354 }, 355 .probe = snd_soc_dummy_probe, 356 }; 357 358 static struct platform_device *soc_dummy_dev; 359 360 int __init snd_soc_util_init(void) 361 { 362 int ret; 363 364 soc_dummy_dev = 365 platform_device_register_simple("snd-soc-dummy", -1, NULL, 0); 366 if (IS_ERR(soc_dummy_dev)) 367 return PTR_ERR(soc_dummy_dev); 368 369 ret = platform_driver_register(&soc_dummy_driver); 370 if (ret != 0) 371 platform_device_unregister(soc_dummy_dev); 372 373 return ret; 374 } 375 376 void __exit snd_soc_util_exit(void) 377 { 378 platform_driver_unregister(&soc_dummy_driver); 379 platform_device_unregister(soc_dummy_dev); 380 } 381