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 const struct snd_soc_component_driver dummy_codec = { 266 .idle_bias_on = 1, 267 .use_pmdown_time = 1, 268 .endianness = 1, 269 .non_legacy_dai_naming = 1, 270 }; 271 272 #define STUB_RATES SNDRV_PCM_RATE_8000_192000 273 #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ 274 SNDRV_PCM_FMTBIT_U8 | \ 275 SNDRV_PCM_FMTBIT_S16_LE | \ 276 SNDRV_PCM_FMTBIT_U16_LE | \ 277 SNDRV_PCM_FMTBIT_S24_LE | \ 278 SNDRV_PCM_FMTBIT_U24_LE | \ 279 SNDRV_PCM_FMTBIT_S32_LE | \ 280 SNDRV_PCM_FMTBIT_U32_LE | \ 281 SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) 282 /* 283 * The dummy CODEC is only meant to be used in situations where there is no 284 * actual hardware. 285 * 286 * If there is actual hardware even if it does not have a control bus 287 * the hardware will still have constraints like supported samplerates, etc. 288 * which should be modelled. And the data flow graph also should be modelled 289 * using DAPM. 290 */ 291 static struct snd_soc_dai_driver dummy_dai = { 292 .name = "snd-soc-dummy-dai", 293 .playback = { 294 .stream_name = "Playback", 295 .channels_min = 1, 296 .channels_max = 384, 297 .rates = STUB_RATES, 298 .formats = STUB_FORMATS, 299 }, 300 .capture = { 301 .stream_name = "Capture", 302 .channels_min = 1, 303 .channels_max = 384, 304 .rates = STUB_RATES, 305 .formats = STUB_FORMATS, 306 }, 307 }; 308 309 int snd_soc_dai_is_dummy(struct snd_soc_dai *dai) 310 { 311 if (dai->driver == &dummy_dai) 312 return 1; 313 return 0; 314 } 315 316 static int snd_soc_dummy_probe(struct platform_device *pdev) 317 { 318 int ret; 319 320 ret = devm_snd_soc_register_component(&pdev->dev, 321 &dummy_codec, &dummy_dai, 1); 322 323 return ret; 324 } 325 326 static struct platform_driver soc_dummy_driver = { 327 .driver = { 328 .name = "snd-soc-dummy", 329 }, 330 .probe = snd_soc_dummy_probe, 331 }; 332 333 static struct platform_device *soc_dummy_dev; 334 335 int __init snd_soc_util_init(void) 336 { 337 int ret; 338 339 soc_dummy_dev = 340 platform_device_register_simple("snd-soc-dummy", -1, NULL, 0); 341 if (IS_ERR(soc_dummy_dev)) 342 return PTR_ERR(soc_dummy_dev); 343 344 ret = platform_driver_register(&soc_dummy_driver); 345 if (ret != 0) 346 platform_device_unregister(soc_dummy_dev); 347 348 return ret; 349 } 350 351 void __exit snd_soc_util_exit(void) 352 { 353 platform_driver_unregister(&soc_dummy_driver); 354 platform_device_unregister(soc_dummy_dev); 355 } 356