Commit | Line | Data |
---|---|---|
4ff1fef1 KM |
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 | // | |
4a81e8f3 | 8 | #include <linux/module.h> |
4ff1fef1 KM |
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 | ||
9d415fbf KM |
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 | ||
8e2a990d KM |
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 | ||
7951b146 KM |
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 | ||
4ff1fef1 KM |
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); | |
4a81e8f3 KM |
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 | } | |
ae2f4849 KM |
313 | |
314 | int snd_soc_component_open(struct snd_soc_component *component, | |
315 | struct snd_pcm_substream *substream) | |
316 | { | |
e2cb4a14 KM |
317 | if (component->driver->open) |
318 | return component->driver->open(component, substream); | |
ae2f4849 KM |
319 | return 0; |
320 | } | |
3672beb8 KM |
321 | |
322 | int snd_soc_component_close(struct snd_soc_component *component, | |
323 | struct snd_pcm_substream *substream) | |
324 | { | |
e2cb4a14 KM |
325 | if (component->driver->close) |
326 | return component->driver->close(component, substream); | |
3672beb8 KM |
327 | return 0; |
328 | } | |
6d537233 KM |
329 | |
330 | int snd_soc_component_prepare(struct snd_soc_component *component, | |
331 | struct snd_pcm_substream *substream) | |
332 | { | |
e2cb4a14 KM |
333 | if (component->driver->prepare) |
334 | return component->driver->prepare(component, substream); | |
6d537233 KM |
335 | return 0; |
336 | } | |
245c539a KM |
337 | |
338 | int snd_soc_component_hw_params(struct snd_soc_component *component, | |
339 | struct snd_pcm_substream *substream, | |
340 | struct snd_pcm_hw_params *params) | |
341 | { | |
e2cb4a14 KM |
342 | if (component->driver->hw_params) |
343 | return component->driver->hw_params(component, | |
344 | substream, params); | |
245c539a KM |
345 | return 0; |
346 | } | |
eae7136a KM |
347 | |
348 | int snd_soc_component_hw_free(struct snd_soc_component *component, | |
349 | struct snd_pcm_substream *substream) | |
350 | { | |
e2cb4a14 KM |
351 | if (component->driver->hw_free) |
352 | return component->driver->hw_free(component, substream); | |
eae7136a KM |
353 | return 0; |
354 | } | |
5693d50c KM |
355 | |
356 | int snd_soc_component_trigger(struct snd_soc_component *component, | |
357 | struct snd_pcm_substream *substream, | |
358 | int cmd) | |
359 | { | |
e2cb4a14 KM |
360 | if (component->driver->trigger) |
361 | return component->driver->trigger(component, substream, cmd); | |
5693d50c KM |
362 | return 0; |
363 | } | |
66c51573 KM |
364 | |
365 | void snd_soc_component_suspend(struct snd_soc_component *component) | |
366 | { | |
367 | if (component->driver->suspend) | |
368 | component->driver->suspend(component); | |
369 | component->suspended = 1; | |
370 | } | |
9a840cba KM |
371 | |
372 | void snd_soc_component_resume(struct snd_soc_component *component) | |
373 | { | |
374 | if (component->driver->resume) | |
375 | component->driver->resume(component); | |
376 | component->suspended = 0; | |
377 | } | |
e40fadbc KM |
378 | |
379 | int snd_soc_component_is_suspended(struct snd_soc_component *component) | |
380 | { | |
381 | return component->suspended; | |
382 | } | |
08e837dd KM |
383 | |
384 | int snd_soc_component_probe(struct snd_soc_component *component) | |
385 | { | |
386 | if (component->driver->probe) | |
387 | return component->driver->probe(component); | |
388 | ||
389 | return 0; | |
390 | } | |
03b34dd7 KM |
391 | |
392 | void snd_soc_component_remove(struct snd_soc_component *component) | |
393 | { | |
394 | if (component->driver->remove) | |
395 | component->driver->remove(component); | |
396 | } | |
2c7b1704 KM |
397 | |
398 | int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component, | |
399 | struct device_node *ep) | |
400 | { | |
401 | if (component->driver->of_xlate_dai_id) | |
402 | return component->driver->of_xlate_dai_id(component, ep); | |
403 | ||
404 | return -ENOTSUPP; | |
405 | } | |
a2a34175 KM |
406 | |
407 | int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component, | |
408 | struct of_phandle_args *args, | |
409 | const char **dai_name) | |
410 | { | |
411 | if (component->driver->of_xlate_dai_name) | |
412 | return component->driver->of_xlate_dai_name(component, | |
413 | args, dai_name); | |
414 | return -ENOTSUPP; | |
415 | } | |
0035e256 KM |
416 | |
417 | int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream) | |
418 | { | |
419 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
420 | struct snd_soc_component *component; | |
613fb500 | 421 | int i; |
0035e256 | 422 | |
2b544dd7 | 423 | /* FIXME: use 1st pointer */ |
613fb500 | 424 | for_each_rtd_components(rtd, i, component) |
e2cb4a14 KM |
425 | if (component->driver->pointer) |
426 | return component->driver->pointer(component, substream); | |
0035e256 KM |
427 | |
428 | return 0; | |
429 | } | |
96a47908 KM |
430 | |
431 | int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, | |
432 | unsigned int cmd, void *arg) | |
433 | { | |
434 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
435 | struct snd_soc_component *component; | |
613fb500 | 436 | int i; |
96a47908 | 437 | |
2b544dd7 | 438 | /* FIXME: use 1st ioctl */ |
613fb500 | 439 | for_each_rtd_components(rtd, i, component) |
e2cb4a14 KM |
440 | if (component->driver->ioctl) |
441 | return component->driver->ioctl(component, substream, | |
442 | cmd, arg); | |
96a47908 KM |
443 | |
444 | return snd_pcm_lib_ioctl(substream, cmd, arg); | |
445 | } | |
82d81f5c | 446 | |
1e5ddb6b TI |
447 | int snd_soc_pcm_component_sync_stop(struct snd_pcm_substream *substream) |
448 | { | |
449 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
450 | struct snd_soc_component *component; | |
613fb500 | 451 | int i, ret; |
1e5ddb6b | 452 | |
613fb500 | 453 | for_each_rtd_components(rtd, i, component) { |
f1861a7c | 454 | if (component->driver->sync_stop) { |
1e5ddb6b TI |
455 | ret = component->driver->sync_stop(component, |
456 | substream); | |
457 | if (ret < 0) | |
458 | return ret; | |
459 | } | |
460 | } | |
461 | ||
462 | return 0; | |
463 | } | |
464 | ||
82d81f5c KM |
465 | int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, |
466 | int channel, unsigned long pos, | |
467 | void __user *buf, unsigned long bytes) | |
468 | { | |
469 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
82d81f5c | 470 | struct snd_soc_component *component; |
613fb500 | 471 | int i; |
82d81f5c | 472 | |
2b544dd7 | 473 | /* FIXME. it returns 1st copy now */ |
613fb500 | 474 | for_each_rtd_components(rtd, i, component) |
e2cb4a14 KM |
475 | if (component->driver->copy_user) |
476 | return component->driver->copy_user( | |
477 | component, substream, channel, pos, buf, bytes); | |
82d81f5c KM |
478 | |
479 | return -EINVAL; | |
480 | } | |
9c712e4f KM |
481 | |
482 | struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, | |
483 | unsigned long offset) | |
484 | { | |
485 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
9c712e4f KM |
486 | struct snd_soc_component *component; |
487 | struct page *page; | |
613fb500 | 488 | int i; |
9c712e4f | 489 | |
2b544dd7 | 490 | /* FIXME. it returns 1st page now */ |
613fb500 | 491 | for_each_rtd_components(rtd, i, component) { |
e2cb4a14 KM |
492 | if (component->driver->page) { |
493 | page = component->driver->page(component, | |
494 | substream, offset); | |
495 | if (page) | |
496 | return page; | |
497 | } | |
9c712e4f KM |
498 | } |
499 | ||
500 | return NULL; | |
501 | } | |
205875e1 KM |
502 | |
503 | int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, | |
504 | struct vm_area_struct *vma) | |
505 | { | |
506 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
205875e1 | 507 | struct snd_soc_component *component; |
613fb500 | 508 | int i; |
205875e1 | 509 | |
2b544dd7 | 510 | /* FIXME. it returns 1st mmap now */ |
613fb500 | 511 | for_each_rtd_components(rtd, i, component) |
e2cb4a14 KM |
512 | if (component->driver->mmap) |
513 | return component->driver->mmap(component, | |
514 | substream, vma); | |
205875e1 KM |
515 | |
516 | return -EINVAL; | |
517 | } | |
7484291e | 518 | |
b2b2afbb | 519 | int snd_soc_pcm_component_new(struct snd_soc_pcm_runtime *rtd) |
7484291e | 520 | { |
7484291e KM |
521 | struct snd_soc_component *component; |
522 | int ret; | |
613fb500 | 523 | int i; |
7484291e | 524 | |
613fb500 | 525 | for_each_rtd_components(rtd, i, component) { |
c64bfc90 KM |
526 | if (component->driver->pcm_construct) { |
527 | ret = component->driver->pcm_construct(component, rtd); | |
528 | if (ret < 0) | |
529 | return ret; | |
530 | } | |
7484291e KM |
531 | } |
532 | ||
533 | return 0; | |
534 | } | |
79776da0 | 535 | |
b2b2afbb | 536 | void snd_soc_pcm_component_free(struct snd_soc_pcm_runtime *rtd) |
79776da0 | 537 | { |
79776da0 | 538 | struct snd_soc_component *component; |
613fb500 | 539 | int i; |
79776da0 | 540 | |
8e3366ca TI |
541 | if (!rtd->pcm) |
542 | return; | |
543 | ||
613fb500 | 544 | for_each_rtd_components(rtd, i, component) |
c64bfc90 | 545 | if (component->driver->pcm_destruct) |
b2b2afbb | 546 | component->driver->pcm_destruct(component, rtd->pcm); |
79776da0 | 547 | } |