~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/soc-utils.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 <linux/math.h>
 13 #include <sound/core.h>
 14 #include <sound/pcm.h>
 15 #include <sound/pcm_params.h>
 16 #include <sound/soc.h>
 17 
 18 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots)
 19 {
 20         return sample_size * channels * tdm_slots;
 21 }
 22 EXPORT_SYMBOL_GPL(snd_soc_calc_frame_size);
 23 
 24 int snd_soc_params_to_frame_size(const struct snd_pcm_hw_params *params)
 25 {
 26         int sample_size;
 27 
 28         sample_size = snd_pcm_format_width(params_format(params));
 29         if (sample_size < 0)
 30                 return sample_size;
 31 
 32         return snd_soc_calc_frame_size(sample_size, params_channels(params),
 33                                        1);
 34 }
 35 EXPORT_SYMBOL_GPL(snd_soc_params_to_frame_size);
 36 
 37 int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots)
 38 {
 39         return fs * snd_soc_calc_frame_size(sample_size, channels, tdm_slots);
 40 }
 41 EXPORT_SYMBOL_GPL(snd_soc_calc_bclk);
 42 
 43 int snd_soc_params_to_bclk(const struct snd_pcm_hw_params *params)
 44 {
 45         int ret;
 46 
 47         ret = snd_soc_params_to_frame_size(params);
 48 
 49         if (ret > 0)
 50                 return ret * params_rate(params);
 51         else
 52                 return ret;
 53 }
 54 EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk);
 55 
 56 /**
 57  * snd_soc_tdm_params_to_bclk - calculate bclk from params and tdm slot info.
 58  *
 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.
 62  *
 63  * If tdm_width == 0:   use params_width() as the slot width.
 64  * If tdm_slots == 0:   use params_channels() as the slot count.
 65  *
 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
 69  * a multiple of 2.
 70  *
 71  * If tdm_width == 0 && tdm_slots == 0 && slot_multiple < 2, this is equivalent
 72  * to calling snd_soc_params_to_bclk().
 73  *
 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.
 78  *
 79  * Return: bclk frequency in Hz, else a negative error code if params format
 80  *         is invalid.
 81  */
 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)
 84 {
 85         if (!tdm_slots)
 86                 tdm_slots = params_channels(params);
 87 
 88         if (slot_multiple > 1)
 89                 tdm_slots = roundup(tdm_slots, slot_multiple);
 90 
 91         if (!tdm_width) {
 92                 tdm_width = snd_pcm_format_width(params_format(params));
 93                 if (tdm_width < 0)
 94                         return tdm_width;
 95         }
 96 
 97         return snd_soc_calc_bclk(params_rate(params), tdm_width, 1, tdm_slots);
 98 }
 99 EXPORT_SYMBOL_GPL(snd_soc_tdm_params_to_bclk);
100 
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       = PAGE_SIZE,
107         .period_bytes_max       = PAGE_SIZE*2,
108         .periods_min            = 2,
109         .periods_max            = 128,
110 };
111 
112 
113 static const struct snd_soc_component_driver dummy_platform;
114 
115 static int dummy_dma_open(struct snd_soc_component *component,
116                           struct snd_pcm_substream *substream)
117 {
118         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
119         int i;
120 
121         /*
122          * If there are other components associated with rtd, we shouldn't
123          * override their hwparams
124          */
125         for_each_rtd_components(rtd, i, component) {
126                 if (component->driver == &dummy_platform)
127                         return 0;
128         }
129 
130         /* BE's dont need dummy params */
131         if (!rtd->dai_link->no_pcm)
132                 snd_soc_set_runtime_hwparams(substream, &dummy_dma_hardware);
133 
134         return 0;
135 }
136 
137 static const struct snd_soc_component_driver dummy_platform = {
138         .open           = dummy_dma_open,
139 };
140 
141 static const struct snd_soc_component_driver dummy_codec = {
142         .idle_bias_on           = 1,
143         .use_pmdown_time        = 1,
144         .endianness             = 1,
145 };
146 
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)
157 
158 /*
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
164  */
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;
179 
180 static const struct snd_soc_dai_ops dummy_dai_ops = {
181         .auto_selectable_formats        = &dummy_dai_formats,
182         .num_auto_selectable_formats    = 1,
183 };
184 
185 /*
186  * The dummy CODEC is only meant to be used in situations where there is no
187  * actual hardware.
188  *
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
192  * using DAPM.
193  */
194 static struct snd_soc_dai_driver dummy_dai = {
195         .name = "snd-soc-dummy-dai",
196         .playback = {
197                 .stream_name    = "Playback",
198                 .channels_min   = 1,
199                 .channels_max   = 384,
200                 .rates          = SNDRV_PCM_RATE_CONTINUOUS,
201                 .rate_min       = 5512,
202                 .rate_max       = 768000,
203                 .formats        = STUB_FORMATS,
204         },
205         .capture = {
206                 .stream_name    = "Capture",
207                 .channels_min   = 1,
208                 .channels_max   = 384,
209                 .rates = SNDRV_PCM_RATE_CONTINUOUS,
210                 .rate_min       = 5512,
211                 .rate_max       = 768000,
212                 .formats = STUB_FORMATS,
213          },
214         .ops = &dummy_dai_ops,
215 };
216 
217 int snd_soc_dai_is_dummy(const struct snd_soc_dai *dai)
218 {
219         if (dai->driver == &dummy_dai)
220                 return 1;
221         return 0;
222 }
223 EXPORT_SYMBOL_GPL(snd_soc_dai_is_dummy);
224 
225 int snd_soc_component_is_dummy(struct snd_soc_component *component)
226 {
227         return ((component->driver == &dummy_platform) ||
228                 (component->driver == &dummy_codec));
229 }
230 
231 struct snd_soc_dai_link_component snd_soc_dummy_dlc = {
232         .of_node        = NULL,
233         .dai_name       = "snd-soc-dummy-dai",
234         .name           = "snd-soc-dummy",
235 };
236 EXPORT_SYMBOL_GPL(snd_soc_dummy_dlc);
237 
238 static int snd_soc_dummy_probe(struct platform_device *pdev)
239 {
240         int ret;
241 
242         ret = devm_snd_soc_register_component(&pdev->dev,
243                                               &dummy_codec, &dummy_dai, 1);
244         if (ret < 0)
245                 return ret;
246 
247         ret = devm_snd_soc_register_component(&pdev->dev, &dummy_platform,
248                                               NULL, 0);
249 
250         return ret;
251 }
252 
253 static struct platform_driver soc_dummy_driver = {
254         .driver = {
255                 .name = "snd-soc-dummy",
256         },
257         .probe = snd_soc_dummy_probe,
258 };
259 
260 static struct platform_device *soc_dummy_dev;
261 
262 int __init snd_soc_util_init(void)
263 {
264         int ret;
265 
266         soc_dummy_dev =
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);
270 
271         ret = platform_driver_register(&soc_dummy_driver);
272         if (ret != 0)
273                 platform_device_unregister(soc_dummy_dev);
274 
275         return ret;
276 }
277 
278 void snd_soc_util_exit(void)
279 {
280         platform_driver_unregister(&soc_dummy_driver);
281         platform_device_unregister(soc_dummy_dev);
282 }
283 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php