]>
Commit | Line | Data |
---|---|---|
4ff1fef1 KM |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // | |
3 | // soc-component.c | |
4 | // | |
460b42d1 | 5 | // Copyright 2009-2011 Wolfson Microelectronics PLC. |
4ff1fef1 | 6 | // Copyright (C) 2019 Renesas Electronics Corp. |
460b42d1 KM |
7 | // |
8 | // Mark Brown <broonie@opensource.wolfsonmicro.com> | |
4ff1fef1 KM |
9 | // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> |
10 | // | |
4a81e8f3 | 11 | #include <linux/module.h> |
4ff1fef1 KM |
12 | #include <sound/soc.h> |
13 | ||
e2329eeb KM |
14 | #define soc_component_ret(dai, ret) _soc_component_ret(dai, __func__, ret) |
15 | static inline int _soc_component_ret(struct snd_soc_component *component, | |
16 | const char *func, int ret) | |
17 | { | |
18 | /* Positive/Zero values are not errors */ | |
19 | if (ret >= 0) | |
20 | return ret; | |
21 | ||
22 | /* Negative values might be errors */ | |
23 | switch (ret) { | |
24 | case -EPROBE_DEFER: | |
25 | case -ENOTSUPP: | |
26 | break; | |
27 | default: | |
28 | dev_err(component->dev, | |
29 | "ASoC: error at %s on %s: %d\n", | |
30 | func, component->name, ret); | |
31 | } | |
32 | ||
33 | return ret; | |
34 | } | |
35 | ||
257c4dac KM |
36 | void snd_soc_component_set_aux(struct snd_soc_component *component, |
37 | struct snd_soc_aux_dev *aux) | |
38 | { | |
39 | component->init = (aux) ? aux->init : NULL; | |
40 | } | |
41 | ||
42 | int snd_soc_component_init(struct snd_soc_component *component) | |
43 | { | |
44 | int ret = 0; | |
45 | ||
46 | if (component->init) | |
47 | ret = component->init(component); | |
48 | ||
49 | return soc_component_ret(component, ret); | |
50 | } | |
51 | ||
4ff1fef1 KM |
52 | /** |
53 | * snd_soc_component_set_sysclk - configure COMPONENT system or master clock. | |
54 | * @component: COMPONENT | |
55 | * @clk_id: DAI specific clock ID | |
56 | * @source: Source for the clock | |
57 | * @freq: new clock frequency in Hz | |
58 | * @dir: new clock direction - input/output. | |
59 | * | |
60 | * Configures the CODEC master (MCLK) or system (SYSCLK) clocking. | |
61 | */ | |
62 | int snd_soc_component_set_sysclk(struct snd_soc_component *component, | |
63 | int clk_id, int source, unsigned int freq, | |
64 | int dir) | |
65 | { | |
e2329eeb KM |
66 | int ret = -ENOTSUPP; |
67 | ||
4ff1fef1 | 68 | if (component->driver->set_sysclk) |
e2329eeb | 69 | ret = component->driver->set_sysclk(component, clk_id, source, |
4ff1fef1 KM |
70 | freq, dir); |
71 | ||
e2329eeb | 72 | return soc_component_ret(component, ret); |
4ff1fef1 KM |
73 | } |
74 | EXPORT_SYMBOL_GPL(snd_soc_component_set_sysclk); | |
75 | ||
76 | /* | |
77 | * snd_soc_component_set_pll - configure component PLL. | |
78 | * @component: COMPONENT | |
79 | * @pll_id: DAI specific PLL ID | |
80 | * @source: DAI specific source for the PLL | |
81 | * @freq_in: PLL input clock frequency in Hz | |
82 | * @freq_out: requested PLL output clock frequency in Hz | |
83 | * | |
84 | * Configures and enables PLL to generate output clock based on input clock. | |
85 | */ | |
86 | int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id, | |
87 | int source, unsigned int freq_in, | |
88 | unsigned int freq_out) | |
89 | { | |
e2329eeb KM |
90 | int ret = -EINVAL; |
91 | ||
4ff1fef1 | 92 | if (component->driver->set_pll) |
e2329eeb | 93 | ret = component->driver->set_pll(component, pll_id, source, |
4ff1fef1 KM |
94 | freq_in, freq_out); |
95 | ||
e2329eeb | 96 | return soc_component_ret(component, ret); |
4ff1fef1 KM |
97 | } |
98 | EXPORT_SYMBOL_GPL(snd_soc_component_set_pll); | |
99 | ||
9d415fbf KM |
100 | void snd_soc_component_seq_notifier(struct snd_soc_component *component, |
101 | enum snd_soc_dapm_type type, int subseq) | |
102 | { | |
103 | if (component->driver->seq_notifier) | |
104 | component->driver->seq_notifier(component, type, subseq); | |
105 | } | |
106 | ||
8e2a990d KM |
107 | int snd_soc_component_stream_event(struct snd_soc_component *component, |
108 | int event) | |
109 | { | |
e2329eeb KM |
110 | int ret = 0; |
111 | ||
8e2a990d | 112 | if (component->driver->stream_event) |
e2329eeb | 113 | ret = component->driver->stream_event(component, event); |
8e2a990d | 114 | |
e2329eeb | 115 | return soc_component_ret(component, ret); |
8e2a990d KM |
116 | } |
117 | ||
7951b146 KM |
118 | int snd_soc_component_set_bias_level(struct snd_soc_component *component, |
119 | enum snd_soc_bias_level level) | |
120 | { | |
e2329eeb KM |
121 | int ret = 0; |
122 | ||
7951b146 | 123 | if (component->driver->set_bias_level) |
e2329eeb | 124 | ret = component->driver->set_bias_level(component, level); |
7951b146 | 125 | |
e2329eeb | 126 | return soc_component_ret(component, ret); |
7951b146 KM |
127 | } |
128 | ||
4ca8701e KM |
129 | static int soc_component_pin(struct snd_soc_component *component, |
130 | const char *pin, | |
131 | int (*pin_func)(struct snd_soc_dapm_context *dapm, | |
132 | const char *pin)) | |
4ff1fef1 KM |
133 | { |
134 | struct snd_soc_dapm_context *dapm = | |
135 | snd_soc_component_get_dapm(component); | |
136 | char *full_name; | |
137 | int ret; | |
138 | ||
e2329eeb KM |
139 | if (!component->name_prefix) { |
140 | ret = pin_func(dapm, pin); | |
141 | goto end; | |
142 | } | |
4ff1fef1 KM |
143 | |
144 | full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); | |
e2329eeb KM |
145 | if (!full_name) { |
146 | ret = -ENOMEM; | |
147 | goto end; | |
148 | } | |
4ff1fef1 | 149 | |
4ca8701e | 150 | ret = pin_func(dapm, full_name); |
4ff1fef1 | 151 | kfree(full_name); |
e2329eeb KM |
152 | end: |
153 | return soc_component_ret(component, ret); | |
4ff1fef1 | 154 | } |
4ca8701e KM |
155 | |
156 | int snd_soc_component_enable_pin(struct snd_soc_component *component, | |
157 | const char *pin) | |
158 | { | |
159 | return soc_component_pin(component, pin, snd_soc_dapm_enable_pin); | |
160 | } | |
4ff1fef1 KM |
161 | EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin); |
162 | ||
163 | int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component, | |
164 | const char *pin) | |
165 | { | |
4ca8701e | 166 | return soc_component_pin(component, pin, snd_soc_dapm_enable_pin_unlocked); |
4ff1fef1 KM |
167 | } |
168 | EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin_unlocked); | |
169 | ||
170 | int snd_soc_component_disable_pin(struct snd_soc_component *component, | |
171 | const char *pin) | |
172 | { | |
4ca8701e | 173 | return soc_component_pin(component, pin, snd_soc_dapm_disable_pin); |
4ff1fef1 KM |
174 | } |
175 | EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin); | |
176 | ||
177 | int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component, | |
178 | const char *pin) | |
179 | { | |
4ca8701e | 180 | return soc_component_pin(component, pin, snd_soc_dapm_disable_pin_unlocked); |
4ff1fef1 KM |
181 | } |
182 | EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin_unlocked); | |
183 | ||
184 | int snd_soc_component_nc_pin(struct snd_soc_component *component, | |
185 | const char *pin) | |
186 | { | |
4ca8701e | 187 | return soc_component_pin(component, pin, snd_soc_dapm_nc_pin); |
4ff1fef1 KM |
188 | } |
189 | EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin); | |
190 | ||
191 | int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component, | |
192 | const char *pin) | |
193 | { | |
4ca8701e | 194 | return soc_component_pin(component, pin, snd_soc_dapm_nc_pin_unlocked); |
4ff1fef1 KM |
195 | } |
196 | EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin_unlocked); | |
197 | ||
198 | int snd_soc_component_get_pin_status(struct snd_soc_component *component, | |
199 | const char *pin) | |
200 | { | |
4ca8701e | 201 | return soc_component_pin(component, pin, snd_soc_dapm_get_pin_status); |
4ff1fef1 KM |
202 | } |
203 | EXPORT_SYMBOL_GPL(snd_soc_component_get_pin_status); | |
204 | ||
205 | int snd_soc_component_force_enable_pin(struct snd_soc_component *component, | |
206 | const char *pin) | |
207 | { | |
4ca8701e | 208 | return soc_component_pin(component, pin, snd_soc_dapm_force_enable_pin); |
4ff1fef1 KM |
209 | } |
210 | EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin); | |
211 | ||
212 | int snd_soc_component_force_enable_pin_unlocked( | |
213 | struct snd_soc_component *component, | |
214 | const char *pin) | |
215 | { | |
4ca8701e | 216 | return soc_component_pin(component, pin, snd_soc_dapm_force_enable_pin_unlocked); |
4ff1fef1 KM |
217 | } |
218 | EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin_unlocked); | |
219 | ||
220 | /** | |
221 | * snd_soc_component_set_jack - configure component jack. | |
222 | * @component: COMPONENTs | |
223 | * @jack: structure to use for the jack | |
224 | * @data: can be used if codec driver need extra data for configuring jack | |
225 | * | |
226 | * Configures and enables jack detection function. | |
227 | */ | |
228 | int snd_soc_component_set_jack(struct snd_soc_component *component, | |
229 | struct snd_soc_jack *jack, void *data) | |
230 | { | |
e2329eeb KM |
231 | int ret = -ENOTSUPP; |
232 | ||
4ff1fef1 | 233 | if (component->driver->set_jack) |
e2329eeb | 234 | ret = component->driver->set_jack(component, jack, data); |
4ff1fef1 | 235 | |
e2329eeb | 236 | return soc_component_ret(component, ret); |
4ff1fef1 KM |
237 | } |
238 | EXPORT_SYMBOL_GPL(snd_soc_component_set_jack); | |
4a81e8f3 KM |
239 | |
240 | int snd_soc_component_module_get(struct snd_soc_component *component, | |
241 | int upon_open) | |
242 | { | |
e2329eeb KM |
243 | int ret = 0; |
244 | ||
4a81e8f3 KM |
245 | if (component->driver->module_get_upon_open == !!upon_open && |
246 | !try_module_get(component->dev->driver->owner)) | |
e2329eeb | 247 | ret = -ENODEV; |
4a81e8f3 | 248 | |
e2329eeb | 249 | return soc_component_ret(component, ret); |
4a81e8f3 KM |
250 | } |
251 | ||
252 | void snd_soc_component_module_put(struct snd_soc_component *component, | |
253 | int upon_open) | |
254 | { | |
255 | if (component->driver->module_get_upon_open == !!upon_open) | |
256 | module_put(component->dev->driver->owner); | |
257 | } | |
ae2f4849 KM |
258 | |
259 | int snd_soc_component_open(struct snd_soc_component *component, | |
260 | struct snd_pcm_substream *substream) | |
261 | { | |
e2329eeb KM |
262 | int ret = 0; |
263 | ||
e2cb4a14 | 264 | if (component->driver->open) |
e2329eeb KM |
265 | ret = component->driver->open(component, substream); |
266 | ||
267 | return soc_component_ret(component, ret); | |
ae2f4849 | 268 | } |
3672beb8 KM |
269 | |
270 | int snd_soc_component_close(struct snd_soc_component *component, | |
271 | struct snd_pcm_substream *substream) | |
272 | { | |
e2329eeb KM |
273 | int ret = 0; |
274 | ||
e2cb4a14 | 275 | if (component->driver->close) |
e2329eeb KM |
276 | ret = component->driver->close(component, substream); |
277 | ||
278 | return soc_component_ret(component, ret); | |
3672beb8 | 279 | } |
6d537233 | 280 | |
66c51573 KM |
281 | void snd_soc_component_suspend(struct snd_soc_component *component) |
282 | { | |
283 | if (component->driver->suspend) | |
284 | component->driver->suspend(component); | |
285 | component->suspended = 1; | |
286 | } | |
9a840cba KM |
287 | |
288 | void snd_soc_component_resume(struct snd_soc_component *component) | |
289 | { | |
290 | if (component->driver->resume) | |
291 | component->driver->resume(component); | |
292 | component->suspended = 0; | |
293 | } | |
e40fadbc KM |
294 | |
295 | int snd_soc_component_is_suspended(struct snd_soc_component *component) | |
296 | { | |
297 | return component->suspended; | |
298 | } | |
08e837dd KM |
299 | |
300 | int snd_soc_component_probe(struct snd_soc_component *component) | |
301 | { | |
e2329eeb KM |
302 | int ret = 0; |
303 | ||
08e837dd | 304 | if (component->driver->probe) |
e2329eeb | 305 | ret = component->driver->probe(component); |
08e837dd | 306 | |
e2329eeb | 307 | return soc_component_ret(component, ret); |
08e837dd | 308 | } |
03b34dd7 KM |
309 | |
310 | void snd_soc_component_remove(struct snd_soc_component *component) | |
311 | { | |
312 | if (component->driver->remove) | |
313 | component->driver->remove(component); | |
314 | } | |
2c7b1704 KM |
315 | |
316 | int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component, | |
317 | struct device_node *ep) | |
318 | { | |
e2329eeb KM |
319 | int ret = -ENOTSUPP; |
320 | ||
2c7b1704 | 321 | if (component->driver->of_xlate_dai_id) |
e2329eeb | 322 | ret = component->driver->of_xlate_dai_id(component, ep); |
2c7b1704 | 323 | |
e2329eeb | 324 | return soc_component_ret(component, ret); |
2c7b1704 | 325 | } |
a2a34175 KM |
326 | |
327 | int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component, | |
328 | struct of_phandle_args *args, | |
329 | const char **dai_name) | |
330 | { | |
331 | if (component->driver->of_xlate_dai_name) | |
cc4d8ceb JB |
332 | return component->driver->of_xlate_dai_name(component, |
333 | args, dai_name); | |
334 | /* | |
335 | * Don't use soc_component_ret here because we may not want to report | |
336 | * the error just yet. If a device has more than one component, the | |
337 | * first may not match and we don't want spam the log with this. | |
338 | */ | |
339 | return -ENOTSUPP; | |
a2a34175 | 340 | } |
0035e256 | 341 | |
c7d75b59 KM |
342 | void snd_soc_component_setup_regmap(struct snd_soc_component *component) |
343 | { | |
344 | int val_bytes = regmap_get_val_bytes(component->regmap); | |
345 | ||
346 | /* Errors are legitimate for non-integer byte multiples */ | |
347 | if (val_bytes > 0) | |
348 | component->val_bytes = val_bytes; | |
349 | } | |
350 | ||
351 | #ifdef CONFIG_REGMAP | |
352 | ||
353 | /** | |
354 | * snd_soc_component_init_regmap() - Initialize regmap instance for the | |
355 | * component | |
356 | * @component: The component for which to initialize the regmap instance | |
357 | * @regmap: The regmap instance that should be used by the component | |
358 | * | |
359 | * This function allows deferred assignment of the regmap instance that is | |
360 | * associated with the component. Only use this if the regmap instance is not | |
361 | * yet ready when the component is registered. The function must also be called | |
362 | * before the first IO attempt of the component. | |
363 | */ | |
364 | void snd_soc_component_init_regmap(struct snd_soc_component *component, | |
365 | struct regmap *regmap) | |
366 | { | |
367 | component->regmap = regmap; | |
368 | snd_soc_component_setup_regmap(component); | |
369 | } | |
370 | EXPORT_SYMBOL_GPL(snd_soc_component_init_regmap); | |
371 | ||
372 | /** | |
373 | * snd_soc_component_exit_regmap() - De-initialize regmap instance for the | |
374 | * component | |
375 | * @component: The component for which to de-initialize the regmap instance | |
376 | * | |
377 | * Calls regmap_exit() on the regmap instance associated to the component and | |
378 | * removes the regmap instance from the component. | |
379 | * | |
380 | * This function should only be used if snd_soc_component_init_regmap() was used | |
381 | * to initialize the regmap instance. | |
382 | */ | |
383 | void snd_soc_component_exit_regmap(struct snd_soc_component *component) | |
384 | { | |
385 | regmap_exit(component->regmap); | |
386 | component->regmap = NULL; | |
387 | } | |
388 | EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap); | |
389 | ||
390 | #endif | |
391 | ||
e8712315 KM |
392 | static unsigned int soc_component_read_no_lock( |
393 | struct snd_soc_component *component, | |
394 | unsigned int reg) | |
460b42d1 KM |
395 | { |
396 | int ret; | |
cf6e26c7 | 397 | unsigned int val = 0; |
460b42d1 KM |
398 | |
399 | if (component->regmap) | |
cf6e26c7 | 400 | ret = regmap_read(component->regmap, reg, &val); |
460b42d1 | 401 | else if (component->driver->read) { |
460b42d1 | 402 | ret = 0; |
cf6e26c7 | 403 | val = component->driver->read(component, reg); |
460b42d1 KM |
404 | } |
405 | else | |
406 | ret = -EIO; | |
407 | ||
460b42d1 | 408 | if (ret < 0) |
efc913c8 | 409 | return soc_component_ret(component, ret); |
460b42d1 KM |
410 | |
411 | return val; | |
412 | } | |
e8712315 KM |
413 | |
414 | /** | |
415 | * snd_soc_component_read() - Read register value | |
416 | * @component: Component to read from | |
417 | * @reg: Register to read | |
418 | * | |
419 | * Return: read value | |
420 | */ | |
421 | unsigned int snd_soc_component_read(struct snd_soc_component *component, | |
422 | unsigned int reg) | |
423 | { | |
424 | unsigned int val; | |
425 | ||
426 | mutex_lock(&component->io_mutex); | |
427 | val = soc_component_read_no_lock(component, reg); | |
428 | mutex_unlock(&component->io_mutex); | |
429 | ||
430 | return val; | |
431 | } | |
cf6e26c7 | 432 | EXPORT_SYMBOL_GPL(snd_soc_component_read); |
460b42d1 | 433 | |
e8712315 KM |
434 | static int soc_component_write_no_lock( |
435 | struct snd_soc_component *component, | |
436 | unsigned int reg, unsigned int val) | |
437 | { | |
438 | int ret = -EIO; | |
439 | ||
440 | if (component->regmap) | |
441 | ret = regmap_write(component->regmap, reg, val); | |
442 | else if (component->driver->write) | |
443 | ret = component->driver->write(component, reg, val); | |
444 | ||
445 | return soc_component_ret(component, ret); | |
446 | } | |
447 | ||
460b42d1 KM |
448 | /** |
449 | * snd_soc_component_write() - Write register value | |
450 | * @component: Component to write to | |
451 | * @reg: Register to write | |
452 | * @val: Value to write to the register | |
453 | * | |
454 | * Return: 0 on success, a negative error code otherwise. | |
455 | */ | |
456 | int snd_soc_component_write(struct snd_soc_component *component, | |
457 | unsigned int reg, unsigned int val) | |
458 | { | |
e8712315 | 459 | int ret; |
460b42d1 | 460 | |
e8712315 KM |
461 | mutex_lock(&component->io_mutex); |
462 | ret = soc_component_write_no_lock(component, reg, val); | |
463 | mutex_unlock(&component->io_mutex); | |
460b42d1 | 464 | |
e8712315 | 465 | return ret; |
460b42d1 KM |
466 | } |
467 | EXPORT_SYMBOL_GPL(snd_soc_component_write); | |
468 | ||
469 | static int snd_soc_component_update_bits_legacy( | |
470 | struct snd_soc_component *component, unsigned int reg, | |
471 | unsigned int mask, unsigned int val, bool *change) | |
472 | { | |
473 | unsigned int old, new; | |
cf6e26c7 | 474 | int ret = 0; |
460b42d1 KM |
475 | |
476 | mutex_lock(&component->io_mutex); | |
477 | ||
e8712315 | 478 | old = soc_component_read_no_lock(component, reg); |
460b42d1 KM |
479 | |
480 | new = (old & ~mask) | (val & mask); | |
481 | *change = old != new; | |
482 | if (*change) | |
e8712315 | 483 | ret = soc_component_write_no_lock(component, reg, new); |
cf6e26c7 | 484 | |
460b42d1 KM |
485 | mutex_unlock(&component->io_mutex); |
486 | ||
487 | return soc_component_ret(component, ret); | |
488 | } | |
489 | ||
490 | /** | |
491 | * snd_soc_component_update_bits() - Perform read/modify/write cycle | |
492 | * @component: Component to update | |
493 | * @reg: Register to update | |
494 | * @mask: Mask that specifies which bits to update | |
495 | * @val: New value for the bits specified by mask | |
496 | * | |
497 | * Return: 1 if the operation was successful and the value of the register | |
498 | * changed, 0 if the operation was successful, but the value did not change. | |
499 | * Returns a negative error code otherwise. | |
500 | */ | |
501 | int snd_soc_component_update_bits(struct snd_soc_component *component, | |
502 | unsigned int reg, unsigned int mask, unsigned int val) | |
503 | { | |
504 | bool change; | |
505 | int ret; | |
506 | ||
507 | if (component->regmap) | |
508 | ret = regmap_update_bits_check(component->regmap, reg, mask, | |
509 | val, &change); | |
510 | else | |
511 | ret = snd_soc_component_update_bits_legacy(component, reg, | |
512 | mask, val, &change); | |
513 | ||
514 | if (ret < 0) | |
515 | return soc_component_ret(component, ret); | |
516 | return change; | |
517 | } | |
518 | EXPORT_SYMBOL_GPL(snd_soc_component_update_bits); | |
519 | ||
520 | /** | |
521 | * snd_soc_component_update_bits_async() - Perform asynchronous | |
522 | * read/modify/write cycle | |
523 | * @component: Component to update | |
524 | * @reg: Register to update | |
525 | * @mask: Mask that specifies which bits to update | |
526 | * @val: New value for the bits specified by mask | |
527 | * | |
528 | * This function is similar to snd_soc_component_update_bits(), but the update | |
529 | * operation is scheduled asynchronously. This means it may not be completed | |
530 | * when the function returns. To make sure that all scheduled updates have been | |
531 | * completed snd_soc_component_async_complete() must be called. | |
532 | * | |
533 | * Return: 1 if the operation was successful and the value of the register | |
534 | * changed, 0 if the operation was successful, but the value did not change. | |
535 | * Returns a negative error code otherwise. | |
536 | */ | |
537 | int snd_soc_component_update_bits_async(struct snd_soc_component *component, | |
538 | unsigned int reg, unsigned int mask, unsigned int val) | |
539 | { | |
540 | bool change; | |
541 | int ret; | |
542 | ||
543 | if (component->regmap) | |
544 | ret = regmap_update_bits_check_async(component->regmap, reg, | |
545 | mask, val, &change); | |
546 | else | |
547 | ret = snd_soc_component_update_bits_legacy(component, reg, | |
548 | mask, val, &change); | |
549 | ||
550 | if (ret < 0) | |
551 | return soc_component_ret(component, ret); | |
552 | return change; | |
553 | } | |
554 | EXPORT_SYMBOL_GPL(snd_soc_component_update_bits_async); | |
555 | ||
556 | /** | |
557 | * snd_soc_component_async_complete() - Ensure asynchronous I/O has completed | |
558 | * @component: Component for which to wait | |
559 | * | |
560 | * This function blocks until all asynchronous I/O which has previously been | |
561 | * scheduled using snd_soc_component_update_bits_async() has completed. | |
562 | */ | |
563 | void snd_soc_component_async_complete(struct snd_soc_component *component) | |
564 | { | |
565 | if (component->regmap) | |
566 | regmap_async_complete(component->regmap); | |
567 | } | |
568 | EXPORT_SYMBOL_GPL(snd_soc_component_async_complete); | |
569 | ||
570 | /** | |
571 | * snd_soc_component_test_bits - Test register for change | |
572 | * @component: component | |
573 | * @reg: Register to test | |
574 | * @mask: Mask that specifies which bits to test | |
575 | * @value: Value to test against | |
576 | * | |
577 | * Tests a register with a new value and checks if the new value is | |
578 | * different from the old value. | |
579 | * | |
580 | * Return: 1 for change, otherwise 0. | |
581 | */ | |
582 | int snd_soc_component_test_bits(struct snd_soc_component *component, | |
583 | unsigned int reg, unsigned int mask, unsigned int value) | |
584 | { | |
585 | unsigned int old, new; | |
460b42d1 | 586 | |
cf6e26c7 | 587 | old = snd_soc_component_read(component, reg); |
460b42d1 KM |
588 | new = (old & ~mask) | value; |
589 | return old != new; | |
590 | } | |
591 | EXPORT_SYMBOL_GPL(snd_soc_component_test_bits); | |
592 | ||
0035e256 KM |
593 | int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream) |
594 | { | |
0ceef681 | 595 | struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
0035e256 | 596 | struct snd_soc_component *component; |
613fb500 | 597 | int i; |
0035e256 | 598 | |
2b544dd7 | 599 | /* FIXME: use 1st pointer */ |
613fb500 | 600 | for_each_rtd_components(rtd, i, component) |
e2cb4a14 KM |
601 | if (component->driver->pointer) |
602 | return component->driver->pointer(component, substream); | |
0035e256 KM |
603 | |
604 | return 0; | |
605 | } | |
96a47908 KM |
606 | |
607 | int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, | |
608 | unsigned int cmd, void *arg) | |
609 | { | |
0ceef681 | 610 | struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
96a47908 | 611 | struct snd_soc_component *component; |
613fb500 | 612 | int i; |
96a47908 | 613 | |
2b544dd7 | 614 | /* FIXME: use 1st ioctl */ |
613fb500 | 615 | for_each_rtd_components(rtd, i, component) |
e2cb4a14 | 616 | if (component->driver->ioctl) |
e2329eeb KM |
617 | return soc_component_ret( |
618 | component, | |
619 | component->driver->ioctl(component, | |
620 | substream, cmd, arg)); | |
96a47908 KM |
621 | |
622 | return snd_pcm_lib_ioctl(substream, cmd, arg); | |
623 | } | |
82d81f5c | 624 | |
1e5ddb6b TI |
625 | int snd_soc_pcm_component_sync_stop(struct snd_pcm_substream *substream) |
626 | { | |
0ceef681 | 627 | struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
1e5ddb6b | 628 | struct snd_soc_component *component; |
613fb500 | 629 | int i, ret; |
1e5ddb6b | 630 | |
613fb500 | 631 | for_each_rtd_components(rtd, i, component) { |
f1861a7c | 632 | if (component->driver->sync_stop) { |
1e5ddb6b TI |
633 | ret = component->driver->sync_stop(component, |
634 | substream); | |
635 | if (ret < 0) | |
be75db57 | 636 | return soc_component_ret(component, ret); |
1e5ddb6b TI |
637 | } |
638 | } | |
639 | ||
640 | return 0; | |
641 | } | |
642 | ||
82d81f5c KM |
643 | int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, |
644 | int channel, unsigned long pos, | |
645 | void __user *buf, unsigned long bytes) | |
646 | { | |
0ceef681 | 647 | struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
82d81f5c | 648 | struct snd_soc_component *component; |
613fb500 | 649 | int i; |
82d81f5c | 650 | |
2b544dd7 | 651 | /* FIXME. it returns 1st copy now */ |
613fb500 | 652 | for_each_rtd_components(rtd, i, component) |
e2cb4a14 | 653 | if (component->driver->copy_user) |
e2329eeb KM |
654 | return soc_component_ret( |
655 | component, | |
656 | component->driver->copy_user( | |
657 | component, substream, channel, | |
658 | pos, buf, bytes)); | |
82d81f5c KM |
659 | |
660 | return -EINVAL; | |
661 | } | |
9c712e4f KM |
662 | |
663 | struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, | |
664 | unsigned long offset) | |
665 | { | |
0ceef681 | 666 | struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
9c712e4f KM |
667 | struct snd_soc_component *component; |
668 | struct page *page; | |
613fb500 | 669 | int i; |
9c712e4f | 670 | |
2b544dd7 | 671 | /* FIXME. it returns 1st page now */ |
613fb500 | 672 | for_each_rtd_components(rtd, i, component) { |
e2cb4a14 KM |
673 | if (component->driver->page) { |
674 | page = component->driver->page(component, | |
675 | substream, offset); | |
676 | if (page) | |
677 | return page; | |
678 | } | |
9c712e4f KM |
679 | } |
680 | ||
681 | return NULL; | |
682 | } | |
205875e1 KM |
683 | |
684 | int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, | |
685 | struct vm_area_struct *vma) | |
686 | { | |
0ceef681 | 687 | struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
205875e1 | 688 | struct snd_soc_component *component; |
613fb500 | 689 | int i; |
205875e1 | 690 | |
2b544dd7 | 691 | /* FIXME. it returns 1st mmap now */ |
613fb500 | 692 | for_each_rtd_components(rtd, i, component) |
e2cb4a14 | 693 | if (component->driver->mmap) |
be75db57 | 694 | return soc_component_ret( |
e2329eeb KM |
695 | component, |
696 | component->driver->mmap(component, | |
697 | substream, vma)); | |
205875e1 KM |
698 | |
699 | return -EINVAL; | |
700 | } | |
7484291e | 701 | |
b2b2afbb | 702 | int snd_soc_pcm_component_new(struct snd_soc_pcm_runtime *rtd) |
7484291e | 703 | { |
7484291e KM |
704 | struct snd_soc_component *component; |
705 | int ret; | |
613fb500 | 706 | int i; |
7484291e | 707 | |
613fb500 | 708 | for_each_rtd_components(rtd, i, component) { |
c64bfc90 KM |
709 | if (component->driver->pcm_construct) { |
710 | ret = component->driver->pcm_construct(component, rtd); | |
711 | if (ret < 0) | |
be75db57 | 712 | return soc_component_ret(component, ret); |
c64bfc90 | 713 | } |
7484291e KM |
714 | } |
715 | ||
716 | return 0; | |
717 | } | |
79776da0 | 718 | |
b2b2afbb | 719 | void snd_soc_pcm_component_free(struct snd_soc_pcm_runtime *rtd) |
79776da0 | 720 | { |
79776da0 | 721 | struct snd_soc_component *component; |
613fb500 | 722 | int i; |
79776da0 | 723 | |
8e3366ca TI |
724 | if (!rtd->pcm) |
725 | return; | |
726 | ||
613fb500 | 727 | for_each_rtd_components(rtd, i, component) |
c64bfc90 | 728 | if (component->driver->pcm_destruct) |
b2b2afbb | 729 | component->driver->pcm_destruct(component, rtd->pcm); |
79776da0 | 730 | } |
4f39514f KM |
731 | |
732 | int snd_soc_pcm_component_prepare(struct snd_pcm_substream *substream) | |
733 | { | |
0ceef681 | 734 | struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
4f39514f KM |
735 | struct snd_soc_component *component; |
736 | int i, ret; | |
737 | ||
738 | for_each_rtd_components(rtd, i, component) { | |
739 | if (component->driver->prepare) { | |
740 | ret = component->driver->prepare(component, substream); | |
741 | if (ret < 0) | |
742 | return soc_component_ret(component, ret); | |
743 | } | |
744 | } | |
745 | ||
746 | return 0; | |
747 | } | |
e1bafa82 KM |
748 | |
749 | int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream, | |
750 | struct snd_pcm_hw_params *params, | |
751 | struct snd_soc_component **last) | |
752 | { | |
0ceef681 | 753 | struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
e1bafa82 KM |
754 | struct snd_soc_component *component; |
755 | int i, ret; | |
756 | ||
757 | for_each_rtd_components(rtd, i, component) { | |
758 | if (component->driver->hw_params) { | |
759 | ret = component->driver->hw_params(component, | |
760 | substream, params); | |
761 | if (ret < 0) { | |
762 | *last = component; | |
763 | return soc_component_ret(component, ret); | |
764 | } | |
765 | } | |
766 | } | |
767 | ||
768 | *last = NULL; | |
769 | return 0; | |
770 | } | |
04751119 KM |
771 | |
772 | void snd_soc_pcm_component_hw_free(struct snd_pcm_substream *substream, | |
773 | struct snd_soc_component *last) | |
774 | { | |
0ceef681 | 775 | struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
04751119 KM |
776 | struct snd_soc_component *component; |
777 | int i, ret; | |
778 | ||
779 | for_each_rtd_components(rtd, i, component) { | |
780 | if (component == last) | |
781 | break; | |
782 | ||
783 | if (component->driver->hw_free) { | |
784 | ret = component->driver->hw_free(component, substream); | |
785 | if (ret < 0) | |
786 | soc_component_ret(component, ret); | |
787 | } | |
788 | } | |
789 | } | |
32fd1204 KM |
790 | |
791 | int snd_soc_pcm_component_trigger(struct snd_pcm_substream *substream, | |
792 | int cmd) | |
793 | { | |
0ceef681 | 794 | struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
32fd1204 KM |
795 | struct snd_soc_component *component; |
796 | int i, ret; | |
797 | ||
798 | for_each_rtd_components(rtd, i, component) { | |
799 | if (component->driver->trigger) { | |
800 | ret = component->driver->trigger(component, substream, cmd); | |
801 | if (ret < 0) | |
802 | return soc_component_ret(component, ret); | |
803 | } | |
804 | } | |
805 | ||
806 | return 0; | |
807 | } |