1 // SPDX-License-Identifier: GPL-2.0+
3 // soc-util.c -- ALSA SoC Audio Layer utility functions
5 // Copyright 2009 Wolfson Microelectronics PLC.
7 // Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
8 // Liam Girdwood <lrg@slimlogic.co.uk>
10 #include <linux/platform_device.h>
11 #include <linux/export.h>
12 #include <linux/math.h>
13 #include <sound/core.h>
14 #include <sound/pcm.h>
15 #include <sound/pcm_params.h>
16 #include <sound/soc.h>
18 int snd_soc_calc_frame_size(int sample_size
, int channels
, int tdm_slots
)
20 return sample_size
* channels
* tdm_slots
;
22 EXPORT_SYMBOL_GPL(snd_soc_calc_frame_size
);
24 int snd_soc_params_to_frame_size(const struct snd_pcm_hw_params
*params
)
28 sample_size
= snd_pcm_format_width(params_format(params
));
32 return snd_soc_calc_frame_size(sample_size
, params_channels(params
),
35 EXPORT_SYMBOL_GPL(snd_soc_params_to_frame_size
);
37 int snd_soc_calc_bclk(int fs
, int sample_size
, int channels
, int tdm_slots
)
39 return fs
* snd_soc_calc_frame_size(sample_size
, channels
, tdm_slots
);
41 EXPORT_SYMBOL_GPL(snd_soc_calc_bclk
);
43 int snd_soc_params_to_bclk(const struct snd_pcm_hw_params
*params
)
47 ret
= snd_soc_params_to_frame_size(params
);
50 return ret
* params_rate(params
);
54 EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk
);
57 * snd_soc_tdm_params_to_bclk - calculate bclk from params and tdm slot info.
59 * Calculate the bclk from the params sample rate, the tdm slot count and the
60 * tdm slot width. Optionally round-up the slot count to a given multiple.
61 * Either or both of tdm_width and tdm_slots can be 0.
63 * If tdm_width == 0: use params_width() as the slot width.
64 * If tdm_slots == 0: use params_channels() as the slot count.
66 * If slot_multiple > 1 the slot count (or params_channels() if tdm_slots == 0)
67 * will be rounded up to a multiple of slot_multiple. This is mainly useful for
68 * I2S mode, which has a left and right phase so the number of slots is always
71 * If tdm_width == 0 && tdm_slots == 0 && slot_multiple < 2, this is equivalent
72 * to calling snd_soc_params_to_bclk().
74 * @params: Pointer to struct_pcm_hw_params.
75 * @tdm_width: Width in bits of the tdm slots. Must be >= 0.
76 * @tdm_slots: Number of tdm slots per frame. Must be >= 0.
77 * @slot_multiple: If >1 roundup slot count to a multiple of this value.
79 * Return: bclk frequency in Hz, else a negative error code if params format
82 int snd_soc_tdm_params_to_bclk(const struct snd_pcm_hw_params
*params
,
83 int tdm_width
, int tdm_slots
, int slot_multiple
)
86 tdm_slots
= params_channels(params
);
88 if (slot_multiple
> 1)
89 tdm_slots
= roundup(tdm_slots
, slot_multiple
);
92 tdm_width
= snd_pcm_format_width(params_format(params
));
97 return snd_soc_calc_bclk(params_rate(params
), tdm_width
, 1, tdm_slots
);
99 EXPORT_SYMBOL_GPL(snd_soc_tdm_params_to_bclk
);
101 static const struct snd_pcm_hardware dummy_dma_hardware
= {
102 /* Random values to keep userspace happy when checking constraints */
103 .info
= SNDRV_PCM_INFO_INTERLEAVED
|
104 SNDRV_PCM_INFO_BLOCK_TRANSFER
,
105 .buffer_bytes_max
= 128*1024,
106 .period_bytes_min
= 4096,
107 .period_bytes_max
= 4096*2,
113 static const struct snd_soc_component_driver dummy_platform
;
115 static int dummy_dma_open(struct snd_soc_component
*component
,
116 struct snd_pcm_substream
*substream
)
118 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
122 * If there are other components associated with rtd, we shouldn't
123 * override their hwparams
125 for_each_rtd_components(rtd
, i
, component
) {
126 if (component
->driver
== &dummy_platform
)
130 /* BE's dont need dummy params */
131 if (!rtd
->dai_link
->no_pcm
)
132 snd_soc_set_runtime_hwparams(substream
, &dummy_dma_hardware
);
137 static const struct snd_soc_component_driver dummy_platform
= {
138 .open
= dummy_dma_open
,
141 static const struct snd_soc_component_driver dummy_codec
= {
143 .use_pmdown_time
= 1,
147 #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
148 SNDRV_PCM_FMTBIT_U8 | \
149 SNDRV_PCM_FMTBIT_S16_LE | \
150 SNDRV_PCM_FMTBIT_U16_LE | \
151 SNDRV_PCM_FMTBIT_S24_LE | \
152 SNDRV_PCM_FMTBIT_S24_3LE | \
153 SNDRV_PCM_FMTBIT_U24_LE | \
154 SNDRV_PCM_FMTBIT_S32_LE | \
155 SNDRV_PCM_FMTBIT_U32_LE | \
156 SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
159 * Select these from Sound Card Manually
160 * SND_SOC_POSSIBLE_DAIFMT_CBP_CFP
161 * SND_SOC_POSSIBLE_DAIFMT_CBP_CFC
162 * SND_SOC_POSSIBLE_DAIFMT_CBC_CFP
163 * SND_SOC_POSSIBLE_DAIFMT_CBC_CFC
165 static const u64 dummy_dai_formats
=
166 SND_SOC_POSSIBLE_DAIFMT_I2S
|
167 SND_SOC_POSSIBLE_DAIFMT_RIGHT_J
|
168 SND_SOC_POSSIBLE_DAIFMT_LEFT_J
|
169 SND_SOC_POSSIBLE_DAIFMT_DSP_A
|
170 SND_SOC_POSSIBLE_DAIFMT_DSP_B
|
171 SND_SOC_POSSIBLE_DAIFMT_AC97
|
172 SND_SOC_POSSIBLE_DAIFMT_PDM
|
173 SND_SOC_POSSIBLE_DAIFMT_GATED
|
174 SND_SOC_POSSIBLE_DAIFMT_CONT
|
175 SND_SOC_POSSIBLE_DAIFMT_NB_NF
|
176 SND_SOC_POSSIBLE_DAIFMT_NB_IF
|
177 SND_SOC_POSSIBLE_DAIFMT_IB_NF
|
178 SND_SOC_POSSIBLE_DAIFMT_IB_IF
;
180 static const struct snd_soc_dai_ops dummy_dai_ops
= {
181 .auto_selectable_formats
= &dummy_dai_formats
,
182 .num_auto_selectable_formats
= 1,
186 * The dummy CODEC is only meant to be used in situations where there is no
189 * If there is actual hardware even if it does not have a control bus
190 * the hardware will still have constraints like supported samplerates, etc.
191 * which should be modelled. And the data flow graph also should be modelled
194 static struct snd_soc_dai_driver dummy_dai
= {
195 .name
= "snd-soc-dummy-dai",
197 .stream_name
= "Playback",
200 .rates
= SNDRV_PCM_RATE_CONTINUOUS
,
203 .formats
= STUB_FORMATS
,
206 .stream_name
= "Capture",
209 .rates
= SNDRV_PCM_RATE_CONTINUOUS
,
212 .formats
= STUB_FORMATS
,
214 .ops
= &dummy_dai_ops
,
217 int snd_soc_dai_is_dummy(const struct snd_soc_dai
*dai
)
219 if (dai
->driver
== &dummy_dai
)
223 EXPORT_SYMBOL_GPL(snd_soc_dai_is_dummy
);
225 int snd_soc_component_is_dummy(struct snd_soc_component
*component
)
227 return ((component
->driver
== &dummy_platform
) ||
228 (component
->driver
== &dummy_codec
));
231 struct snd_soc_dai_link_component snd_soc_dummy_dlc
= {
233 .dai_name
= "snd-soc-dummy-dai",
234 .name
= "snd-soc-dummy",
236 EXPORT_SYMBOL_GPL(snd_soc_dummy_dlc
);
238 static int snd_soc_dummy_probe(struct platform_device
*pdev
)
242 ret
= devm_snd_soc_register_component(&pdev
->dev
,
243 &dummy_codec
, &dummy_dai
, 1);
247 ret
= devm_snd_soc_register_component(&pdev
->dev
, &dummy_platform
,
253 static struct platform_driver soc_dummy_driver
= {
255 .name
= "snd-soc-dummy",
257 .probe
= snd_soc_dummy_probe
,
260 static struct platform_device
*soc_dummy_dev
;
262 int __init
snd_soc_util_init(void)
267 platform_device_register_simple("snd-soc-dummy", -1, NULL
, 0);
268 if (IS_ERR(soc_dummy_dev
))
269 return PTR_ERR(soc_dummy_dev
);
271 ret
= platform_driver_register(&soc_dummy_driver
);
273 platform_device_unregister(soc_dummy_dev
);
278 void snd_soc_util_exit(void)
280 platform_driver_unregister(&soc_dummy_driver
);
281 platform_device_unregister(soc_dummy_dev
);