linux/sound/soc/soc-utils.c
<<
>>
Prefs
   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
  17int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots)
  18{
  19        return sample_size * channels * tdm_slots;
  20}
  21EXPORT_SYMBOL_GPL(snd_soc_calc_frame_size);
  22
  23int 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}
  34EXPORT_SYMBOL_GPL(snd_soc_params_to_frame_size);
  35
  36int 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}
  40EXPORT_SYMBOL_GPL(snd_soc_calc_bclk);
  41
  42int 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}
  53EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk);
  54
  55static const struct snd_pcm_hardware dummy_dma_hardware = {
  56        /* Random values to keep userspace happy when checking constraints */
  57        .info                   = SNDRV_PCM_INFO_INTERLEAVED |
  58                                  SNDRV_PCM_INFO_BLOCK_TRANSFER,
  59        .buffer_bytes_max       = 128*1024,
  60        .period_bytes_min       = PAGE_SIZE,
  61        .period_bytes_max       = PAGE_SIZE*2,
  62        .periods_min            = 2,
  63        .periods_max            = 128,
  64};
  65
  66static int dummy_dma_open(struct snd_soc_component *component,
  67                          struct snd_pcm_substream *substream)
  68{
  69        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  70
  71        /* BE's dont need dummy params */
  72        if (!rtd->dai_link->no_pcm)
  73                snd_soc_set_runtime_hwparams(substream, &dummy_dma_hardware);
  74
  75        return 0;
  76}
  77
  78static const struct snd_soc_component_driver dummy_platform = {
  79        .open           = dummy_dma_open,
  80};
  81
  82static const struct snd_soc_component_driver dummy_codec = {
  83        .idle_bias_on           = 1,
  84        .use_pmdown_time        = 1,
  85        .endianness             = 1,
  86        .non_legacy_dai_naming  = 1,
  87};
  88
  89#define STUB_RATES      SNDRV_PCM_RATE_8000_384000
  90#define STUB_FORMATS    (SNDRV_PCM_FMTBIT_S8 | \
  91                        SNDRV_PCM_FMTBIT_U8 | \
  92                        SNDRV_PCM_FMTBIT_S16_LE | \
  93                        SNDRV_PCM_FMTBIT_U16_LE | \
  94                        SNDRV_PCM_FMTBIT_S24_LE | \
  95                        SNDRV_PCM_FMTBIT_S24_3LE | \
  96                        SNDRV_PCM_FMTBIT_U24_LE | \
  97                        SNDRV_PCM_FMTBIT_S32_LE | \
  98                        SNDRV_PCM_FMTBIT_U32_LE | \
  99                        SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
 100
 101/*
 102 * Select these from Sound Card Manually
 103 *      SND_SOC_POSSIBLE_DAIFMT_CBP_CFP
 104 *      SND_SOC_POSSIBLE_DAIFMT_CBP_CFC
 105 *      SND_SOC_POSSIBLE_DAIFMT_CBC_CFP
 106 *      SND_SOC_POSSIBLE_DAIFMT_CBC_CFC
 107 */
 108static u64 dummy_dai_formats =
 109        SND_SOC_POSSIBLE_DAIFMT_I2S     |
 110        SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
 111        SND_SOC_POSSIBLE_DAIFMT_LEFT_J  |
 112        SND_SOC_POSSIBLE_DAIFMT_DSP_A   |
 113        SND_SOC_POSSIBLE_DAIFMT_DSP_B   |
 114        SND_SOC_POSSIBLE_DAIFMT_AC97    |
 115        SND_SOC_POSSIBLE_DAIFMT_PDM     |
 116        SND_SOC_POSSIBLE_DAIFMT_GATED   |
 117        SND_SOC_POSSIBLE_DAIFMT_CONT    |
 118        SND_SOC_POSSIBLE_DAIFMT_NB_NF   |
 119        SND_SOC_POSSIBLE_DAIFMT_NB_IF   |
 120        SND_SOC_POSSIBLE_DAIFMT_IB_NF   |
 121        SND_SOC_POSSIBLE_DAIFMT_IB_IF;
 122
 123static const struct snd_soc_dai_ops dummy_dai_ops = {
 124        .auto_selectable_formats        = &dummy_dai_formats,
 125        .num_auto_selectable_formats    = 1,
 126};
 127
 128/*
 129 * The dummy CODEC is only meant to be used in situations where there is no
 130 * actual hardware.
 131 *
 132 * If there is actual hardware even if it does not have a control bus
 133 * the hardware will still have constraints like supported samplerates, etc.
 134 * which should be modelled. And the data flow graph also should be modelled
 135 * using DAPM.
 136 */
 137static struct snd_soc_dai_driver dummy_dai = {
 138        .name = "snd-soc-dummy-dai",
 139        .playback = {
 140                .stream_name    = "Playback",
 141                .channels_min   = 1,
 142                .channels_max   = 384,
 143                .rates          = STUB_RATES,
 144                .formats        = STUB_FORMATS,
 145        },
 146        .capture = {
 147                .stream_name    = "Capture",
 148                .channels_min   = 1,
 149                .channels_max   = 384,
 150                .rates = STUB_RATES,
 151                .formats = STUB_FORMATS,
 152         },
 153        .ops = &dummy_dai_ops,
 154};
 155
 156int snd_soc_dai_is_dummy(struct snd_soc_dai *dai)
 157{
 158        if (dai->driver == &dummy_dai)
 159                return 1;
 160        return 0;
 161}
 162
 163int snd_soc_component_is_dummy(struct snd_soc_component *component)
 164{
 165        return ((component->driver == &dummy_platform) ||
 166                (component->driver == &dummy_codec));
 167}
 168
 169static int snd_soc_dummy_probe(struct platform_device *pdev)
 170{
 171        int ret;
 172
 173        ret = devm_snd_soc_register_component(&pdev->dev,
 174                                              &dummy_codec, &dummy_dai, 1);
 175        if (ret < 0)
 176                return ret;
 177
 178        ret = devm_snd_soc_register_component(&pdev->dev, &dummy_platform,
 179                                              NULL, 0);
 180
 181        return ret;
 182}
 183
 184static struct platform_driver soc_dummy_driver = {
 185        .driver = {
 186                .name = "snd-soc-dummy",
 187        },
 188        .probe = snd_soc_dummy_probe,
 189};
 190
 191static struct platform_device *soc_dummy_dev;
 192
 193int __init snd_soc_util_init(void)
 194{
 195        int ret;
 196
 197        soc_dummy_dev =
 198                platform_device_register_simple("snd-soc-dummy", -1, NULL, 0);
 199        if (IS_ERR(soc_dummy_dev))
 200                return PTR_ERR(soc_dummy_dev);
 201
 202        ret = platform_driver_register(&soc_dummy_driver);
 203        if (ret != 0)
 204                platform_device_unregister(soc_dummy_dev);
 205
 206        return ret;
 207}
 208
 209void __exit snd_soc_util_exit(void)
 210{
 211        platform_driver_unregister(&soc_dummy_driver);
 212        platform_device_unregister(soc_dummy_dev);
 213}
 214