0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/platform_device.h>
0011 #include <linux/export.h>
0012 #include <linux/math.h>
0013 #include <sound/core.h>
0014 #include <sound/pcm.h>
0015 #include <sound/pcm_params.h>
0016 #include <sound/soc.h>
0017
0018 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots)
0019 {
0020 return sample_size * channels * tdm_slots;
0021 }
0022 EXPORT_SYMBOL_GPL(snd_soc_calc_frame_size);
0023
0024 int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params)
0025 {
0026 int sample_size;
0027
0028 sample_size = snd_pcm_format_width(params_format(params));
0029 if (sample_size < 0)
0030 return sample_size;
0031
0032 return snd_soc_calc_frame_size(sample_size, params_channels(params),
0033 1);
0034 }
0035 EXPORT_SYMBOL_GPL(snd_soc_params_to_frame_size);
0036
0037 int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots)
0038 {
0039 return fs * snd_soc_calc_frame_size(sample_size, channels, tdm_slots);
0040 }
0041 EXPORT_SYMBOL_GPL(snd_soc_calc_bclk);
0042
0043 int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params)
0044 {
0045 int ret;
0046
0047 ret = snd_soc_params_to_frame_size(params);
0048
0049 if (ret > 0)
0050 return ret * params_rate(params);
0051 else
0052 return ret;
0053 }
0054 EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk);
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081 int snd_soc_tdm_params_to_bclk(struct snd_pcm_hw_params *params,
0082 int tdm_width, int tdm_slots, int slot_multiple)
0083 {
0084 if (!tdm_slots)
0085 tdm_slots = params_channels(params);
0086
0087 if (slot_multiple > 1)
0088 tdm_slots = roundup(tdm_slots, slot_multiple);
0089
0090 if (!tdm_width) {
0091 tdm_width = snd_pcm_format_width(params_format(params));
0092 if (tdm_width < 0)
0093 return tdm_width;
0094 }
0095
0096 return snd_soc_calc_bclk(params_rate(params), tdm_width, 1, tdm_slots);
0097 }
0098 EXPORT_SYMBOL_GPL(snd_soc_tdm_params_to_bclk);
0099
0100 static const struct snd_pcm_hardware dummy_dma_hardware = {
0101
0102 .info = SNDRV_PCM_INFO_INTERLEAVED |
0103 SNDRV_PCM_INFO_BLOCK_TRANSFER,
0104 .buffer_bytes_max = 128*1024,
0105 .period_bytes_min = PAGE_SIZE,
0106 .period_bytes_max = PAGE_SIZE*2,
0107 .periods_min = 2,
0108 .periods_max = 128,
0109 };
0110
0111
0112 static const struct snd_soc_component_driver dummy_platform;
0113
0114 static int dummy_dma_open(struct snd_soc_component *component,
0115 struct snd_pcm_substream *substream)
0116 {
0117 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0118 int i;
0119
0120
0121
0122
0123
0124 for_each_rtd_components(rtd, i, component) {
0125 if (component->driver == &dummy_platform)
0126 return 0;
0127 }
0128
0129
0130 if (!rtd->dai_link->no_pcm)
0131 snd_soc_set_runtime_hwparams(substream, &dummy_dma_hardware);
0132
0133 return 0;
0134 }
0135
0136 static const struct snd_soc_component_driver dummy_platform = {
0137 .open = dummy_dma_open,
0138 };
0139
0140 static const struct snd_soc_component_driver dummy_codec = {
0141 .idle_bias_on = 1,
0142 .use_pmdown_time = 1,
0143 .endianness = 1,
0144 };
0145
0146 #define STUB_RATES SNDRV_PCM_RATE_8000_384000
0147 #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
0148 SNDRV_PCM_FMTBIT_U8 | \
0149 SNDRV_PCM_FMTBIT_S16_LE | \
0150 SNDRV_PCM_FMTBIT_U16_LE | \
0151 SNDRV_PCM_FMTBIT_S24_LE | \
0152 SNDRV_PCM_FMTBIT_S24_3LE | \
0153 SNDRV_PCM_FMTBIT_U24_LE | \
0154 SNDRV_PCM_FMTBIT_S32_LE | \
0155 SNDRV_PCM_FMTBIT_U32_LE | \
0156 SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
0157
0158
0159
0160
0161
0162
0163
0164
0165 static u64 dummy_dai_formats =
0166 SND_SOC_POSSIBLE_DAIFMT_I2S |
0167 SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
0168 SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
0169 SND_SOC_POSSIBLE_DAIFMT_DSP_A |
0170 SND_SOC_POSSIBLE_DAIFMT_DSP_B |
0171 SND_SOC_POSSIBLE_DAIFMT_AC97 |
0172 SND_SOC_POSSIBLE_DAIFMT_PDM |
0173 SND_SOC_POSSIBLE_DAIFMT_GATED |
0174 SND_SOC_POSSIBLE_DAIFMT_CONT |
0175 SND_SOC_POSSIBLE_DAIFMT_NB_NF |
0176 SND_SOC_POSSIBLE_DAIFMT_NB_IF |
0177 SND_SOC_POSSIBLE_DAIFMT_IB_NF |
0178 SND_SOC_POSSIBLE_DAIFMT_IB_IF;
0179
0180 static const struct snd_soc_dai_ops dummy_dai_ops = {
0181 .auto_selectable_formats = &dummy_dai_formats,
0182 .num_auto_selectable_formats = 1,
0183 };
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194 static struct snd_soc_dai_driver dummy_dai = {
0195 .name = "snd-soc-dummy-dai",
0196 .playback = {
0197 .stream_name = "Playback",
0198 .channels_min = 1,
0199 .channels_max = 384,
0200 .rates = STUB_RATES,
0201 .formats = STUB_FORMATS,
0202 },
0203 .capture = {
0204 .stream_name = "Capture",
0205 .channels_min = 1,
0206 .channels_max = 384,
0207 .rates = STUB_RATES,
0208 .formats = STUB_FORMATS,
0209 },
0210 .ops = &dummy_dai_ops,
0211 };
0212
0213 int snd_soc_dai_is_dummy(struct snd_soc_dai *dai)
0214 {
0215 if (dai->driver == &dummy_dai)
0216 return 1;
0217 return 0;
0218 }
0219
0220 int snd_soc_component_is_dummy(struct snd_soc_component *component)
0221 {
0222 return ((component->driver == &dummy_platform) ||
0223 (component->driver == &dummy_codec));
0224 }
0225
0226 static int snd_soc_dummy_probe(struct platform_device *pdev)
0227 {
0228 int ret;
0229
0230 ret = devm_snd_soc_register_component(&pdev->dev,
0231 &dummy_codec, &dummy_dai, 1);
0232 if (ret < 0)
0233 return ret;
0234
0235 ret = devm_snd_soc_register_component(&pdev->dev, &dummy_platform,
0236 NULL, 0);
0237
0238 return ret;
0239 }
0240
0241 static struct platform_driver soc_dummy_driver = {
0242 .driver = {
0243 .name = "snd-soc-dummy",
0244 },
0245 .probe = snd_soc_dummy_probe,
0246 };
0247
0248 static struct platform_device *soc_dummy_dev;
0249
0250 int __init snd_soc_util_init(void)
0251 {
0252 int ret;
0253
0254 soc_dummy_dev =
0255 platform_device_register_simple("snd-soc-dummy", -1, NULL, 0);
0256 if (IS_ERR(soc_dummy_dev))
0257 return PTR_ERR(soc_dummy_dev);
0258
0259 ret = platform_driver_register(&soc_dummy_driver);
0260 if (ret != 0)
0261 platform_device_unregister(soc_dummy_dev);
0262
0263 return ret;
0264 }
0265
0266 void __exit snd_soc_util_exit(void)
0267 {
0268 platform_driver_unregister(&soc_dummy_driver);
0269 platform_device_unregister(soc_dummy_dev);
0270 }