xref: /openbmc/linux/sound/soc/soc-utils.c (revision aa1f10e8)
1 /*
2  * soc-util.c  --  ALSA SoC Audio Layer utility functions
3  *
4  * Copyright 2009 Wolfson Microelectronics PLC.
5  *
6  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7  *         Liam Girdwood <lrg@slimlogic.co.uk>
8  *
9  *
10  *  This program is free software; you can redistribute  it and/or modify it
11  *  under  the terms of  the GNU General  Public License as published by the
12  *  Free Software Foundation;  either version 2 of the  License, or (at your
13  *  option) any later version.
14  */
15 
16 #include <linux/platform_device.h>
17 #include <linux/export.h>
18 #include <sound/core.h>
19 #include <sound/pcm.h>
20 #include <sound/pcm_params.h>
21 #include <sound/soc.h>
22 
23 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots)
24 {
25 	return sample_size * channels * tdm_slots;
26 }
27 EXPORT_SYMBOL_GPL(snd_soc_calc_frame_size);
28 
29 int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params)
30 {
31 	int sample_size;
32 
33 	sample_size = snd_pcm_format_width(params_format(params));
34 	if (sample_size < 0)
35 		return sample_size;
36 
37 	return snd_soc_calc_frame_size(sample_size, params_channels(params),
38 				       1);
39 }
40 EXPORT_SYMBOL_GPL(snd_soc_params_to_frame_size);
41 
42 int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots)
43 {
44 	return fs * snd_soc_calc_frame_size(sample_size, channels, tdm_slots);
45 }
46 EXPORT_SYMBOL_GPL(snd_soc_calc_bclk);
47 
48 int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params)
49 {
50 	int ret;
51 
52 	ret = snd_soc_params_to_frame_size(params);
53 
54 	if (ret > 0)
55 		return ret * params_rate(params);
56 	else
57 		return ret;
58 }
59 EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk);
60 
61 int snd_soc_component_enable_pin(struct snd_soc_component *component,
62 				 const char *pin)
63 {
64 	struct snd_soc_dapm_context *dapm =
65 		snd_soc_component_get_dapm(component);
66 	char *full_name;
67 	int ret;
68 
69 	if (!component->name_prefix)
70 		return snd_soc_dapm_enable_pin(dapm, pin);
71 
72 	full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin);
73 	if (!full_name)
74 		return -ENOMEM;
75 
76 	ret = snd_soc_dapm_enable_pin(dapm, full_name);
77 	kfree(full_name);
78 
79 	return ret;
80 }
81 EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin);
82 
83 int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component,
84 					  const char *pin)
85 {
86 	struct snd_soc_dapm_context *dapm =
87 		snd_soc_component_get_dapm(component);
88 	char *full_name;
89 	int ret;
90 
91 	if (!component->name_prefix)
92 		return snd_soc_dapm_enable_pin_unlocked(dapm, pin);
93 
94 	full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin);
95 	if (!full_name)
96 		return -ENOMEM;
97 
98 	ret = snd_soc_dapm_enable_pin_unlocked(dapm, full_name);
99 	kfree(full_name);
100 
101 	return ret;
102 }
103 EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin_unlocked);
104 
105 int snd_soc_component_disable_pin(struct snd_soc_component *component,
106 				  const char *pin)
107 {
108 	struct snd_soc_dapm_context *dapm =
109 		snd_soc_component_get_dapm(component);
110 	char *full_name;
111 	int ret;
112 
113 	if (!component->name_prefix)
114 		return snd_soc_dapm_disable_pin(dapm, pin);
115 
116 	full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin);
117 	if (!full_name)
118 		return -ENOMEM;
119 
120 	ret = snd_soc_dapm_disable_pin(dapm, full_name);
121 	kfree(full_name);
122 
123 	return ret;
124 }
125 EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin);
126 
127 int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component,
128 					   const char *pin)
129 {
130 	struct snd_soc_dapm_context *dapm =
131 		snd_soc_component_get_dapm(component);
132 	char *full_name;
133 	int ret;
134 
135 	if (!component->name_prefix)
136 		return snd_soc_dapm_disable_pin_unlocked(dapm, pin);
137 
138 	full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin);
139 	if (!full_name)
140 		return -ENOMEM;
141 
142 	ret = snd_soc_dapm_disable_pin_unlocked(dapm, full_name);
143 	kfree(full_name);
144 
145 	return ret;
146 }
147 EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin_unlocked);
148 
149 int snd_soc_component_nc_pin(struct snd_soc_component *component,
150 			     const char *pin)
151 {
152 	struct snd_soc_dapm_context *dapm =
153 		snd_soc_component_get_dapm(component);
154 	char *full_name;
155 	int ret;
156 
157 	if (!component->name_prefix)
158 		return snd_soc_dapm_nc_pin(dapm, pin);
159 
160 	full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin);
161 	if (!full_name)
162 		return -ENOMEM;
163 
164 	ret = snd_soc_dapm_nc_pin(dapm, full_name);
165 	kfree(full_name);
166 
167 	return ret;
168 }
169 EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin);
170 
171 int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component,
172 				      const char *pin)
173 {
174 	struct snd_soc_dapm_context *dapm =
175 		snd_soc_component_get_dapm(component);
176 	char *full_name;
177 	int ret;
178 
179 	if (!component->name_prefix)
180 		return snd_soc_dapm_nc_pin_unlocked(dapm, pin);
181 
182 	full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin);
183 	if (!full_name)
184 		return -ENOMEM;
185 
186 	ret = snd_soc_dapm_nc_pin_unlocked(dapm, full_name);
187 	kfree(full_name);
188 
189 	return ret;
190 }
191 EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin_unlocked);
192 
193 int snd_soc_component_get_pin_status(struct snd_soc_component *component,
194 				     const char *pin)
195 {
196 	struct snd_soc_dapm_context *dapm =
197 		snd_soc_component_get_dapm(component);
198 	char *full_name;
199 	int ret;
200 
201 	if (!component->name_prefix)
202 		return snd_soc_dapm_get_pin_status(dapm, pin);
203 
204 	full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin);
205 	if (!full_name)
206 		return -ENOMEM;
207 
208 	ret = snd_soc_dapm_get_pin_status(dapm, full_name);
209 	kfree(full_name);
210 
211 	return ret;
212 }
213 EXPORT_SYMBOL_GPL(snd_soc_component_get_pin_status);
214 
215 int snd_soc_component_force_enable_pin(struct snd_soc_component *component,
216 				       const char *pin)
217 {
218 	struct snd_soc_dapm_context *dapm =
219 		snd_soc_component_get_dapm(component);
220 	char *full_name;
221 	int ret;
222 
223 	if (!component->name_prefix)
224 		return snd_soc_dapm_force_enable_pin(dapm, pin);
225 
226 	full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin);
227 	if (!full_name)
228 		return -ENOMEM;
229 
230 	ret = snd_soc_dapm_force_enable_pin(dapm, full_name);
231 	kfree(full_name);
232 
233 	return ret;
234 }
235 EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin);
236 
237 int snd_soc_component_force_enable_pin_unlocked(
238 					struct snd_soc_component *component,
239 					const char *pin)
240 {
241 	struct snd_soc_dapm_context *dapm =
242 		snd_soc_component_get_dapm(component);
243 	char *full_name;
244 	int ret;
245 
246 	if (!component->name_prefix)
247 		return snd_soc_dapm_force_enable_pin_unlocked(dapm, pin);
248 
249 	full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin);
250 	if (!full_name)
251 		return -ENOMEM;
252 
253 	ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, full_name);
254 	kfree(full_name);
255 
256 	return ret;
257 }
258 EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin_unlocked);
259 
260 static const struct snd_pcm_hardware dummy_dma_hardware = {
261 	/* Random values to keep userspace happy when checking constraints */
262 	.info			= SNDRV_PCM_INFO_INTERLEAVED |
263 				  SNDRV_PCM_INFO_BLOCK_TRANSFER,
264 	.buffer_bytes_max	= 128*1024,
265 	.period_bytes_min	= PAGE_SIZE,
266 	.period_bytes_max	= PAGE_SIZE*2,
267 	.periods_min		= 2,
268 	.periods_max		= 128,
269 };
270 
271 static int dummy_dma_open(struct snd_pcm_substream *substream)
272 {
273 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
274 
275 	/* BE's dont need dummy params */
276 	if (!rtd->dai_link->no_pcm)
277 		snd_soc_set_runtime_hwparams(substream, &dummy_dma_hardware);
278 
279 	return 0;
280 }
281 
282 static const struct snd_pcm_ops dummy_dma_ops = {
283 	.open		= dummy_dma_open,
284 	.ioctl		= snd_pcm_lib_ioctl,
285 };
286 
287 static const struct snd_soc_platform_driver dummy_platform = {
288 	.ops = &dummy_dma_ops,
289 };
290 
291 static struct snd_soc_codec_driver dummy_codec;
292 
293 #define STUB_RATES	SNDRV_PCM_RATE_8000_192000
294 #define STUB_FORMATS	(SNDRV_PCM_FMTBIT_S8 | \
295 			SNDRV_PCM_FMTBIT_U8 | \
296 			SNDRV_PCM_FMTBIT_S16_LE | \
297 			SNDRV_PCM_FMTBIT_U16_LE | \
298 			SNDRV_PCM_FMTBIT_S24_LE | \
299 			SNDRV_PCM_FMTBIT_U24_LE | \
300 			SNDRV_PCM_FMTBIT_S32_LE | \
301 			SNDRV_PCM_FMTBIT_U32_LE | \
302 			SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
303 /*
304  * The dummy CODEC is only meant to be used in situations where there is no
305  * actual hardware.
306  *
307  * If there is actual hardware even if it does not have a control bus
308  * the hardware will still have constraints like supported samplerates, etc.
309  * which should be modelled. And the data flow graph also should be modelled
310  * using DAPM.
311  */
312 static struct snd_soc_dai_driver dummy_dai = {
313 	.name = "snd-soc-dummy-dai",
314 	.playback = {
315 		.stream_name	= "Playback",
316 		.channels_min	= 1,
317 		.channels_max	= 384,
318 		.rates		= STUB_RATES,
319 		.formats	= STUB_FORMATS,
320 	},
321 	.capture = {
322 		.stream_name	= "Capture",
323 		.channels_min	= 1,
324 		.channels_max	= 384,
325 		.rates = STUB_RATES,
326 		.formats = STUB_FORMATS,
327 	 },
328 };
329 
330 int snd_soc_dai_is_dummy(struct snd_soc_dai *dai)
331 {
332 	if (dai->driver == &dummy_dai)
333 		return 1;
334 	return 0;
335 }
336 
337 static int snd_soc_dummy_probe(struct platform_device *pdev)
338 {
339 	int ret;
340 
341 	ret = snd_soc_register_codec(&pdev->dev, &dummy_codec, &dummy_dai, 1);
342 	if (ret < 0)
343 		return ret;
344 
345 	ret = snd_soc_register_platform(&pdev->dev, &dummy_platform);
346 	if (ret < 0) {
347 		snd_soc_unregister_codec(&pdev->dev);
348 		return ret;
349 	}
350 
351 	return ret;
352 }
353 
354 static int snd_soc_dummy_remove(struct platform_device *pdev)
355 {
356 	snd_soc_unregister_platform(&pdev->dev);
357 	snd_soc_unregister_codec(&pdev->dev);
358 
359 	return 0;
360 }
361 
362 static struct platform_driver soc_dummy_driver = {
363 	.driver = {
364 		.name = "snd-soc-dummy",
365 	},
366 	.probe = snd_soc_dummy_probe,
367 	.remove = snd_soc_dummy_remove,
368 };
369 
370 static struct platform_device *soc_dummy_dev;
371 
372 int __init snd_soc_util_init(void)
373 {
374 	int ret;
375 
376 	soc_dummy_dev =
377 		platform_device_register_simple("snd-soc-dummy", -1, NULL, 0);
378 	if (IS_ERR(soc_dummy_dev))
379 		return PTR_ERR(soc_dummy_dev);
380 
381 	ret = platform_driver_register(&soc_dummy_driver);
382 	if (ret != 0)
383 		platform_device_unregister(soc_dummy_dev);
384 
385 	return ret;
386 }
387 
388 void __exit snd_soc_util_exit(void)
389 {
390 	platform_device_unregister(soc_dummy_dev);
391 	platform_driver_unregister(&soc_dummy_driver);
392 }
393