diff options
Diffstat (limited to 'sound/soc/soc-component.c')
-rw-r--r-- | sound/soc/soc-component.c | 561 |
1 files changed, 561 insertions, 0 deletions
diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c new file mode 100644 index 000000000000..79ffc2820ba9 --- /dev/null +++ b/sound/soc/soc-component.c | |||
@@ -0,0 +1,561 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | // | ||
3 | // soc-component.c | ||
4 | // | ||
5 | // Copyright (C) 2019 Renesas Electronics Corp. | ||
6 | // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
7 | // | ||
8 | #include <linux/module.h> | ||
9 | #include <sound/soc.h> | ||
10 | |||
11 | /** | ||
12 | * snd_soc_component_set_sysclk - configure COMPONENT system or master clock. | ||
13 | * @component: COMPONENT | ||
14 | * @clk_id: DAI specific clock ID | ||
15 | * @source: Source for the clock | ||
16 | * @freq: new clock frequency in Hz | ||
17 | * @dir: new clock direction - input/output. | ||
18 | * | ||
19 | * Configures the CODEC master (MCLK) or system (SYSCLK) clocking. | ||
20 | */ | ||
21 | int snd_soc_component_set_sysclk(struct snd_soc_component *component, | ||
22 | int clk_id, int source, unsigned int freq, | ||
23 | int dir) | ||
24 | { | ||
25 | if (component->driver->set_sysclk) | ||
26 | return component->driver->set_sysclk(component, clk_id, source, | ||
27 | freq, dir); | ||
28 | |||
29 | return -ENOTSUPP; | ||
30 | } | ||
31 | EXPORT_SYMBOL_GPL(snd_soc_component_set_sysclk); | ||
32 | |||
33 | /* | ||
34 | * snd_soc_component_set_pll - configure component PLL. | ||
35 | * @component: COMPONENT | ||
36 | * @pll_id: DAI specific PLL ID | ||
37 | * @source: DAI specific source for the PLL | ||
38 | * @freq_in: PLL input clock frequency in Hz | ||
39 | * @freq_out: requested PLL output clock frequency in Hz | ||
40 | * | ||
41 | * Configures and enables PLL to generate output clock based on input clock. | ||
42 | */ | ||
43 | int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id, | ||
44 | int source, unsigned int freq_in, | ||
45 | unsigned int freq_out) | ||
46 | { | ||
47 | if (component->driver->set_pll) | ||
48 | return component->driver->set_pll(component, pll_id, source, | ||
49 | freq_in, freq_out); | ||
50 | |||
51 | return -EINVAL; | ||
52 | } | ||
53 | EXPORT_SYMBOL_GPL(snd_soc_component_set_pll); | ||
54 | |||
55 | void snd_soc_component_seq_notifier(struct snd_soc_component *component, | ||
56 | enum snd_soc_dapm_type type, int subseq) | ||
57 | { | ||
58 | if (component->driver->seq_notifier) | ||
59 | component->driver->seq_notifier(component, type, subseq); | ||
60 | } | ||
61 | |||
62 | int snd_soc_component_stream_event(struct snd_soc_component *component, | ||
63 | int event) | ||
64 | { | ||
65 | if (component->driver->stream_event) | ||
66 | return component->driver->stream_event(component, event); | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | int snd_soc_component_set_bias_level(struct snd_soc_component *component, | ||
72 | enum snd_soc_bias_level level) | ||
73 | { | ||
74 | if (component->driver->set_bias_level) | ||
75 | return component->driver->set_bias_level(component, level); | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | int snd_soc_component_enable_pin(struct snd_soc_component *component, | ||
81 | const char *pin) | ||
82 | { | ||
83 | struct snd_soc_dapm_context *dapm = | ||
84 | snd_soc_component_get_dapm(component); | ||
85 | char *full_name; | ||
86 | int ret; | ||
87 | |||
88 | if (!component->name_prefix) | ||
89 | return snd_soc_dapm_enable_pin(dapm, pin); | ||
90 | |||
91 | full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); | ||
92 | if (!full_name) | ||
93 | return -ENOMEM; | ||
94 | |||
95 | ret = snd_soc_dapm_enable_pin(dapm, full_name); | ||
96 | kfree(full_name); | ||
97 | |||
98 | return ret; | ||
99 | } | ||
100 | EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin); | ||
101 | |||
102 | int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component, | ||
103 | const char *pin) | ||
104 | { | ||
105 | struct snd_soc_dapm_context *dapm = | ||
106 | snd_soc_component_get_dapm(component); | ||
107 | char *full_name; | ||
108 | int ret; | ||
109 | |||
110 | if (!component->name_prefix) | ||
111 | return snd_soc_dapm_enable_pin_unlocked(dapm, pin); | ||
112 | |||
113 | full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); | ||
114 | if (!full_name) | ||
115 | return -ENOMEM; | ||
116 | |||
117 | ret = snd_soc_dapm_enable_pin_unlocked(dapm, full_name); | ||
118 | kfree(full_name); | ||
119 | |||
120 | return ret; | ||
121 | } | ||
122 | EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin_unlocked); | ||
123 | |||
124 | int snd_soc_component_disable_pin(struct snd_soc_component *component, | ||
125 | const char *pin) | ||
126 | { | ||
127 | struct snd_soc_dapm_context *dapm = | ||
128 | snd_soc_component_get_dapm(component); | ||
129 | char *full_name; | ||
130 | int ret; | ||
131 | |||
132 | if (!component->name_prefix) | ||
133 | return snd_soc_dapm_disable_pin(dapm, pin); | ||
134 | |||
135 | full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); | ||
136 | if (!full_name) | ||
137 | return -ENOMEM; | ||
138 | |||
139 | ret = snd_soc_dapm_disable_pin(dapm, full_name); | ||
140 | kfree(full_name); | ||
141 | |||
142 | return ret; | ||
143 | } | ||
144 | EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin); | ||
145 | |||
146 | int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component, | ||
147 | const char *pin) | ||
148 | { | ||
149 | struct snd_soc_dapm_context *dapm = | ||
150 | snd_soc_component_get_dapm(component); | ||
151 | char *full_name; | ||
152 | int ret; | ||
153 | |||
154 | if (!component->name_prefix) | ||
155 | return snd_soc_dapm_disable_pin_unlocked(dapm, pin); | ||
156 | |||
157 | full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); | ||
158 | if (!full_name) | ||
159 | return -ENOMEM; | ||
160 | |||
161 | ret = snd_soc_dapm_disable_pin_unlocked(dapm, full_name); | ||
162 | kfree(full_name); | ||
163 | |||
164 | return ret; | ||
165 | } | ||
166 | EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin_unlocked); | ||
167 | |||
168 | int snd_soc_component_nc_pin(struct snd_soc_component *component, | ||
169 | const char *pin) | ||
170 | { | ||
171 | struct snd_soc_dapm_context *dapm = | ||
172 | snd_soc_component_get_dapm(component); | ||
173 | char *full_name; | ||
174 | int ret; | ||
175 | |||
176 | if (!component->name_prefix) | ||
177 | return snd_soc_dapm_nc_pin(dapm, pin); | ||
178 | |||
179 | full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); | ||
180 | if (!full_name) | ||
181 | return -ENOMEM; | ||
182 | |||
183 | ret = snd_soc_dapm_nc_pin(dapm, full_name); | ||
184 | kfree(full_name); | ||
185 | |||
186 | return ret; | ||
187 | } | ||
188 | EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin); | ||
189 | |||
190 | int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component, | ||
191 | const char *pin) | ||
192 | { | ||
193 | struct snd_soc_dapm_context *dapm = | ||
194 | snd_soc_component_get_dapm(component); | ||
195 | char *full_name; | ||
196 | int ret; | ||
197 | |||
198 | if (!component->name_prefix) | ||
199 | return snd_soc_dapm_nc_pin_unlocked(dapm, pin); | ||
200 | |||
201 | full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); | ||
202 | if (!full_name) | ||
203 | return -ENOMEM; | ||
204 | |||
205 | ret = snd_soc_dapm_nc_pin_unlocked(dapm, full_name); | ||
206 | kfree(full_name); | ||
207 | |||
208 | return ret; | ||
209 | } | ||
210 | EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin_unlocked); | ||
211 | |||
212 | int snd_soc_component_get_pin_status(struct snd_soc_component *component, | ||
213 | const char *pin) | ||
214 | { | ||
215 | struct snd_soc_dapm_context *dapm = | ||
216 | snd_soc_component_get_dapm(component); | ||
217 | char *full_name; | ||
218 | int ret; | ||
219 | |||
220 | if (!component->name_prefix) | ||
221 | return snd_soc_dapm_get_pin_status(dapm, pin); | ||
222 | |||
223 | full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); | ||
224 | if (!full_name) | ||
225 | return -ENOMEM; | ||
226 | |||
227 | ret = snd_soc_dapm_get_pin_status(dapm, full_name); | ||
228 | kfree(full_name); | ||
229 | |||
230 | return ret; | ||
231 | } | ||
232 | EXPORT_SYMBOL_GPL(snd_soc_component_get_pin_status); | ||
233 | |||
234 | int snd_soc_component_force_enable_pin(struct snd_soc_component *component, | ||
235 | const char *pin) | ||
236 | { | ||
237 | struct snd_soc_dapm_context *dapm = | ||
238 | snd_soc_component_get_dapm(component); | ||
239 | char *full_name; | ||
240 | int ret; | ||
241 | |||
242 | if (!component->name_prefix) | ||
243 | return snd_soc_dapm_force_enable_pin(dapm, pin); | ||
244 | |||
245 | full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); | ||
246 | if (!full_name) | ||
247 | return -ENOMEM; | ||
248 | |||
249 | ret = snd_soc_dapm_force_enable_pin(dapm, full_name); | ||
250 | kfree(full_name); | ||
251 | |||
252 | return ret; | ||
253 | } | ||
254 | EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin); | ||
255 | |||
256 | int snd_soc_component_force_enable_pin_unlocked( | ||
257 | struct snd_soc_component *component, | ||
258 | const char *pin) | ||
259 | { | ||
260 | struct snd_soc_dapm_context *dapm = | ||
261 | snd_soc_component_get_dapm(component); | ||
262 | char *full_name; | ||
263 | int ret; | ||
264 | |||
265 | if (!component->name_prefix) | ||
266 | return snd_soc_dapm_force_enable_pin_unlocked(dapm, pin); | ||
267 | |||
268 | full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); | ||
269 | if (!full_name) | ||
270 | return -ENOMEM; | ||
271 | |||
272 | ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, full_name); | ||
273 | kfree(full_name); | ||
274 | |||
275 | return ret; | ||
276 | } | ||
277 | EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin_unlocked); | ||
278 | |||
279 | /** | ||
280 | * snd_soc_component_set_jack - configure component jack. | ||
281 | * @component: COMPONENTs | ||
282 | * @jack: structure to use for the jack | ||
283 | * @data: can be used if codec driver need extra data for configuring jack | ||
284 | * | ||
285 | * Configures and enables jack detection function. | ||
286 | */ | ||
287 | int snd_soc_component_set_jack(struct snd_soc_component *component, | ||
288 | struct snd_soc_jack *jack, void *data) | ||
289 | { | ||
290 | if (component->driver->set_jack) | ||
291 | return component->driver->set_jack(component, jack, data); | ||
292 | |||
293 | return -ENOTSUPP; | ||
294 | } | ||
295 | EXPORT_SYMBOL_GPL(snd_soc_component_set_jack); | ||
296 | |||
297 | int snd_soc_component_module_get(struct snd_soc_component *component, | ||
298 | int upon_open) | ||
299 | { | ||
300 | if (component->driver->module_get_upon_open == !!upon_open && | ||
301 | !try_module_get(component->dev->driver->owner)) | ||
302 | return -ENODEV; | ||
303 | |||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | void snd_soc_component_module_put(struct snd_soc_component *component, | ||
308 | int upon_open) | ||
309 | { | ||
310 | if (component->driver->module_get_upon_open == !!upon_open) | ||
311 | module_put(component->dev->driver->owner); | ||
312 | } | ||
313 | |||
314 | int snd_soc_component_open(struct snd_soc_component *component, | ||
315 | struct snd_pcm_substream *substream) | ||
316 | { | ||
317 | if (component->driver->ops && | ||
318 | component->driver->ops->open) | ||
319 | return component->driver->ops->open(substream); | ||
320 | |||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | int snd_soc_component_close(struct snd_soc_component *component, | ||
325 | struct snd_pcm_substream *substream) | ||
326 | { | ||
327 | if (component->driver->ops && | ||
328 | component->driver->ops->close) | ||
329 | return component->driver->ops->close(substream); | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | int snd_soc_component_prepare(struct snd_soc_component *component, | ||
335 | struct snd_pcm_substream *substream) | ||
336 | { | ||
337 | if (component->driver->ops && | ||
338 | component->driver->ops->prepare) | ||
339 | return component->driver->ops->prepare(substream); | ||
340 | |||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | int snd_soc_component_hw_params(struct snd_soc_component *component, | ||
345 | struct snd_pcm_substream *substream, | ||
346 | struct snd_pcm_hw_params *params) | ||
347 | { | ||
348 | if (component->driver->ops && | ||
349 | component->driver->ops->hw_params) | ||
350 | return component->driver->ops->hw_params(substream, params); | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | int snd_soc_component_hw_free(struct snd_soc_component *component, | ||
356 | struct snd_pcm_substream *substream) | ||
357 | { | ||
358 | if (component->driver->ops && | ||
359 | component->driver->ops->hw_free) | ||
360 | return component->driver->ops->hw_free(substream); | ||
361 | |||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | int snd_soc_component_trigger(struct snd_soc_component *component, | ||
366 | struct snd_pcm_substream *substream, | ||
367 | int cmd) | ||
368 | { | ||
369 | if (component->driver->ops && | ||
370 | component->driver->ops->trigger) | ||
371 | return component->driver->ops->trigger(substream, cmd); | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | void snd_soc_component_suspend(struct snd_soc_component *component) | ||
377 | { | ||
378 | if (component->driver->suspend) | ||
379 | component->driver->suspend(component); | ||
380 | component->suspended = 1; | ||
381 | } | ||
382 | |||
383 | void snd_soc_component_resume(struct snd_soc_component *component) | ||
384 | { | ||
385 | if (component->driver->resume) | ||
386 | component->driver->resume(component); | ||
387 | component->suspended = 0; | ||
388 | } | ||
389 | |||
390 | int snd_soc_component_is_suspended(struct snd_soc_component *component) | ||
391 | { | ||
392 | return component->suspended; | ||
393 | } | ||
394 | |||
395 | int snd_soc_component_probe(struct snd_soc_component *component) | ||
396 | { | ||
397 | if (component->driver->probe) | ||
398 | return component->driver->probe(component); | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | void snd_soc_component_remove(struct snd_soc_component *component) | ||
404 | { | ||
405 | if (component->driver->remove) | ||
406 | component->driver->remove(component); | ||
407 | } | ||
408 | |||
409 | int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component, | ||
410 | struct device_node *ep) | ||
411 | { | ||
412 | if (component->driver->of_xlate_dai_id) | ||
413 | return component->driver->of_xlate_dai_id(component, ep); | ||
414 | |||
415 | return -ENOTSUPP; | ||
416 | } | ||
417 | |||
418 | int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component, | ||
419 | struct of_phandle_args *args, | ||
420 | const char **dai_name) | ||
421 | { | ||
422 | if (component->driver->of_xlate_dai_name) | ||
423 | return component->driver->of_xlate_dai_name(component, | ||
424 | args, dai_name); | ||
425 | return -ENOTSUPP; | ||
426 | } | ||
427 | |||
428 | int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream) | ||
429 | { | ||
430 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
431 | struct snd_soc_component *component; | ||
432 | struct snd_soc_rtdcom_list *rtdcom; | ||
433 | |||
434 | for_each_rtdcom(rtd, rtdcom) { | ||
435 | component = rtdcom->component; | ||
436 | |||
437 | /* FIXME: use 1st pointer */ | ||
438 | if (component->driver->ops && | ||
439 | component->driver->ops->pointer) | ||
440 | return component->driver->ops->pointer(substream); | ||
441 | } | ||
442 | |||
443 | return 0; | ||
444 | } | ||
445 | |||
446 | int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, | ||
447 | unsigned int cmd, void *arg) | ||
448 | { | ||
449 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
450 | struct snd_soc_component *component; | ||
451 | struct snd_soc_rtdcom_list *rtdcom; | ||
452 | |||
453 | for_each_rtdcom(rtd, rtdcom) { | ||
454 | component = rtdcom->component; | ||
455 | |||
456 | /* FIXME: use 1st ioctl */ | ||
457 | if (component->driver->ops && | ||
458 | component->driver->ops->ioctl) | ||
459 | return component->driver->ops->ioctl(substream, | ||
460 | cmd, arg); | ||
461 | } | ||
462 | |||
463 | return snd_pcm_lib_ioctl(substream, cmd, arg); | ||
464 | } | ||
465 | |||
466 | int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, | ||
467 | int channel, unsigned long pos, | ||
468 | void __user *buf, unsigned long bytes) | ||
469 | { | ||
470 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
471 | struct snd_soc_rtdcom_list *rtdcom; | ||
472 | struct snd_soc_component *component; | ||
473 | |||
474 | for_each_rtdcom(rtd, rtdcom) { | ||
475 | component = rtdcom->component; | ||
476 | |||
477 | /* FIXME. it returns 1st copy now */ | ||
478 | if (component->driver->ops && | ||
479 | component->driver->ops->copy_user) | ||
480 | return component->driver->ops->copy_user( | ||
481 | substream, channel, pos, buf, bytes); | ||
482 | } | ||
483 | |||
484 | return -EINVAL; | ||
485 | } | ||
486 | |||
487 | struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, | ||
488 | unsigned long offset) | ||
489 | { | ||
490 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
491 | struct snd_soc_rtdcom_list *rtdcom; | ||
492 | struct snd_soc_component *component; | ||
493 | struct page *page; | ||
494 | |||
495 | for_each_rtdcom(rtd, rtdcom) { | ||
496 | component = rtdcom->component; | ||
497 | |||
498 | /* FIXME. it returns 1st page now */ | ||
499 | if (component->driver->ops && | ||
500 | component->driver->ops->page) { | ||
501 | page = component->driver->ops->page(substream, offset); | ||
502 | if (page) | ||
503 | return page; | ||
504 | } | ||
505 | } | ||
506 | |||
507 | return NULL; | ||
508 | } | ||
509 | |||
510 | int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, | ||
511 | struct vm_area_struct *vma) | ||
512 | { | ||
513 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
514 | struct snd_soc_rtdcom_list *rtdcom; | ||
515 | struct snd_soc_component *component; | ||
516 | |||
517 | for_each_rtdcom(rtd, rtdcom) { | ||
518 | component = rtdcom->component; | ||
519 | |||
520 | /* FIXME. it returns 1st mmap now */ | ||
521 | if (component->driver->ops && | ||
522 | component->driver->ops->mmap) | ||
523 | return component->driver->ops->mmap(substream, vma); | ||
524 | } | ||
525 | |||
526 | return -EINVAL; | ||
527 | } | ||
528 | |||
529 | int snd_soc_pcm_component_new(struct snd_pcm *pcm) | ||
530 | { | ||
531 | struct snd_soc_pcm_runtime *rtd = pcm->private_data; | ||
532 | struct snd_soc_rtdcom_list *rtdcom; | ||
533 | struct snd_soc_component *component; | ||
534 | int ret; | ||
535 | |||
536 | for_each_rtdcom(rtd, rtdcom) { | ||
537 | component = rtdcom->component; | ||
538 | |||
539 | if (component->driver->pcm_new) { | ||
540 | ret = component->driver->pcm_new(rtd); | ||
541 | if (ret < 0) | ||
542 | return ret; | ||
543 | } | ||
544 | } | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | void snd_soc_pcm_component_free(struct snd_pcm *pcm) | ||
550 | { | ||
551 | struct snd_soc_pcm_runtime *rtd = pcm->private_data; | ||
552 | struct snd_soc_rtdcom_list *rtdcom; | ||
553 | struct snd_soc_component *component; | ||
554 | |||
555 | for_each_rtdcom(rtd, rtdcom) { | ||
556 | component = rtdcom->component; | ||
557 | |||
558 | if (component->driver->pcm_free) | ||
559 | component->driver->pcm_free(pcm); | ||
560 | } | ||
561 | } | ||