18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// soc-util.c -- ALSA SoC Audio Layer utility functions 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright 2009 Wolfson Microelectronics PLC. 68c2ecf20Sopenharmony_ci// 78c2ecf20Sopenharmony_ci// Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 88c2ecf20Sopenharmony_ci// Liam Girdwood <lrg@slimlogic.co.uk> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 118c2ecf20Sopenharmony_ci#include <linux/export.h> 128c2ecf20Sopenharmony_ci#include <sound/core.h> 138c2ecf20Sopenharmony_ci#include <sound/pcm.h> 148c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 158c2ecf20Sopenharmony_ci#include <sound/soc.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ciint snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci return sample_size * channels * tdm_slots; 208c2ecf20Sopenharmony_ci} 218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_calc_frame_size); 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ciint snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci int sample_size; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci sample_size = snd_pcm_format_width(params_format(params)); 288c2ecf20Sopenharmony_ci if (sample_size < 0) 298c2ecf20Sopenharmony_ci return sample_size; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci return snd_soc_calc_frame_size(sample_size, params_channels(params), 328c2ecf20Sopenharmony_ci 1); 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_params_to_frame_size); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ciint snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci return fs * snd_soc_calc_frame_size(sample_size, channels, tdm_slots); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_calc_bclk); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ciint snd_soc_params_to_bclk(struct snd_pcm_hw_params *params) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci int ret; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci ret = snd_soc_params_to_frame_size(params); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (ret > 0) 498c2ecf20Sopenharmony_ci return ret * params_rate(params); 508c2ecf20Sopenharmony_ci else 518c2ecf20Sopenharmony_ci return ret; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_params_to_bclk); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware dummy_dma_hardware = { 568c2ecf20Sopenharmony_ci /* Random values to keep userspace happy when checking constraints */ 578c2ecf20Sopenharmony_ci .info = SNDRV_PCM_INFO_INTERLEAVED | 588c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER, 598c2ecf20Sopenharmony_ci .buffer_bytes_max = 128*1024, 608c2ecf20Sopenharmony_ci .period_bytes_min = PAGE_SIZE, 618c2ecf20Sopenharmony_ci .period_bytes_max = PAGE_SIZE*2, 628c2ecf20Sopenharmony_ci .periods_min = 2, 638c2ecf20Sopenharmony_ci .periods_max = 128, 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic int dummy_dma_open(struct snd_soc_component *component, 678c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* BE's dont need dummy params */ 728c2ecf20Sopenharmony_ci if (!rtd->dai_link->no_pcm) 738c2ecf20Sopenharmony_ci snd_soc_set_runtime_hwparams(substream, &dummy_dma_hardware); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci return 0; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver dummy_platform = { 798c2ecf20Sopenharmony_ci .open = dummy_dma_open, 808c2ecf20Sopenharmony_ci}; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver dummy_codec = { 838c2ecf20Sopenharmony_ci .idle_bias_on = 1, 848c2ecf20Sopenharmony_ci .use_pmdown_time = 1, 858c2ecf20Sopenharmony_ci .endianness = 1, 868c2ecf20Sopenharmony_ci .non_legacy_dai_naming = 1, 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci#define STUB_RATES SNDRV_PCM_RATE_8000_384000 908c2ecf20Sopenharmony_ci#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ 918c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U8 | \ 928c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S16_LE | \ 938c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U16_LE | \ 948c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | \ 958c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_3LE | \ 968c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U24_LE | \ 978c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE | \ 988c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U32_LE | \ 998c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) 1008c2ecf20Sopenharmony_ci/* 1018c2ecf20Sopenharmony_ci * The dummy CODEC is only meant to be used in situations where there is no 1028c2ecf20Sopenharmony_ci * actual hardware. 1038c2ecf20Sopenharmony_ci * 1048c2ecf20Sopenharmony_ci * If there is actual hardware even if it does not have a control bus 1058c2ecf20Sopenharmony_ci * the hardware will still have constraints like supported samplerates, etc. 1068c2ecf20Sopenharmony_ci * which should be modelled. And the data flow graph also should be modelled 1078c2ecf20Sopenharmony_ci * using DAPM. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver dummy_dai = { 1108c2ecf20Sopenharmony_ci .name = "snd-soc-dummy-dai", 1118c2ecf20Sopenharmony_ci .playback = { 1128c2ecf20Sopenharmony_ci .stream_name = "Playback", 1138c2ecf20Sopenharmony_ci .channels_min = 1, 1148c2ecf20Sopenharmony_ci .channels_max = 384, 1158c2ecf20Sopenharmony_ci .rates = STUB_RATES, 1168c2ecf20Sopenharmony_ci .formats = STUB_FORMATS, 1178c2ecf20Sopenharmony_ci }, 1188c2ecf20Sopenharmony_ci .capture = { 1198c2ecf20Sopenharmony_ci .stream_name = "Capture", 1208c2ecf20Sopenharmony_ci .channels_min = 1, 1218c2ecf20Sopenharmony_ci .channels_max = 384, 1228c2ecf20Sopenharmony_ci .rates = STUB_RATES, 1238c2ecf20Sopenharmony_ci .formats = STUB_FORMATS, 1248c2ecf20Sopenharmony_ci }, 1258c2ecf20Sopenharmony_ci}; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ciint snd_soc_dai_is_dummy(struct snd_soc_dai *dai) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci if (dai->driver == &dummy_dai) 1308c2ecf20Sopenharmony_ci return 1; 1318c2ecf20Sopenharmony_ci return 0; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic int snd_soc_dummy_probe(struct platform_device *pdev) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci int ret; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, 1398c2ecf20Sopenharmony_ci &dummy_codec, &dummy_dai, 1); 1408c2ecf20Sopenharmony_ci if (ret < 0) 1418c2ecf20Sopenharmony_ci return ret; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, &dummy_platform, 1448c2ecf20Sopenharmony_ci NULL, 0); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci return ret; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic struct platform_driver soc_dummy_driver = { 1508c2ecf20Sopenharmony_ci .driver = { 1518c2ecf20Sopenharmony_ci .name = "snd-soc-dummy", 1528c2ecf20Sopenharmony_ci }, 1538c2ecf20Sopenharmony_ci .probe = snd_soc_dummy_probe, 1548c2ecf20Sopenharmony_ci}; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic struct platform_device *soc_dummy_dev; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ciint __init snd_soc_util_init(void) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci int ret; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci soc_dummy_dev = 1638c2ecf20Sopenharmony_ci platform_device_register_simple("snd-soc-dummy", -1, NULL, 0); 1648c2ecf20Sopenharmony_ci if (IS_ERR(soc_dummy_dev)) 1658c2ecf20Sopenharmony_ci return PTR_ERR(soc_dummy_dev); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci ret = platform_driver_register(&soc_dummy_driver); 1688c2ecf20Sopenharmony_ci if (ret != 0) 1698c2ecf20Sopenharmony_ci platform_device_unregister(soc_dummy_dev); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci return ret; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_civoid snd_soc_util_exit(void) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci platform_driver_unregister(&soc_dummy_driver); 1778c2ecf20Sopenharmony_ci platform_device_unregister(soc_dummy_dev); 1788c2ecf20Sopenharmony_ci} 179