]>
Commit | Line | Data |
---|---|---|
873486ed KM |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // | |
3 | // soc-core.c -- ALSA SoC Audio Layer | |
4 | // | |
5 | // Copyright 2005 Wolfson Microelectronics PLC. | |
6 | // Copyright 2005 Openedhand Ltd. | |
7 | // Copyright (C) 2010 Slimlogic Ltd. | |
8 | // Copyright (C) 2010 Texas Instruments Inc. | |
9 | // | |
10 | // Author: Liam Girdwood <[email protected]> | |
11 | // with code, comments and ideas from :- | |
12 | // Richard Purdie <[email protected]> | |
13 | // | |
14 | // TODO: | |
15 | // o Add hw rules to enforce rates, etc. | |
16 | // o More testing with other codecs/machines. | |
17 | // o Add more codecs and platforms to ensure good API coverage. | |
18 | // o Support TDM on PCM and I2S | |
db2a4165 FM |
19 | |
20 | #include <linux/module.h> | |
21 | #include <linux/moduleparam.h> | |
22 | #include <linux/init.h> | |
23 | #include <linux/delay.h> | |
24 | #include <linux/pm.h> | |
25 | #include <linux/bitops.h> | |
12ef193d | 26 | #include <linux/debugfs.h> |
db2a4165 | 27 | #include <linux/platform_device.h> |
741a509f | 28 | #include <linux/pinctrl/consumer.h> |
f0e8ed85 | 29 | #include <linux/ctype.h> |
5a0e3ad6 | 30 | #include <linux/slab.h> |
bec4fa05 | 31 | #include <linux/of.h> |
a180e8b9 | 32 | #include <linux/of_graph.h> |
345233d7 | 33 | #include <linux/dmi.h> |
db2a4165 | 34 | #include <sound/core.h> |
3028eb8c | 35 | #include <sound/jack.h> |
db2a4165 FM |
36 | #include <sound/pcm.h> |
37 | #include <sound/pcm_params.h> | |
38 | #include <sound/soc.h> | |
01d7584c | 39 | #include <sound/soc-dpcm.h> |
8a978234 | 40 | #include <sound/soc-topology.h> |
db2a4165 FM |
41 | #include <sound/initval.h> |
42 | ||
a8b1d34f MB |
43 | #define CREATE_TRACE_POINTS |
44 | #include <trace/events/asoc.h> | |
45 | ||
f0fba2ad LG |
46 | #define NAME_SIZE 32 |
47 | ||
384c89e2 | 48 | #ifdef CONFIG_DEBUG_FS |
8a9dab1a MB |
49 | struct dentry *snd_soc_debugfs_root; |
50 | EXPORT_SYMBOL_GPL(snd_soc_debugfs_root); | |
384c89e2 MB |
51 | #endif |
52 | ||
c5af3a2e | 53 | static DEFINE_MUTEX(client_mutex); |
030e79f6 | 54 | static LIST_HEAD(component_list); |
e894efef | 55 | static LIST_HEAD(unbind_card_list); |
c5af3a2e | 56 | |
368dee94 KM |
57 | #define for_each_component(component) \ |
58 | list_for_each_entry(component, &component_list, list) | |
59 | ||
db2a4165 FM |
60 | /* |
61 | * This is a timeout to do a DAPM powerdown after a stream is closed(). | |
62 | * It can be used to eliminate pops between different playback streams, e.g. | |
63 | * between two audio tracks. | |
64 | */ | |
65 | static int pmdown_time = 5000; | |
66 | module_param(pmdown_time, int, 0); | |
67 | MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); | |
68 | ||
2c7b696a MZ |
69 | /* |
70 | * If a DMI filed contain strings in this blacklist (e.g. | |
71 | * "Type2 - Board Manufacturer" or "Type1 - TBD by OEM"), it will be taken | |
98faf436 ML |
72 | * as invalid and dropped when setting the card long name from DMI info. |
73 | */ | |
74 | static const char * const dmi_blacklist[] = { | |
75 | "To be filled by OEM", | |
76 | "TBD by OEM", | |
77 | "Default String", | |
78 | "Board Manufacturer", | |
79 | "Board Vendor Name", | |
80 | "Board Product Name", | |
81 | NULL, /* terminator */ | |
82 | }; | |
83 | ||
dbe21408 MB |
84 | static ssize_t pmdown_time_show(struct device *dev, |
85 | struct device_attribute *attr, char *buf) | |
86 | { | |
36ae1a96 | 87 | struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); |
dbe21408 | 88 | |
f0fba2ad | 89 | return sprintf(buf, "%ld\n", rtd->pmdown_time); |
dbe21408 MB |
90 | } |
91 | ||
92 | static ssize_t pmdown_time_set(struct device *dev, | |
93 | struct device_attribute *attr, | |
94 | const char *buf, size_t count) | |
95 | { | |
36ae1a96 | 96 | struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); |
c593b520 | 97 | int ret; |
dbe21408 | 98 | |
b785a492 | 99 | ret = kstrtol(buf, 10, &rtd->pmdown_time); |
c593b520 MB |
100 | if (ret) |
101 | return ret; | |
dbe21408 MB |
102 | |
103 | return count; | |
104 | } | |
105 | ||
106 | static DEVICE_ATTR(pmdown_time, 0644, pmdown_time_show, pmdown_time_set); | |
107 | ||
d29697dc | 108 | static struct attribute *soc_dev_attrs[] = { |
d29697dc TI |
109 | &dev_attr_pmdown_time.attr, |
110 | NULL | |
111 | }; | |
112 | ||
113 | static umode_t soc_dev_attr_is_visible(struct kobject *kobj, | |
114 | struct attribute *attr, int idx) | |
115 | { | |
116 | struct device *dev = kobj_to_dev(kobj); | |
117 | struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); | |
118 | ||
119 | if (attr == &dev_attr_pmdown_time.attr) | |
120 | return attr->mode; /* always visible */ | |
3b6eed8d | 121 | return rtd->num_codecs ? attr->mode : 0; /* enabled only with codec */ |
d29697dc TI |
122 | } |
123 | ||
124 | static const struct attribute_group soc_dapm_dev_group = { | |
125 | .attrs = soc_dapm_dev_attrs, | |
126 | .is_visible = soc_dev_attr_is_visible, | |
127 | }; | |
128 | ||
f7e73b26 | 129 | static const struct attribute_group soc_dev_group = { |
d29697dc TI |
130 | .attrs = soc_dev_attrs, |
131 | .is_visible = soc_dev_attr_is_visible, | |
132 | }; | |
133 | ||
134 | static const struct attribute_group *soc_dev_attr_groups[] = { | |
135 | &soc_dapm_dev_group, | |
f7e73b26 | 136 | &soc_dev_group, |
d29697dc TI |
137 | NULL |
138 | }; | |
139 | ||
2624d5fa | 140 | #ifdef CONFIG_DEBUG_FS |
81c7cfd1 | 141 | static void soc_init_component_debugfs(struct snd_soc_component *component) |
e73f3de5 | 142 | { |
6553bf06 LPC |
143 | if (!component->card->debugfs_card_root) |
144 | return; | |
145 | ||
81c7cfd1 LPC |
146 | if (component->debugfs_prefix) { |
147 | char *name; | |
e73f3de5 | 148 | |
81c7cfd1 LPC |
149 | name = kasprintf(GFP_KERNEL, "%s:%s", |
150 | component->debugfs_prefix, component->name); | |
151 | if (name) { | |
152 | component->debugfs_root = debugfs_create_dir(name, | |
153 | component->card->debugfs_card_root); | |
154 | kfree(name); | |
155 | } | |
156 | } else { | |
157 | component->debugfs_root = debugfs_create_dir(component->name, | |
158 | component->card->debugfs_card_root); | |
159 | } | |
e73f3de5 | 160 | |
81c7cfd1 LPC |
161 | if (!component->debugfs_root) { |
162 | dev_warn(component->dev, | |
163 | "ASoC: Failed to create component debugfs directory\n"); | |
164 | return; | |
165 | } | |
e73f3de5 | 166 | |
81c7cfd1 LPC |
167 | snd_soc_dapm_debugfs_init(snd_soc_component_get_dapm(component), |
168 | component->debugfs_root); | |
e73f3de5 RK |
169 | } |
170 | ||
81c7cfd1 | 171 | static void soc_cleanup_component_debugfs(struct snd_soc_component *component) |
2624d5fa | 172 | { |
81c7cfd1 LPC |
173 | debugfs_remove_recursive(component->debugfs_root); |
174 | } | |
d6ce4cf3 | 175 | |
c15b2a1d | 176 | static int dai_list_show(struct seq_file *m, void *v) |
f3208780 | 177 | { |
1438c2f6 | 178 | struct snd_soc_component *component; |
f3208780 MB |
179 | struct snd_soc_dai *dai; |
180 | ||
34e81ab4 LPC |
181 | mutex_lock(&client_mutex); |
182 | ||
368dee94 | 183 | for_each_component(component) |
15a0c645 | 184 | for_each_component_dais(component, dai) |
700c17ca | 185 | seq_printf(m, "%s\n", dai->name); |
f3208780 | 186 | |
34e81ab4 LPC |
187 | mutex_unlock(&client_mutex); |
188 | ||
700c17ca DP |
189 | return 0; |
190 | } | |
c15b2a1d | 191 | DEFINE_SHOW_ATTRIBUTE(dai_list); |
f3208780 | 192 | |
db795f9b KM |
193 | static int component_list_show(struct seq_file *m, void *v) |
194 | { | |
195 | struct snd_soc_component *component; | |
196 | ||
197 | mutex_lock(&client_mutex); | |
198 | ||
368dee94 | 199 | for_each_component(component) |
db795f9b KM |
200 | seq_printf(m, "%s\n", component->name); |
201 | ||
202 | mutex_unlock(&client_mutex); | |
203 | ||
204 | return 0; | |
205 | } | |
206 | DEFINE_SHOW_ATTRIBUTE(component_list); | |
207 | ||
a6052154 JN |
208 | static void soc_init_card_debugfs(struct snd_soc_card *card) |
209 | { | |
6553bf06 LPC |
210 | if (!snd_soc_debugfs_root) |
211 | return; | |
212 | ||
a6052154 | 213 | card->debugfs_card_root = debugfs_create_dir(card->name, |
8a9dab1a | 214 | snd_soc_debugfs_root); |
3a45b867 | 215 | if (!card->debugfs_card_root) { |
a6052154 | 216 | dev_warn(card->dev, |
7c08be84 | 217 | "ASoC: Failed to create card debugfs directory\n"); |
3a45b867 JN |
218 | return; |
219 | } | |
220 | ||
221 | card->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0644, | |
222 | card->debugfs_card_root, | |
223 | &card->pop_time); | |
224 | if (!card->debugfs_pop_time) | |
225 | dev_warn(card->dev, | |
2c7b696a | 226 | "ASoC: Failed to create pop time debugfs file\n"); |
a6052154 JN |
227 | } |
228 | ||
229 | static void soc_cleanup_card_debugfs(struct snd_soc_card *card) | |
230 | { | |
231 | debugfs_remove_recursive(card->debugfs_card_root); | |
232 | } | |
233 | ||
6553bf06 LPC |
234 | static void snd_soc_debugfs_init(void) |
235 | { | |
236 | snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL); | |
d9a02c55 | 237 | if (IS_ERR_OR_NULL(snd_soc_debugfs_root)) { |
6553bf06 LPC |
238 | pr_warn("ASoC: Failed to create debugfs directory\n"); |
239 | snd_soc_debugfs_root = NULL; | |
240 | return; | |
241 | } | |
242 | ||
6553bf06 LPC |
243 | if (!debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL, |
244 | &dai_list_fops)) | |
245 | pr_warn("ASoC: Failed to create DAI list debugfs file\n"); | |
db795f9b KM |
246 | |
247 | if (!debugfs_create_file("components", 0444, snd_soc_debugfs_root, NULL, | |
248 | &component_list_fops)) | |
249 | pr_warn("ASoC: Failed to create component list debugfs file\n"); | |
6553bf06 LPC |
250 | } |
251 | ||
252 | static void snd_soc_debugfs_exit(void) | |
253 | { | |
254 | debugfs_remove_recursive(snd_soc_debugfs_root); | |
255 | } | |
256 | ||
2624d5fa MB |
257 | #else |
258 | ||
81c7cfd1 LPC |
259 | static inline void soc_init_component_debugfs( |
260 | struct snd_soc_component *component) | |
731f1ab2 SG |
261 | { |
262 | } | |
263 | ||
81c7cfd1 LPC |
264 | static inline void soc_cleanup_component_debugfs( |
265 | struct snd_soc_component *component) | |
731f1ab2 SG |
266 | { |
267 | } | |
268 | ||
b95fccbc AL |
269 | static inline void soc_init_card_debugfs(struct snd_soc_card *card) |
270 | { | |
271 | } | |
272 | ||
273 | static inline void soc_cleanup_card_debugfs(struct snd_soc_card *card) | |
274 | { | |
275 | } | |
6553bf06 LPC |
276 | |
277 | static inline void snd_soc_debugfs_init(void) | |
278 | { | |
279 | } | |
280 | ||
281 | static inline void snd_soc_debugfs_exit(void) | |
282 | { | |
283 | } | |
284 | ||
2624d5fa MB |
285 | #endif |
286 | ||
a0ac4411 KM |
287 | static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd, |
288 | struct snd_soc_component *component) | |
289 | { | |
290 | struct snd_soc_rtdcom_list *rtdcom; | |
291 | struct snd_soc_rtdcom_list *new_rtdcom; | |
292 | ||
293 | for_each_rtdcom(rtd, rtdcom) { | |
294 | /* already connected */ | |
295 | if (rtdcom->component == component) | |
296 | return 0; | |
297 | } | |
298 | ||
299 | new_rtdcom = kmalloc(sizeof(*new_rtdcom), GFP_KERNEL); | |
300 | if (!new_rtdcom) | |
301 | return -ENOMEM; | |
302 | ||
303 | new_rtdcom->component = component; | |
304 | INIT_LIST_HEAD(&new_rtdcom->list); | |
305 | ||
306 | list_add_tail(&new_rtdcom->list, &rtd->component_list); | |
307 | ||
308 | return 0; | |
309 | } | |
310 | ||
311 | static void snd_soc_rtdcom_del_all(struct snd_soc_pcm_runtime *rtd) | |
312 | { | |
313 | struct snd_soc_rtdcom_list *rtdcom1, *rtdcom2; | |
314 | ||
315 | for_each_rtdcom_safe(rtd, rtdcom1, rtdcom2) | |
316 | kfree(rtdcom1); | |
317 | ||
318 | INIT_LIST_HEAD(&rtd->component_list); | |
319 | } | |
320 | ||
321 | struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, | |
322 | const char *driver_name) | |
323 | { | |
324 | struct snd_soc_rtdcom_list *rtdcom; | |
325 | ||
971da24c KM |
326 | if (!driver_name) |
327 | return NULL; | |
328 | ||
a0ac4411 | 329 | for_each_rtdcom(rtd, rtdcom) { |
971da24c KM |
330 | const char *component_name = rtdcom->component->driver->name; |
331 | ||
332 | if (!component_name) | |
333 | continue; | |
334 | ||
335 | if ((component_name == driver_name) || | |
336 | strcmp(component_name, driver_name) == 0) | |
a0ac4411 KM |
337 | return rtdcom->component; |
338 | } | |
339 | ||
340 | return NULL; | |
341 | } | |
031734b7 | 342 | EXPORT_SYMBOL_GPL(snd_soc_rtdcom_lookup); |
a0ac4411 | 343 | |
47c88fff LG |
344 | struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, |
345 | const char *dai_link, int stream) | |
346 | { | |
1a497983 | 347 | struct snd_soc_pcm_runtime *rtd; |
47c88fff | 348 | |
bcb1fd1f | 349 | for_each_card_rtds(card, rtd) { |
1a497983 ML |
350 | if (rtd->dai_link->no_pcm && |
351 | !strcmp(rtd->dai_link->name, dai_link)) | |
352 | return rtd->pcm->streams[stream].substream; | |
47c88fff | 353 | } |
f110bfc7 | 354 | dev_dbg(card->dev, "ASoC: failed to find dai link %s\n", dai_link); |
47c88fff LG |
355 | return NULL; |
356 | } | |
357 | EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream); | |
358 | ||
75ab9eb6 KM |
359 | static const struct snd_soc_ops null_snd_soc_ops; |
360 | ||
1a497983 ML |
361 | static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( |
362 | struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) | |
363 | { | |
364 | struct snd_soc_pcm_runtime *rtd; | |
365 | ||
366 | rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL); | |
367 | if (!rtd) | |
368 | return NULL; | |
369 | ||
a0ac4411 | 370 | INIT_LIST_HEAD(&rtd->component_list); |
1a497983 ML |
371 | rtd->card = card; |
372 | rtd->dai_link = dai_link; | |
75ab9eb6 KM |
373 | if (!rtd->dai_link->ops) |
374 | rtd->dai_link->ops = &null_snd_soc_ops; | |
375 | ||
6396bb22 KC |
376 | rtd->codec_dais = kcalloc(dai_link->num_codecs, |
377 | sizeof(struct snd_soc_dai *), | |
1a497983 ML |
378 | GFP_KERNEL); |
379 | if (!rtd->codec_dais) { | |
380 | kfree(rtd); | |
381 | return NULL; | |
382 | } | |
383 | ||
384 | return rtd; | |
385 | } | |
386 | ||
387 | static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd) | |
388 | { | |
db1721f5 | 389 | kfree(rtd->codec_dais); |
a0ac4411 | 390 | snd_soc_rtdcom_del_all(rtd); |
1a497983 ML |
391 | kfree(rtd); |
392 | } | |
393 | ||
394 | static void soc_add_pcm_runtime(struct snd_soc_card *card, | |
395 | struct snd_soc_pcm_runtime *rtd) | |
396 | { | |
397 | list_add_tail(&rtd->list, &card->rtd_list); | |
398 | rtd->num = card->num_rtd; | |
399 | card->num_rtd++; | |
400 | } | |
401 | ||
402 | static void soc_remove_pcm_runtimes(struct snd_soc_card *card) | |
403 | { | |
404 | struct snd_soc_pcm_runtime *rtd, *_rtd; | |
405 | ||
bcb1fd1f | 406 | for_each_card_rtds_safe(card, rtd, _rtd) { |
1a497983 ML |
407 | list_del(&rtd->list); |
408 | soc_free_pcm_runtime(rtd); | |
409 | } | |
410 | ||
411 | card->num_rtd = 0; | |
412 | } | |
413 | ||
47c88fff LG |
414 | struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, |
415 | const char *dai_link) | |
416 | { | |
1a497983 | 417 | struct snd_soc_pcm_runtime *rtd; |
47c88fff | 418 | |
bcb1fd1f | 419 | for_each_card_rtds(card, rtd) { |
1a497983 ML |
420 | if (!strcmp(rtd->dai_link->name, dai_link)) |
421 | return rtd; | |
47c88fff | 422 | } |
f110bfc7 | 423 | dev_dbg(card->dev, "ASoC: failed to find rtd %s\n", dai_link); |
47c88fff LG |
424 | return NULL; |
425 | } | |
426 | EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); | |
427 | ||
9d58a077 RF |
428 | static void codec2codec_close_delayed_work(struct work_struct *work) |
429 | { | |
2c7b696a MZ |
430 | /* |
431 | * Currently nothing to do for c2c links | |
9d58a077 RF |
432 | * Since c2c links are internal nodes in the DAPM graph and |
433 | * don't interface with the outside world or application layer | |
434 | * we don't have to do any special handling on close. | |
435 | */ | |
436 | } | |
437 | ||
6f8ab4ac | 438 | #ifdef CONFIG_PM_SLEEP |
db2a4165 | 439 | /* powers down audio subsystem for suspend */ |
6f8ab4ac | 440 | int snd_soc_suspend(struct device *dev) |
db2a4165 | 441 | { |
6f8ab4ac | 442 | struct snd_soc_card *card = dev_get_drvdata(dev); |
d9fc4063 | 443 | struct snd_soc_component *component; |
1a497983 ML |
444 | struct snd_soc_pcm_runtime *rtd; |
445 | int i; | |
db2a4165 | 446 | |
c5599b87 LPC |
447 | /* If the card is not initialized yet there is nothing to do */ |
448 | if (!card->instantiated) | |
e3509ff0 DM |
449 | return 0; |
450 | ||
2c7b696a MZ |
451 | /* |
452 | * Due to the resume being scheduled into a workqueue we could | |
453 | * suspend before that's finished - wait for it to complete. | |
6ed25978 | 454 | */ |
f0fba2ad | 455 | snd_power_wait(card->snd_card, SNDRV_CTL_POWER_D0); |
6ed25978 AG |
456 | |
457 | /* we're going to block userspace touching us until resume completes */ | |
f0fba2ad | 458 | snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot); |
6ed25978 | 459 | |
a00f90f9 | 460 | /* mute any active DACs */ |
bcb1fd1f | 461 | for_each_card_rtds(card, rtd) { |
0b7990e3 | 462 | struct snd_soc_dai *dai; |
3efab7dc | 463 | |
1a497983 | 464 | if (rtd->dai_link->ignore_suspend) |
3efab7dc MB |
465 | continue; |
466 | ||
0b7990e3 | 467 | for_each_rtd_codec_dai(rtd, i, dai) { |
88bd870f BC |
468 | struct snd_soc_dai_driver *drv = dai->driver; |
469 | ||
470 | if (drv->ops->digital_mute && dai->playback_active) | |
471 | drv->ops->digital_mute(dai, 1); | |
472 | } | |
db2a4165 FM |
473 | } |
474 | ||
4ccab3e7 | 475 | /* suspend all pcms */ |
bcb1fd1f | 476 | for_each_card_rtds(card, rtd) { |
1a497983 | 477 | if (rtd->dai_link->ignore_suspend) |
3efab7dc MB |
478 | continue; |
479 | ||
1a497983 | 480 | snd_pcm_suspend_all(rtd->pcm); |
3efab7dc | 481 | } |
4ccab3e7 | 482 | |
87506549 | 483 | if (card->suspend_pre) |
70b2ac12 | 484 | card->suspend_pre(card); |
db2a4165 | 485 | |
bcb1fd1f | 486 | for_each_card_rtds(card, rtd) { |
1a497983 | 487 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
3efab7dc | 488 | |
1a497983 | 489 | if (rtd->dai_link->ignore_suspend) |
3efab7dc MB |
490 | continue; |
491 | ||
bc263214 | 492 | if (cpu_dai->driver->suspend && !cpu_dai->driver->bus_control) |
f0fba2ad | 493 | cpu_dai->driver->suspend(cpu_dai); |
db2a4165 FM |
494 | } |
495 | ||
37660b6d | 496 | /* close any waiting streams */ |
bcb1fd1f | 497 | for_each_card_rtds(card, rtd) |
1a497983 | 498 | flush_delayed_work(&rtd->delayed_work); |
db2a4165 | 499 | |
bcb1fd1f | 500 | for_each_card_rtds(card, rtd) { |
3efab7dc | 501 | |
1a497983 | 502 | if (rtd->dai_link->ignore_suspend) |
3efab7dc MB |
503 | continue; |
504 | ||
1a497983 | 505 | snd_soc_dapm_stream_event(rtd, |
7bd3a6f3 | 506 | SNDRV_PCM_STREAM_PLAYBACK, |
7bd3a6f3 | 507 | SND_SOC_DAPM_STREAM_SUSPEND); |
f0fba2ad | 508 | |
1a497983 | 509 | snd_soc_dapm_stream_event(rtd, |
7bd3a6f3 | 510 | SNDRV_PCM_STREAM_CAPTURE, |
7bd3a6f3 | 511 | SND_SOC_DAPM_STREAM_SUSPEND); |
db2a4165 FM |
512 | } |
513 | ||
8be4da29 LPC |
514 | /* Recheck all endpoints too, their state is affected by suspend */ |
515 | dapm_mark_endpoints_dirty(card); | |
e2d32ff6 MB |
516 | snd_soc_dapm_sync(&card->dapm); |
517 | ||
9178feb4 | 518 | /* suspend all COMPONENTs */ |
f70f18f7 | 519 | for_each_card_components(card, component) { |
2c7b696a MZ |
520 | struct snd_soc_dapm_context *dapm = |
521 | snd_soc_component_get_dapm(component); | |
d9fc4063 | 522 | |
2c7b696a MZ |
523 | /* |
524 | * If there are paths active then the COMPONENT will be held | |
525 | * with bias _ON and should not be suspended. | |
526 | */ | |
9178feb4 | 527 | if (!component->suspended) { |
4890140f | 528 | switch (snd_soc_dapm_get_bias_level(dapm)) { |
f0fba2ad | 529 | case SND_SOC_BIAS_STANDBY: |
125a25da | 530 | /* |
9178feb4 | 531 | * If the COMPONENT is capable of idle |
125a25da MB |
532 | * bias off then being in STANDBY |
533 | * means it's doing something, | |
534 | * otherwise fall through. | |
535 | */ | |
4890140f | 536 | if (dapm->idle_bias_off) { |
9178feb4 | 537 | dev_dbg(component->dev, |
10e8aa9a | 538 | "ASoC: idle_bias_off CODEC on over suspend\n"); |
125a25da MB |
539 | break; |
540 | } | |
1a12d5dc | 541 | /* fall through */ |
a8093297 | 542 | |
f0fba2ad | 543 | case SND_SOC_BIAS_OFF: |
999f7f5a KM |
544 | if (component->driver->suspend) |
545 | component->driver->suspend(component); | |
9178feb4 KM |
546 | component->suspended = 1; |
547 | if (component->regmap) | |
548 | regcache_mark_dirty(component->regmap); | |
988e8cc4 | 549 | /* deactivate pins to sleep state */ |
9178feb4 | 550 | pinctrl_pm_select_sleep_state(component->dev); |
f0fba2ad LG |
551 | break; |
552 | default: | |
9178feb4 KM |
553 | dev_dbg(component->dev, |
554 | "ASoC: COMPONENT is on over suspend\n"); | |
f0fba2ad LG |
555 | break; |
556 | } | |
1547aba9 MB |
557 | } |
558 | } | |
db2a4165 | 559 | |
bcb1fd1f | 560 | for_each_card_rtds(card, rtd) { |
1a497983 | 561 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
3efab7dc | 562 | |
1a497983 | 563 | if (rtd->dai_link->ignore_suspend) |
3efab7dc MB |
564 | continue; |
565 | ||
bc263214 | 566 | if (cpu_dai->driver->suspend && cpu_dai->driver->bus_control) |
f0fba2ad | 567 | cpu_dai->driver->suspend(cpu_dai); |
988e8cc4 NC |
568 | |
569 | /* deactivate pins to sleep state */ | |
570 | pinctrl_pm_select_sleep_state(cpu_dai->dev); | |
db2a4165 FM |
571 | } |
572 | ||
87506549 | 573 | if (card->suspend_post) |
70b2ac12 | 574 | card->suspend_post(card); |
db2a4165 FM |
575 | |
576 | return 0; | |
577 | } | |
6f8ab4ac | 578 | EXPORT_SYMBOL_GPL(snd_soc_suspend); |
db2a4165 | 579 | |
2c7b696a MZ |
580 | /* |
581 | * deferred resume work, so resume can complete before we finished | |
6ed25978 AG |
582 | * setting our codec back up, which can be very slow on I2C |
583 | */ | |
584 | static void soc_resume_deferred(struct work_struct *work) | |
db2a4165 | 585 | { |
f0fba2ad | 586 | struct snd_soc_card *card = |
2c7b696a MZ |
587 | container_of(work, struct snd_soc_card, |
588 | deferred_resume_work); | |
1a497983 | 589 | struct snd_soc_pcm_runtime *rtd; |
d9fc4063 | 590 | struct snd_soc_component *component; |
1a497983 | 591 | int i; |
db2a4165 | 592 | |
2c7b696a MZ |
593 | /* |
594 | * our power state is still SNDRV_CTL_POWER_D3hot from suspend time, | |
6ed25978 AG |
595 | * so userspace apps are blocked from touching us |
596 | */ | |
597 | ||
f110bfc7 | 598 | dev_dbg(card->dev, "ASoC: starting resume work\n"); |
6ed25978 | 599 | |
9949788b | 600 | /* Bring us up into D2 so that DAPM starts enabling things */ |
f0fba2ad | 601 | snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D2); |
9949788b | 602 | |
87506549 | 603 | if (card->resume_pre) |
70b2ac12 | 604 | card->resume_pre(card); |
db2a4165 | 605 | |
bc263214 | 606 | /* resume control bus DAIs */ |
bcb1fd1f | 607 | for_each_card_rtds(card, rtd) { |
1a497983 | 608 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
3efab7dc | 609 | |
1a497983 | 610 | if (rtd->dai_link->ignore_suspend) |
3efab7dc MB |
611 | continue; |
612 | ||
bc263214 | 613 | if (cpu_dai->driver->resume && cpu_dai->driver->bus_control) |
f0fba2ad LG |
614 | cpu_dai->driver->resume(cpu_dai); |
615 | } | |
616 | ||
f70f18f7 | 617 | for_each_card_components(card, component) { |
9178feb4 | 618 | if (component->suspended) { |
999f7f5a KM |
619 | if (component->driver->resume) |
620 | component->driver->resume(component); | |
9178feb4 | 621 | component->suspended = 0; |
1547aba9 MB |
622 | } |
623 | } | |
db2a4165 | 624 | |
bcb1fd1f | 625 | for_each_card_rtds(card, rtd) { |
3efab7dc | 626 | |
1a497983 | 627 | if (rtd->dai_link->ignore_suspend) |
3efab7dc MB |
628 | continue; |
629 | ||
1a497983 | 630 | snd_soc_dapm_stream_event(rtd, |
d9b0951b | 631 | SNDRV_PCM_STREAM_PLAYBACK, |
7bd3a6f3 | 632 | SND_SOC_DAPM_STREAM_RESUME); |
f0fba2ad | 633 | |
1a497983 | 634 | snd_soc_dapm_stream_event(rtd, |
d9b0951b | 635 | SNDRV_PCM_STREAM_CAPTURE, |
7bd3a6f3 | 636 | SND_SOC_DAPM_STREAM_RESUME); |
db2a4165 FM |
637 | } |
638 | ||
3ff3f64b | 639 | /* unmute any active DACs */ |
bcb1fd1f | 640 | for_each_card_rtds(card, rtd) { |
0b7990e3 | 641 | struct snd_soc_dai *dai; |
3efab7dc | 642 | |
1a497983 | 643 | if (rtd->dai_link->ignore_suspend) |
3efab7dc MB |
644 | continue; |
645 | ||
0b7990e3 | 646 | for_each_rtd_codec_dai(rtd, i, dai) { |
88bd870f BC |
647 | struct snd_soc_dai_driver *drv = dai->driver; |
648 | ||
649 | if (drv->ops->digital_mute && dai->playback_active) | |
650 | drv->ops->digital_mute(dai, 0); | |
651 | } | |
db2a4165 FM |
652 | } |
653 | ||
bcb1fd1f | 654 | for_each_card_rtds(card, rtd) { |
1a497983 | 655 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
3efab7dc | 656 | |
1a497983 | 657 | if (rtd->dai_link->ignore_suspend) |
3efab7dc MB |
658 | continue; |
659 | ||
bc263214 | 660 | if (cpu_dai->driver->resume && !cpu_dai->driver->bus_control) |
f0fba2ad | 661 | cpu_dai->driver->resume(cpu_dai); |
db2a4165 FM |
662 | } |
663 | ||
87506549 | 664 | if (card->resume_post) |
70b2ac12 | 665 | card->resume_post(card); |
db2a4165 | 666 | |
f110bfc7 | 667 | dev_dbg(card->dev, "ASoC: resume work completed\n"); |
6ed25978 | 668 | |
8be4da29 LPC |
669 | /* Recheck all endpoints too, their state is affected by suspend */ |
670 | dapm_mark_endpoints_dirty(card); | |
e2d32ff6 | 671 | snd_soc_dapm_sync(&card->dapm); |
1a7aaa58 JK |
672 | |
673 | /* userspace can access us now we are back as we were before */ | |
674 | snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0); | |
6ed25978 AG |
675 | } |
676 | ||
677 | /* powers up audio subsystem after a suspend */ | |
6f8ab4ac | 678 | int snd_soc_resume(struct device *dev) |
6ed25978 | 679 | { |
6f8ab4ac | 680 | struct snd_soc_card *card = dev_get_drvdata(dev); |
bc263214 | 681 | bool bus_control = false; |
1a497983 | 682 | struct snd_soc_pcm_runtime *rtd; |
b9dd94a8 | 683 | |
c5599b87 LPC |
684 | /* If the card is not initialized yet there is nothing to do */ |
685 | if (!card->instantiated) | |
5ff1ddf2 EM |
686 | return 0; |
687 | ||
988e8cc4 | 688 | /* activate pins from sleep state */ |
bcb1fd1f | 689 | for_each_card_rtds(card, rtd) { |
0b7990e3 | 690 | struct snd_soc_dai *codec_dai; |
88bd870f BC |
691 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
692 | int j; | |
693 | ||
988e8cc4 NC |
694 | if (cpu_dai->active) |
695 | pinctrl_pm_select_default_state(cpu_dai->dev); | |
88bd870f | 696 | |
0b7990e3 | 697 | for_each_rtd_codec_dai(rtd, j, codec_dai) { |
88bd870f BC |
698 | if (codec_dai->active) |
699 | pinctrl_pm_select_default_state(codec_dai->dev); | |
700 | } | |
988e8cc4 NC |
701 | } |
702 | ||
bc263214 LPC |
703 | /* |
704 | * DAIs that also act as the control bus master might have other drivers | |
705 | * hanging off them so need to resume immediately. Other drivers don't | |
706 | * have that problem and may take a substantial amount of time to resume | |
64ab9baa MB |
707 | * due to I/O costs and anti-pop so handle them out of line. |
708 | */ | |
bcb1fd1f | 709 | for_each_card_rtds(card, rtd) { |
1a497983 | 710 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
2c7b696a | 711 | |
bc263214 | 712 | bus_control |= cpu_dai->driver->bus_control; |
82e14e8b | 713 | } |
bc263214 LPC |
714 | if (bus_control) { |
715 | dev_dbg(dev, "ASoC: Resuming control bus master immediately\n"); | |
82e14e8b SW |
716 | soc_resume_deferred(&card->deferred_resume_work); |
717 | } else { | |
f110bfc7 | 718 | dev_dbg(dev, "ASoC: Scheduling resume work\n"); |
82e14e8b | 719 | if (!schedule_work(&card->deferred_resume_work)) |
f110bfc7 | 720 | dev_err(dev, "ASoC: resume work item may be lost\n"); |
64ab9baa | 721 | } |
6ed25978 | 722 | |
db2a4165 FM |
723 | return 0; |
724 | } | |
6f8ab4ac | 725 | EXPORT_SYMBOL_GPL(snd_soc_resume); |
db2a4165 | 726 | #else |
6f8ab4ac MB |
727 | #define snd_soc_suspend NULL |
728 | #define snd_soc_resume NULL | |
db2a4165 FM |
729 | #endif |
730 | ||
85e7652d | 731 | static const struct snd_soc_dai_ops null_dai_ops = { |
02a06d30 BS |
732 | }; |
733 | ||
65d9361f LPC |
734 | static struct snd_soc_component *soc_find_component( |
735 | const struct device_node *of_node, const char *name) | |
12023a9a | 736 | { |
65d9361f | 737 | struct snd_soc_component *component; |
12023a9a | 738 | |
34e81ab4 LPC |
739 | lockdep_assert_held(&client_mutex); |
740 | ||
368dee94 | 741 | for_each_component(component) { |
65d9361f LPC |
742 | if (of_node) { |
743 | if (component->dev->of_node == of_node) | |
744 | return component; | |
745 | } else if (strcmp(component->name, name) == 0) { | |
746 | return component; | |
12023a9a | 747 | } |
12023a9a MLC |
748 | } |
749 | ||
750 | return NULL; | |
751 | } | |
752 | ||
be6ac0a9 KM |
753 | static int snd_soc_is_matching_component( |
754 | const struct snd_soc_dai_link_component *dlc, | |
755 | struct snd_soc_component *component) | |
756 | { | |
757 | struct device_node *component_of_node; | |
758 | ||
759 | component_of_node = component->dev->of_node; | |
760 | if (!component_of_node && component->dev->parent) | |
761 | component_of_node = component->dev->parent->of_node; | |
762 | ||
763 | if (dlc->of_node && component_of_node != dlc->of_node) | |
764 | return 0; | |
765 | if (dlc->name && strcmp(component->name, dlc->name)) | |
766 | return 0; | |
767 | ||
768 | return 1; | |
769 | } | |
770 | ||
fbb88b5c ML |
771 | /** |
772 | * snd_soc_find_dai - Find a registered DAI | |
773 | * | |
4958471b | 774 | * @dlc: name of the DAI or the DAI driver and optional component info to match |
fbb88b5c | 775 | * |
ad61dd30 | 776 | * This function will search all registered components and their DAIs to |
fbb88b5c ML |
777 | * find the DAI of the same name. The component's of_node and name |
778 | * should also match if being specified. | |
779 | * | |
780 | * Return: pointer of DAI, or NULL if not found. | |
781 | */ | |
305e9020 | 782 | struct snd_soc_dai *snd_soc_find_dai( |
14621c7e | 783 | const struct snd_soc_dai_link_component *dlc) |
12023a9a | 784 | { |
14621c7e LPC |
785 | struct snd_soc_component *component; |
786 | struct snd_soc_dai *dai; | |
12023a9a | 787 | |
34e81ab4 LPC |
788 | lockdep_assert_held(&client_mutex); |
789 | ||
2c7b696a | 790 | /* Find CPU DAI from registered DAIs */ |
368dee94 | 791 | for_each_component(component) { |
be6ac0a9 | 792 | if (!snd_soc_is_matching_component(dlc, component)) |
14621c7e | 793 | continue; |
15a0c645 | 794 | for_each_component_dais(component, dai) { |
4958471b | 795 | if (dlc->dai_name && strcmp(dai->name, dlc->dai_name) |
6a6dafda JC |
796 | && (!dai->driver->name |
797 | || strcmp(dai->driver->name, dlc->dai_name))) | |
12023a9a | 798 | continue; |
12023a9a | 799 | |
14621c7e | 800 | return dai; |
12023a9a MLC |
801 | } |
802 | } | |
803 | ||
804 | return NULL; | |
805 | } | |
305e9020 | 806 | EXPORT_SYMBOL_GPL(snd_soc_find_dai); |
12023a9a | 807 | |
17fb1755 ML |
808 | /** |
809 | * snd_soc_find_dai_link - Find a DAI link | |
810 | * | |
811 | * @card: soc card | |
812 | * @id: DAI link ID to match | |
813 | * @name: DAI link name to match, optional | |
8abab35f | 814 | * @stream_name: DAI link stream name to match, optional |
17fb1755 ML |
815 | * |
816 | * This function will search all existing DAI links of the soc card to | |
817 | * find the link of the same ID. Since DAI links may not have their | |
818 | * unique ID, so name and stream name should also match if being | |
819 | * specified. | |
820 | * | |
821 | * Return: pointer of DAI link, or NULL if not found. | |
822 | */ | |
823 | struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, | |
824 | int id, const char *name, | |
825 | const char *stream_name) | |
826 | { | |
827 | struct snd_soc_dai_link *link, *_link; | |
828 | ||
829 | lockdep_assert_held(&client_mutex); | |
830 | ||
98061fdb | 831 | for_each_card_links_safe(card, link, _link) { |
17fb1755 ML |
832 | if (link->id != id) |
833 | continue; | |
834 | ||
835 | if (name && (!link->name || strcmp(name, link->name))) | |
836 | continue; | |
837 | ||
838 | if (stream_name && (!link->stream_name | |
839 | || strcmp(stream_name, link->stream_name))) | |
840 | continue; | |
841 | ||
842 | return link; | |
843 | } | |
844 | ||
845 | return NULL; | |
846 | } | |
847 | EXPORT_SYMBOL_GPL(snd_soc_find_dai_link); | |
848 | ||
49a5ba1c ML |
849 | static bool soc_is_dai_link_bound(struct snd_soc_card *card, |
850 | struct snd_soc_dai_link *dai_link) | |
851 | { | |
852 | struct snd_soc_pcm_runtime *rtd; | |
853 | ||
bcb1fd1f | 854 | for_each_card_rtds(card, rtd) { |
49a5ba1c ML |
855 | if (rtd->dai_link == dai_link) |
856 | return true; | |
857 | } | |
858 | ||
859 | return false; | |
860 | } | |
861 | ||
6f2f1ff0 ML |
862 | static int soc_bind_dai_link(struct snd_soc_card *card, |
863 | struct snd_soc_dai_link *dai_link) | |
db2a4165 | 864 | { |
1a497983 | 865 | struct snd_soc_pcm_runtime *rtd; |
88bd870f | 866 | struct snd_soc_dai_link_component *codecs = dai_link->codecs; |
14621c7e | 867 | struct snd_soc_dai_link_component cpu_dai_component; |
90be711e | 868 | struct snd_soc_component *component; |
1a497983 | 869 | struct snd_soc_dai **codec_dais; |
88bd870f | 870 | int i; |
435c5e25 | 871 | |
a655de80 LG |
872 | if (dai_link->ignore) |
873 | return 0; | |
874 | ||
6f2f1ff0 | 875 | dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name); |
435c5e25 | 876 | |
49a5ba1c ML |
877 | if (soc_is_dai_link_bound(card, dai_link)) { |
878 | dev_dbg(card->dev, "ASoC: dai link %s already bound\n", | |
879 | dai_link->name); | |
880 | return 0; | |
881 | } | |
435c5e25 | 882 | |
513cb311 SM |
883 | rtd = soc_new_pcm_runtime(card, dai_link); |
884 | if (!rtd) | |
885 | return -ENOMEM; | |
886 | ||
14621c7e LPC |
887 | cpu_dai_component.name = dai_link->cpu_name; |
888 | cpu_dai_component.of_node = dai_link->cpu_of_node; | |
889 | cpu_dai_component.dai_name = dai_link->cpu_dai_name; | |
890 | rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component); | |
b19e6e7b | 891 | if (!rtd->cpu_dai) { |
6b490879 MH |
892 | dev_info(card->dev, "ASoC: CPU DAI %s not registered\n", |
893 | dai_link->cpu_dai_name); | |
1a497983 | 894 | goto _err_defer; |
f0fba2ad | 895 | } |
90be711e | 896 | snd_soc_rtdcom_add(rtd, rtd->cpu_dai->component); |
f0fba2ad | 897 | |
88bd870f | 898 | rtd->num_codecs = dai_link->num_codecs; |
848dd8be | 899 | |
88bd870f | 900 | /* Find CODEC from registered CODECs */ |
0b7990e3 | 901 | /* we can use for_each_rtd_codec_dai() after this */ |
1a497983 | 902 | codec_dais = rtd->codec_dais; |
88bd870f | 903 | for (i = 0; i < rtd->num_codecs; i++) { |
14621c7e | 904 | codec_dais[i] = snd_soc_find_dai(&codecs[i]); |
88bd870f BC |
905 | if (!codec_dais[i]) { |
906 | dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", | |
907 | codecs[i].dai_name); | |
1a497983 | 908 | goto _err_defer; |
88bd870f | 909 | } |
90be711e | 910 | snd_soc_rtdcom_add(rtd, codec_dais[i]->component); |
12023a9a MLC |
911 | } |
912 | ||
88bd870f BC |
913 | /* Single codec links expect codec and codec_dai in runtime data */ |
914 | rtd->codec_dai = codec_dais[0]; | |
88bd870f | 915 | |
90be711e | 916 | /* find one from the set of registered platforms */ |
368dee94 | 917 | for_each_component(component) { |
be6ac0a9 KM |
918 | if (!snd_soc_is_matching_component(dai_link->platform, |
919 | component)) | |
920 | continue; | |
90be711e KM |
921 | |
922 | snd_soc_rtdcom_add(rtd, component); | |
923 | } | |
924 | ||
1a497983 | 925 | soc_add_pcm_runtime(card, rtd); |
b19e6e7b | 926 | return 0; |
1a497983 ML |
927 | |
928 | _err_defer: | |
929 | soc_free_pcm_runtime(rtd); | |
2c7b696a | 930 | return -EPROBE_DEFER; |
f0fba2ad LG |
931 | } |
932 | ||
f1d45cc3 | 933 | static void soc_remove_component(struct snd_soc_component *component) |
d12cd198 | 934 | { |
abd31b32 | 935 | if (!component->card) |
70090bbb | 936 | return; |
d12cd198 | 937 | |
d9fc4063 | 938 | list_del(&component->card_list); |
589c3563 | 939 | |
999f7f5a KM |
940 | if (component->driver->remove) |
941 | component->driver->remove(component); | |
589c3563 | 942 | |
f1d45cc3 | 943 | snd_soc_dapm_free(snd_soc_component_get_dapm(component)); |
589c3563 | 944 | |
f1d45cc3 | 945 | soc_cleanup_component_debugfs(component); |
abd31b32 | 946 | component->card = NULL; |
f1d45cc3 | 947 | module_put(component->dev->driver->owner); |
589c3563 JN |
948 | } |
949 | ||
e60cd14f | 950 | static void soc_remove_dai(struct snd_soc_dai *dai, int order) |
f0fba2ad | 951 | { |
f0fba2ad LG |
952 | int err; |
953 | ||
2eda3cb1 KM |
954 | if (!dai || !dai->probed || |
955 | dai->driver->remove_order != order) | |
956 | return; | |
957 | ||
958 | if (dai->driver->remove) { | |
959 | err = dai->driver->remove(dai); | |
960 | if (err < 0) | |
961 | dev_err(dai->dev, | |
962 | "ASoC: failed to remove %s: %d\n", | |
963 | dai->name, err); | |
f0fba2ad | 964 | } |
2eda3cb1 | 965 | dai->probed = 0; |
b0aa88af MLC |
966 | } |
967 | ||
1a497983 ML |
968 | static void soc_remove_link_dais(struct snd_soc_card *card, |
969 | struct snd_soc_pcm_runtime *rtd, int order) | |
b0aa88af | 970 | { |
e60cd14f | 971 | int i; |
0b7990e3 | 972 | struct snd_soc_dai *codec_dai; |
b0aa88af MLC |
973 | |
974 | /* unregister the rtd device */ | |
975 | if (rtd->dev_registered) { | |
b0aa88af MLC |
976 | device_unregister(rtd->dev); |
977 | rtd->dev_registered = 0; | |
978 | } | |
979 | ||
980 | /* remove the CODEC DAI */ | |
0b7990e3 KM |
981 | for_each_rtd_codec_dai(rtd, i, codec_dai) |
982 | soc_remove_dai(codec_dai, order); | |
6b05eda6 | 983 | |
e60cd14f | 984 | soc_remove_dai(rtd->cpu_dai, order); |
f0fba2ad | 985 | } |
db2a4165 | 986 | |
1a497983 ML |
987 | static void soc_remove_link_components(struct snd_soc_card *card, |
988 | struct snd_soc_pcm_runtime *rtd, int order) | |
62ae68fa | 989 | { |
61aca564 | 990 | struct snd_soc_component *component; |
90be711e | 991 | struct snd_soc_rtdcom_list *rtdcom; |
62ae68fa | 992 | |
90be711e KM |
993 | for_each_rtdcom(rtd, rtdcom) { |
994 | component = rtdcom->component; | |
62ae68fa | 995 | |
70090bbb | 996 | if (component->driver->remove_order == order) |
61aca564 | 997 | soc_remove_component(component); |
62ae68fa | 998 | } |
62ae68fa SW |
999 | } |
1000 | ||
0671fd8e KM |
1001 | static void soc_remove_dai_links(struct snd_soc_card *card) |
1002 | { | |
1a497983 ML |
1003 | int order; |
1004 | struct snd_soc_pcm_runtime *rtd; | |
f8f80361 | 1005 | struct snd_soc_dai_link *link, *_link; |
0671fd8e | 1006 | |
1a1035a9 | 1007 | for_each_comp_order(order) { |
bcb1fd1f | 1008 | for_each_card_rtds(card, rtd) |
1a497983 | 1009 | soc_remove_link_dais(card, rtd, order); |
62ae68fa SW |
1010 | } |
1011 | ||
1a1035a9 | 1012 | for_each_comp_order(order) { |
bcb1fd1f | 1013 | for_each_card_rtds(card, rtd) |
1a497983 | 1014 | soc_remove_link_components(card, rtd, order); |
0168bf0d | 1015 | } |
62ae68fa | 1016 | |
98061fdb | 1017 | for_each_card_links_safe(card, link, _link) { |
f8f80361 ML |
1018 | if (link->dobj.type == SND_SOC_DOBJ_DAI_LINK) |
1019 | dev_warn(card->dev, "Topology forgot to remove link %s?\n", | |
1020 | link->name); | |
1021 | ||
1022 | list_del(&link->list); | |
f8f80361 | 1023 | } |
0671fd8e KM |
1024 | } |
1025 | ||
daecf46e KM |
1026 | static int snd_soc_init_platform(struct snd_soc_card *card, |
1027 | struct snd_soc_dai_link *dai_link) | |
1028 | { | |
4a9ed394 KM |
1029 | struct snd_soc_dai_link_component *platform = dai_link->platform; |
1030 | ||
daecf46e KM |
1031 | /* |
1032 | * FIXME | |
1033 | * | |
1034 | * this function should be removed in the future | |
1035 | */ | |
1036 | /* convert Legacy platform link */ | |
4a9ed394 KM |
1037 | if (!platform) { |
1038 | platform = devm_kzalloc(card->dev, | |
daecf46e KM |
1039 | sizeof(struct snd_soc_dai_link_component), |
1040 | GFP_KERNEL); | |
4a9ed394 KM |
1041 | if (!platform) |
1042 | return -ENOMEM; | |
1043 | ||
1044 | dai_link->platform = platform; | |
1045 | platform->name = dai_link->platform_name; | |
1046 | platform->of_node = dai_link->platform_of_node; | |
1047 | platform->dai_name = NULL; | |
1048 | } | |
daecf46e | 1049 | |
4a9ed394 KM |
1050 | /* if there's no platform we match on the empty platform */ |
1051 | if (!platform->name && | |
1052 | !platform->of_node) | |
1053 | platform->name = "snd-soc-dummy"; | |
daecf46e KM |
1054 | |
1055 | return 0; | |
1056 | } | |
1057 | ||
923c5e61 ML |
1058 | static int snd_soc_init_multicodec(struct snd_soc_card *card, |
1059 | struct snd_soc_dai_link *dai_link) | |
1060 | { | |
1061 | /* Legacy codec/codec_dai link is a single entry in multicodec */ | |
1062 | if (dai_link->codec_name || dai_link->codec_of_node || | |
1063 | dai_link->codec_dai_name) { | |
1064 | dai_link->num_codecs = 1; | |
1065 | ||
1066 | dai_link->codecs = devm_kzalloc(card->dev, | |
1067 | sizeof(struct snd_soc_dai_link_component), | |
1068 | GFP_KERNEL); | |
1069 | if (!dai_link->codecs) | |
1070 | return -ENOMEM; | |
1071 | ||
1072 | dai_link->codecs[0].name = dai_link->codec_name; | |
1073 | dai_link->codecs[0].of_node = dai_link->codec_of_node; | |
1074 | dai_link->codecs[0].dai_name = dai_link->codec_dai_name; | |
1075 | } | |
1076 | ||
1077 | if (!dai_link->codecs) { | |
1078 | dev_err(card->dev, "ASoC: DAI link has no CODECs\n"); | |
1079 | return -EINVAL; | |
1080 | } | |
1081 | ||
1082 | return 0; | |
1083 | } | |
1084 | ||
1085 | static int soc_init_dai_link(struct snd_soc_card *card, | |
2c7b696a | 1086 | struct snd_soc_dai_link *link) |
923c5e61 ML |
1087 | { |
1088 | int i, ret; | |
3db769f1 | 1089 | struct snd_soc_dai_link_component *codec; |
923c5e61 | 1090 | |
daecf46e KM |
1091 | ret = snd_soc_init_platform(card, link); |
1092 | if (ret) { | |
1093 | dev_err(card->dev, "ASoC: failed to init multiplatform\n"); | |
1094 | return ret; | |
1095 | } | |
1096 | ||
923c5e61 ML |
1097 | ret = snd_soc_init_multicodec(card, link); |
1098 | if (ret) { | |
1099 | dev_err(card->dev, "ASoC: failed to init multicodec\n"); | |
1100 | return ret; | |
1101 | } | |
1102 | ||
3db769f1 | 1103 | for_each_link_codecs(link, i, codec) { |
923c5e61 ML |
1104 | /* |
1105 | * Codec must be specified by 1 of name or OF node, | |
1106 | * not both or neither. | |
1107 | */ | |
3db769f1 KM |
1108 | if (!!codec->name == |
1109 | !!codec->of_node) { | |
923c5e61 ML |
1110 | dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n", |
1111 | link->name); | |
1112 | return -EINVAL; | |
1113 | } | |
1114 | /* Codec DAI name must be specified */ | |
3db769f1 | 1115 | if (!codec->dai_name) { |
923c5e61 ML |
1116 | dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n", |
1117 | link->name); | |
1118 | return -EINVAL; | |
1119 | } | |
1120 | } | |
1121 | ||
1122 | /* | |
1123 | * Platform may be specified by either name or OF node, but | |
1124 | * can be left unspecified, and a dummy platform will be used. | |
1125 | */ | |
daecf46e | 1126 | if (link->platform->name && link->platform->of_node) { |
923c5e61 ML |
1127 | dev_err(card->dev, |
1128 | "ASoC: Both platform name/of_node are set for %s\n", | |
1129 | link->name); | |
1130 | return -EINVAL; | |
1131 | } | |
923c5e61 ML |
1132 | /* |
1133 | * CPU device may be specified by either name or OF node, but | |
1134 | * can be left unspecified, and will be matched based on DAI | |
1135 | * name alone.. | |
1136 | */ | |
1137 | if (link->cpu_name && link->cpu_of_node) { | |
1138 | dev_err(card->dev, | |
1139 | "ASoC: Neither/both cpu name/of_node are set for %s\n", | |
1140 | link->name); | |
1141 | return -EINVAL; | |
1142 | } | |
1143 | /* | |
1144 | * At least one of CPU DAI name or CPU device name/node must be | |
1145 | * specified | |
1146 | */ | |
1147 | if (!link->cpu_dai_name && | |
1148 | !(link->cpu_name || link->cpu_of_node)) { | |
1149 | dev_err(card->dev, | |
1150 | "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n", | |
1151 | link->name); | |
1152 | return -EINVAL; | |
1153 | } | |
1154 | ||
1155 | return 0; | |
0671fd8e KM |
1156 | } |
1157 | ||
ef2e8175 KM |
1158 | void snd_soc_disconnect_sync(struct device *dev) |
1159 | { | |
2c7b696a MZ |
1160 | struct snd_soc_component *component = |
1161 | snd_soc_lookup_component(dev, NULL); | |
ef2e8175 KM |
1162 | |
1163 | if (!component || !component->card) | |
1164 | return; | |
1165 | ||
1166 | snd_card_disconnect_sync(component->card->snd_card); | |
1167 | } | |
df532185 | 1168 | EXPORT_SYMBOL_GPL(snd_soc_disconnect_sync); |
ef2e8175 | 1169 | |
f8f80361 ML |
1170 | /** |
1171 | * snd_soc_add_dai_link - Add a DAI link dynamically | |
1172 | * @card: The ASoC card to which the DAI link is added | |
1173 | * @dai_link: The new DAI link to add | |
1174 | * | |
1175 | * This function adds a DAI link to the ASoC card's link list. | |
1176 | * | |
1177 | * Note: Topology can use this API to add DAI links when probing the | |
1178 | * topology component. And machine drivers can still define static | |
1179 | * DAI links in dai_link array. | |
1180 | */ | |
1181 | int snd_soc_add_dai_link(struct snd_soc_card *card, | |
1182 | struct snd_soc_dai_link *dai_link) | |
1183 | { | |
1184 | if (dai_link->dobj.type | |
1185 | && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) { | |
1186 | dev_err(card->dev, "Invalid dai link type %d\n", | |
1187 | dai_link->dobj.type); | |
1188 | return -EINVAL; | |
1189 | } | |
1190 | ||
1191 | lockdep_assert_held(&client_mutex); | |
2c7b696a MZ |
1192 | /* |
1193 | * Notify the machine driver for extra initialization | |
d6f220ea ML |
1194 | * on the link created by topology. |
1195 | */ | |
1196 | if (dai_link->dobj.type && card->add_dai_link) | |
1197 | card->add_dai_link(card, dai_link); | |
1198 | ||
f8f80361 | 1199 | list_add_tail(&dai_link->list, &card->dai_link_list); |
f8f80361 ML |
1200 | |
1201 | return 0; | |
1202 | } | |
1203 | EXPORT_SYMBOL_GPL(snd_soc_add_dai_link); | |
1204 | ||
1205 | /** | |
1206 | * snd_soc_remove_dai_link - Remove a DAI link from the list | |
1207 | * @card: The ASoC card that owns the link | |
1208 | * @dai_link: The DAI link to remove | |
1209 | * | |
1210 | * This function removes a DAI link from the ASoC card's link list. | |
1211 | * | |
1212 | * For DAI links previously added by topology, topology should | |
1213 | * remove them by using the dobj embedded in the link. | |
1214 | */ | |
1215 | void snd_soc_remove_dai_link(struct snd_soc_card *card, | |
1216 | struct snd_soc_dai_link *dai_link) | |
1217 | { | |
1218 | struct snd_soc_dai_link *link, *_link; | |
1219 | ||
1220 | if (dai_link->dobj.type | |
1221 | && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) { | |
1222 | dev_err(card->dev, "Invalid dai link type %d\n", | |
1223 | dai_link->dobj.type); | |
1224 | return; | |
1225 | } | |
1226 | ||
1227 | lockdep_assert_held(&client_mutex); | |
2c7b696a MZ |
1228 | /* |
1229 | * Notify the machine driver for extra destruction | |
d6f220ea ML |
1230 | * on the link created by topology. |
1231 | */ | |
1232 | if (dai_link->dobj.type && card->remove_dai_link) | |
1233 | card->remove_dai_link(card, dai_link); | |
1234 | ||
98061fdb | 1235 | for_each_card_links_safe(card, link, _link) { |
f8f80361 ML |
1236 | if (link == dai_link) { |
1237 | list_del(&link->list); | |
f8f80361 ML |
1238 | return; |
1239 | } | |
1240 | } | |
1241 | } | |
1242 | EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link); | |
1243 | ||
aefba455 JB |
1244 | static void soc_set_of_name_prefix(struct snd_soc_component *component) |
1245 | { | |
1246 | struct device_node *component_of_node = component->dev->of_node; | |
1247 | const char *str; | |
1248 | int ret; | |
1249 | ||
1250 | if (!component_of_node && component->dev->parent) | |
1251 | component_of_node = component->dev->parent->of_node; | |
1252 | ||
1253 | ret = of_property_read_string(component_of_node, "sound-name-prefix", | |
1254 | &str); | |
1255 | if (!ret) | |
1256 | component->name_prefix = str; | |
1257 | } | |
1258 | ||
ead9b919 | 1259 | static void soc_set_name_prefix(struct snd_soc_card *card, |
94f99c87 | 1260 | struct snd_soc_component *component) |
ead9b919 JN |
1261 | { |
1262 | int i; | |
1263 | ||
aefba455 | 1264 | for (i = 0; i < card->num_configs && card->codec_conf; i++) { |
ff819b83 | 1265 | struct snd_soc_codec_conf *map = &card->codec_conf[i]; |
b24c539b CK |
1266 | struct device_node *component_of_node = component->dev->of_node; |
1267 | ||
1268 | if (!component_of_node && component->dev->parent) | |
1269 | component_of_node = component->dev->parent->of_node; | |
1270 | ||
1271 | if (map->of_node && component_of_node != map->of_node) | |
3ca041ed | 1272 | continue; |
94f99c87 | 1273 | if (map->dev_name && strcmp(component->name, map->dev_name)) |
3ca041ed | 1274 | continue; |
94f99c87 | 1275 | component->name_prefix = map->name_prefix; |
aefba455 | 1276 | return; |
ead9b919 | 1277 | } |
aefba455 JB |
1278 | |
1279 | /* | |
1280 | * If there is no configuration table or no match in the table, | |
1281 | * check if a prefix is provided in the node | |
1282 | */ | |
1283 | soc_set_of_name_prefix(component); | |
ead9b919 JN |
1284 | } |
1285 | ||
f1d45cc3 LPC |
1286 | static int soc_probe_component(struct snd_soc_card *card, |
1287 | struct snd_soc_component *component) | |
589c3563 | 1288 | { |
2c7b696a MZ |
1289 | struct snd_soc_dapm_context *dapm = |
1290 | snd_soc_component_get_dapm(component); | |
888df395 | 1291 | struct snd_soc_dai *dai; |
f1d45cc3 | 1292 | int ret; |
589c3563 | 1293 | |
1b7c1231 | 1294 | if (!strcmp(component->name, "snd-soc-dummy")) |
70090bbb | 1295 | return 0; |
589c3563 | 1296 | |
abd31b32 | 1297 | if (component->card) { |
1b7c1231 LPC |
1298 | if (component->card != card) { |
1299 | dev_err(component->dev, | |
1300 | "Trying to bind component to card \"%s\" but is already bound to card \"%s\"\n", | |
1301 | card->name, component->card->name); | |
1302 | return -ENODEV; | |
1303 | } | |
1304 | return 0; | |
1305 | } | |
589c3563 | 1306 | |
f1d45cc3 | 1307 | if (!try_module_get(component->dev->driver->owner)) |
70d29331 JN |
1308 | return -ENODEV; |
1309 | ||
f1d45cc3 LPC |
1310 | component->card = card; |
1311 | dapm->card = card; | |
1312 | soc_set_name_prefix(card, component); | |
589c3563 | 1313 | |
f1d45cc3 | 1314 | soc_init_component_debugfs(component); |
d5d1e0be | 1315 | |
688d0ebf KM |
1316 | if (component->driver->dapm_widgets) { |
1317 | ret = snd_soc_dapm_new_controls(dapm, | |
1318 | component->driver->dapm_widgets, | |
1319 | component->driver->num_dapm_widgets); | |
b318ad50 NP |
1320 | |
1321 | if (ret != 0) { | |
f1d45cc3 | 1322 | dev_err(component->dev, |
b318ad50 NP |
1323 | "Failed to create new controls %d\n", ret); |
1324 | goto err_probe; | |
1325 | } | |
1326 | } | |
77530150 | 1327 | |
15a0c645 | 1328 | for_each_component_dais(component, dai) { |
0634814f | 1329 | ret = snd_soc_dapm_new_dai_widgets(dapm, dai); |
261edc70 | 1330 | if (ret != 0) { |
0634814f | 1331 | dev_err(component->dev, |
261edc70 NP |
1332 | "Failed to create DAI widgets %d\n", ret); |
1333 | goto err_probe; | |
1334 | } | |
1335 | } | |
888df395 | 1336 | |
999f7f5a KM |
1337 | if (component->driver->probe) { |
1338 | ret = component->driver->probe(component); | |
589c3563 | 1339 | if (ret < 0) { |
f1d45cc3 LPC |
1340 | dev_err(component->dev, |
1341 | "ASoC: failed to probe component %d\n", ret); | |
70d29331 | 1342 | goto err_probe; |
589c3563 | 1343 | } |
cb2cf612 | 1344 | |
f1d45cc3 LPC |
1345 | WARN(dapm->idle_bias_off && |
1346 | dapm->bias_level != SND_SOC_BIAS_OFF, | |
1347 | "codec %s can not start from non-off bias with idle_bias_off==1\n", | |
1348 | component->name); | |
be09ad90 LG |
1349 | } |
1350 | ||
f2ed6b07 ML |
1351 | /* machine specific init */ |
1352 | if (component->init) { | |
1353 | ret = component->init(component); | |
1354 | if (ret < 0) { | |
1355 | dev_err(component->dev, | |
1356 | "Failed to do machine specific init %d\n", ret); | |
1357 | goto err_probe; | |
1358 | } | |
1359 | } | |
1360 | ||
b8972bf0 KM |
1361 | if (component->driver->controls) |
1362 | snd_soc_add_component_controls(component, | |
1363 | component->driver->controls, | |
1364 | component->driver->num_controls); | |
6969b2ba KM |
1365 | if (component->driver->dapm_routes) |
1366 | snd_soc_dapm_add_routes(dapm, | |
1367 | component->driver->dapm_routes, | |
1368 | component->driver->num_dapm_routes); | |
3fec6b6d | 1369 | |
f1d45cc3 | 1370 | list_add(&dapm->list, &card->dapm_list); |
f70f18f7 | 1371 | /* see for_each_card_components */ |
d9fc4063 | 1372 | list_add(&component->card_list, &card->component_dev_list); |
956245e9 LG |
1373 | |
1374 | return 0; | |
1375 | ||
1376 | err_probe: | |
f1d45cc3 | 1377 | soc_cleanup_component_debugfs(component); |
abd31b32 | 1378 | component->card = NULL; |
f1d45cc3 | 1379 | module_put(component->dev->driver->owner); |
956245e9 LG |
1380 | |
1381 | return ret; | |
1382 | } | |
1383 | ||
36ae1a96 MB |
1384 | static void rtd_release(struct device *dev) |
1385 | { | |
1386 | kfree(dev); | |
1387 | } | |
f0fba2ad | 1388 | |
5f3484ac LPC |
1389 | static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, |
1390 | const char *name) | |
503ae5e0 | 1391 | { |
589c3563 JN |
1392 | int ret = 0; |
1393 | ||
589c3563 | 1394 | /* register the rtd device */ |
36ae1a96 MB |
1395 | rtd->dev = kzalloc(sizeof(struct device), GFP_KERNEL); |
1396 | if (!rtd->dev) | |
1397 | return -ENOMEM; | |
1398 | device_initialize(rtd->dev); | |
5f3484ac | 1399 | rtd->dev->parent = rtd->card->dev; |
36ae1a96 | 1400 | rtd->dev->release = rtd_release; |
d29697dc | 1401 | rtd->dev->groups = soc_dev_attr_groups; |
f294afed | 1402 | dev_set_name(rtd->dev, "%s", name); |
36ae1a96 | 1403 | dev_set_drvdata(rtd->dev, rtd); |
b8c0dab9 | 1404 | mutex_init(&rtd->pcm_mutex); |
01d7584c LG |
1405 | INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients); |
1406 | INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients); | |
1407 | INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].fe_clients); | |
1408 | INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients); | |
36ae1a96 | 1409 | ret = device_add(rtd->dev); |
589c3563 | 1410 | if (ret < 0) { |
865df9cb CL |
1411 | /* calling put_device() here to free the rtd->dev */ |
1412 | put_device(rtd->dev); | |
5f3484ac | 1413 | dev_err(rtd->card->dev, |
f110bfc7 | 1414 | "ASoC: failed to register runtime device: %d\n", ret); |
589c3563 JN |
1415 | return ret; |
1416 | } | |
1417 | rtd->dev_registered = 1; | |
589c3563 JN |
1418 | return 0; |
1419 | } | |
1420 | ||
1a497983 | 1421 | static int soc_probe_link_components(struct snd_soc_card *card, |
2c7b696a | 1422 | struct snd_soc_pcm_runtime *rtd, int order) |
62ae68fa | 1423 | { |
f1d45cc3 | 1424 | struct snd_soc_component *component; |
90be711e KM |
1425 | struct snd_soc_rtdcom_list *rtdcom; |
1426 | int ret; | |
62ae68fa | 1427 | |
90be711e KM |
1428 | for_each_rtdcom(rtd, rtdcom) { |
1429 | component = rtdcom->component; | |
62ae68fa | 1430 | |
70090bbb | 1431 | if (component->driver->probe_order == order) { |
f1d45cc3 | 1432 | ret = soc_probe_component(card, component); |
88bd870f BC |
1433 | if (ret < 0) |
1434 | return ret; | |
1435 | } | |
62ae68fa SW |
1436 | } |
1437 | ||
62ae68fa SW |
1438 | return 0; |
1439 | } | |
1440 | ||
8e2be562 | 1441 | static int soc_probe_dai(struct snd_soc_dai *dai, int order) |
b0aa88af | 1442 | { |
7a2ccad5 KM |
1443 | if (dai->probed || |
1444 | dai->driver->probe_order != order) | |
1445 | return 0; | |
b0aa88af | 1446 | |
7a2ccad5 KM |
1447 | if (dai->driver->probe) { |
1448 | int ret = dai->driver->probe(dai); | |
2c7b696a | 1449 | |
7a2ccad5 KM |
1450 | if (ret < 0) { |
1451 | dev_err(dai->dev, "ASoC: failed to probe DAI %s: %d\n", | |
1452 | dai->name, ret); | |
1453 | return ret; | |
b0aa88af | 1454 | } |
b0aa88af MLC |
1455 | } |
1456 | ||
7a2ccad5 KM |
1457 | dai->probed = 1; |
1458 | ||
b0aa88af MLC |
1459 | return 0; |
1460 | } | |
1461 | ||
25f7b701 AP |
1462 | static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, |
1463 | struct snd_soc_pcm_runtime *rtd) | |
1464 | { | |
1465 | int i, ret = 0; | |
1466 | ||
1467 | for (i = 0; i < num_dais; ++i) { | |
1468 | struct snd_soc_dai_driver *drv = dais[i]->driver; | |
1469 | ||
1470 | if (!rtd->dai_link->no_pcm && drv->pcm_new) | |
1471 | ret = drv->pcm_new(rtd, dais[i]); | |
1472 | if (ret < 0) { | |
1473 | dev_err(dais[i]->dev, | |
1474 | "ASoC: Failed to bind %s with pcm device\n", | |
1475 | dais[i]->name); | |
1476 | return ret; | |
1477 | } | |
1478 | } | |
1479 | ||
1480 | return 0; | |
1481 | } | |
1482 | ||
1a497983 ML |
1483 | static int soc_probe_link_dais(struct snd_soc_card *card, |
1484 | struct snd_soc_pcm_runtime *rtd, int order) | |
f0fba2ad | 1485 | { |
1a497983 | 1486 | struct snd_soc_dai_link *dai_link = rtd->dai_link; |
c74184ed | 1487 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
a655de80 LG |
1488 | struct snd_soc_rtdcom_list *rtdcom; |
1489 | struct snd_soc_component *component; | |
0b7990e3 | 1490 | struct snd_soc_dai *codec_dai; |
a655de80 | 1491 | int i, ret, num; |
f0fba2ad | 1492 | |
f110bfc7 | 1493 | dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", |
1a497983 | 1494 | card->name, rtd->num, order); |
f0fba2ad | 1495 | |
f0fba2ad LG |
1496 | /* set default power off timeout */ |
1497 | rtd->pmdown_time = pmdown_time; | |
1498 | ||
8e2be562 LPC |
1499 | ret = soc_probe_dai(cpu_dai, order); |
1500 | if (ret) | |
1501 | return ret; | |
db2a4165 | 1502 | |
f0fba2ad | 1503 | /* probe the CODEC DAI */ |
0b7990e3 KM |
1504 | for_each_rtd_codec_dai(rtd, i, codec_dai) { |
1505 | ret = soc_probe_dai(codec_dai, order); | |
88bd870f BC |
1506 | if (ret) |
1507 | return ret; | |
1508 | } | |
fe3e78e0 | 1509 | |
0168bf0d LG |
1510 | /* complete DAI probe during last probe */ |
1511 | if (order != SND_SOC_COMP_ORDER_LAST) | |
1512 | return 0; | |
1513 | ||
5f3484ac LPC |
1514 | /* do machine specific initialization */ |
1515 | if (dai_link->init) { | |
1516 | ret = dai_link->init(rtd); | |
1517 | if (ret < 0) { | |
1518 | dev_err(card->dev, "ASoC: failed to init %s: %d\n", | |
1519 | dai_link->name, ret); | |
1520 | return ret; | |
1521 | } | |
1522 | } | |
1523 | ||
a5053a8e KM |
1524 | if (dai_link->dai_fmt) |
1525 | snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt); | |
1526 | ||
5f3484ac | 1527 | ret = soc_post_component_init(rtd, dai_link->name); |
589c3563 | 1528 | if (ret) |
f0fba2ad | 1529 | return ret; |
fe3e78e0 | 1530 | |
5f3484ac LPC |
1531 | #ifdef CONFIG_DEBUG_FS |
1532 | /* add DPCM sysfs entries */ | |
2e55b90a LPC |
1533 | if (dai_link->dynamic) |
1534 | soc_dpcm_debugfs_add(rtd); | |
5f3484ac LPC |
1535 | #endif |
1536 | ||
a655de80 LG |
1537 | num = rtd->num; |
1538 | ||
1539 | /* | |
1540 | * most drivers will register their PCMs using DAI link ordering but | |
1541 | * topology based drivers can use the DAI link id field to set PCM | |
1542 | * device number and then use rtd + a base offset of the BEs. | |
1543 | */ | |
1544 | for_each_rtdcom(rtd, rtdcom) { | |
1545 | component = rtdcom->component; | |
1546 | ||
1547 | if (!component->driver->use_dai_pcm_id) | |
1548 | continue; | |
1549 | ||
1550 | if (rtd->dai_link->no_pcm) | |
1551 | num += component->driver->be_pcm_base; | |
1552 | else | |
1553 | num = rtd->dai_link->id; | |
1554 | } | |
1555 | ||
6f0c4226 | 1556 | if (cpu_dai->driver->compress_new) { |
2c7b696a | 1557 | /* create compress_device" */ |
a655de80 | 1558 | ret = cpu_dai->driver->compress_new(rtd, num); |
c74184ed | 1559 | if (ret < 0) { |
f110bfc7 | 1560 | dev_err(card->dev, "ASoC: can't create compress %s\n", |
1245b700 | 1561 | dai_link->stream_name); |
c74184ed MB |
1562 | return ret; |
1563 | } | |
1564 | } else { | |
1245b700 NK |
1565 | |
1566 | if (!dai_link->params) { | |
1567 | /* create the pcm */ | |
a655de80 | 1568 | ret = soc_new_pcm(rtd, num); |
1245b700 | 1569 | if (ret < 0) { |
f110bfc7 | 1570 | dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", |
2c7b696a | 1571 | dai_link->stream_name, ret); |
c74184ed MB |
1572 | return ret; |
1573 | } | |
25f7b701 AP |
1574 | ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); |
1575 | if (ret < 0) | |
1576 | return ret; | |
1577 | ret = soc_link_dai_pcm_new(rtd->codec_dais, | |
1578 | rtd->num_codecs, rtd); | |
1579 | if (ret < 0) | |
1580 | return ret; | |
1245b700 | 1581 | } else { |
9d58a077 RF |
1582 | INIT_DELAYED_WORK(&rtd->delayed_work, |
1583 | codec2codec_close_delayed_work); | |
c74184ed | 1584 | } |
f0fba2ad LG |
1585 | } |
1586 | ||
f0fba2ad LG |
1587 | return 0; |
1588 | } | |
1589 | ||
44c69bb1 | 1590 | static int soc_bind_aux_dev(struct snd_soc_card *card, int num) |
3ca041ed SR |
1591 | { |
1592 | struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; | |
f2ed6b07 ML |
1593 | struct snd_soc_component *component; |
1594 | const char *name; | |
1595 | struct device_node *codec_of_node; | |
1596 | ||
1597 | if (aux_dev->codec_of_node || aux_dev->codec_name) { | |
1598 | /* codecs, usually analog devices */ | |
1599 | name = aux_dev->codec_name; | |
1600 | codec_of_node = aux_dev->codec_of_node; | |
1601 | component = soc_find_component(codec_of_node, name); | |
1602 | if (!component) { | |
1603 | if (codec_of_node) | |
1604 | name = of_node_full_name(codec_of_node); | |
1605 | goto err_defer; | |
1606 | } | |
1607 | } else if (aux_dev->name) { | |
1608 | /* generic components */ | |
1609 | name = aux_dev->name; | |
1610 | component = soc_find_component(NULL, name); | |
1611 | if (!component) | |
1612 | goto err_defer; | |
1613 | } else { | |
1614 | dev_err(card->dev, "ASoC: Invalid auxiliary device\n"); | |
1615 | return -EINVAL; | |
3ca041ed | 1616 | } |
fb099cb7 | 1617 | |
f2ed6b07 | 1618 | component->init = aux_dev->init; |
d2e3a135 | 1619 | list_add(&component->card_aux_list, &card->aux_comp_list); |
1a653aa4 | 1620 | |
44c69bb1 | 1621 | return 0; |
f2ed6b07 ML |
1622 | |
1623 | err_defer: | |
1624 | dev_err(card->dev, "ASoC: %s not registered\n", name); | |
1625 | return -EPROBE_DEFER; | |
b19e6e7b MB |
1626 | } |
1627 | ||
f2ed6b07 | 1628 | static int soc_probe_aux_devices(struct snd_soc_card *card) |
2eea392d | 1629 | { |
991454e1 | 1630 | struct snd_soc_component *comp; |
f2ed6b07 | 1631 | int order; |
44c69bb1 | 1632 | int ret; |
3ca041ed | 1633 | |
1a1035a9 | 1634 | for_each_comp_order(order) { |
991454e1 | 1635 | list_for_each_entry(comp, &card->aux_comp_list, card_aux_list) { |
f2ed6b07 ML |
1636 | if (comp->driver->probe_order == order) { |
1637 | ret = soc_probe_component(card, comp); | |
1638 | if (ret < 0) { | |
1639 | dev_err(card->dev, | |
1640 | "ASoC: failed to probe aux component %s %d\n", | |
1641 | comp->name, ret); | |
1642 | return ret; | |
1643 | } | |
1644 | } | |
5f3484ac LPC |
1645 | } |
1646 | } | |
2eea392d | 1647 | |
f2ed6b07 | 1648 | return 0; |
2eea392d JN |
1649 | } |
1650 | ||
f2ed6b07 | 1651 | static void soc_remove_aux_devices(struct snd_soc_card *card) |
2eea392d | 1652 | { |
f2ed6b07 ML |
1653 | struct snd_soc_component *comp, *_comp; |
1654 | int order; | |
2eea392d | 1655 | |
1a1035a9 | 1656 | for_each_comp_order(order) { |
f2ed6b07 | 1657 | list_for_each_entry_safe(comp, _comp, |
991454e1 | 1658 | &card->aux_comp_list, card_aux_list) { |
1a653aa4 | 1659 | |
f2ed6b07 ML |
1660 | if (comp->driver->remove_order == order) { |
1661 | soc_remove_component(comp); | |
991454e1 KM |
1662 | /* remove it from the card's aux_comp_list */ |
1663 | list_del(&comp->card_aux_list); | |
f2ed6b07 ML |
1664 | } |
1665 | } | |
2eea392d | 1666 | } |
2eea392d JN |
1667 | } |
1668 | ||
ce64c8b9 LPC |
1669 | /** |
1670 | * snd_soc_runtime_set_dai_fmt() - Change DAI link format for a ASoC runtime | |
1671 | * @rtd: The runtime for which the DAI link format should be changed | |
1672 | * @dai_fmt: The new DAI link format | |
1673 | * | |
1674 | * This function updates the DAI link format for all DAIs connected to the DAI | |
1675 | * link for the specified runtime. | |
1676 | * | |
1677 | * Note: For setups with a static format set the dai_fmt field in the | |
1678 | * corresponding snd_dai_link struct instead of using this function. | |
1679 | * | |
1680 | * Returns 0 on success, otherwise a negative error code. | |
1681 | */ | |
1682 | int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, | |
1683 | unsigned int dai_fmt) | |
1684 | { | |
ce64c8b9 | 1685 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
0b7990e3 | 1686 | struct snd_soc_dai *codec_dai; |
ce64c8b9 LPC |
1687 | unsigned int i; |
1688 | int ret; | |
1689 | ||
0b7990e3 | 1690 | for_each_rtd_codec_dai(rtd, i, codec_dai) { |
ce64c8b9 LPC |
1691 | ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt); |
1692 | if (ret != 0 && ret != -ENOTSUPP) { | |
1693 | dev_warn(codec_dai->dev, | |
1694 | "ASoC: Failed to set DAI format: %d\n", ret); | |
1695 | return ret; | |
1696 | } | |
1697 | } | |
1698 | ||
2c7b696a MZ |
1699 | /* |
1700 | * Flip the polarity for the "CPU" end of a CODEC<->CODEC link | |
1701 | * the component which has non_legacy_dai_naming is Codec | |
1702 | */ | |
999f7f5a | 1703 | if (cpu_dai->component->driver->non_legacy_dai_naming) { |
ce64c8b9 LPC |
1704 | unsigned int inv_dai_fmt; |
1705 | ||
1706 | inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_MASTER_MASK; | |
1707 | switch (dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) { | |
1708 | case SND_SOC_DAIFMT_CBM_CFM: | |
1709 | inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; | |
1710 | break; | |
1711 | case SND_SOC_DAIFMT_CBM_CFS: | |
1712 | inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFM; | |
1713 | break; | |
1714 | case SND_SOC_DAIFMT_CBS_CFM: | |
1715 | inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFS; | |
1716 | break; | |
1717 | case SND_SOC_DAIFMT_CBS_CFS: | |
1718 | inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; | |
1719 | break; | |
1720 | } | |
1721 | ||
1722 | dai_fmt = inv_dai_fmt; | |
1723 | } | |
1724 | ||
1725 | ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt); | |
1726 | if (ret != 0 && ret != -ENOTSUPP) { | |
1727 | dev_warn(cpu_dai->dev, | |
1728 | "ASoC: Failed to set DAI format: %d\n", ret); | |
1729 | return ret; | |
1730 | } | |
1731 | ||
1732 | return 0; | |
1733 | } | |
ddaca25a | 1734 | EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt); |
ce64c8b9 | 1735 | |
1f5a4535 | 1736 | #ifdef CONFIG_DMI |
2c7b696a MZ |
1737 | /* |
1738 | * Trim special characters, and replace '-' with '_' since '-' is used to | |
345233d7 LG |
1739 | * separate different DMI fields in the card long name. Only number and |
1740 | * alphabet characters and a few separator characters are kept. | |
1741 | */ | |
1742 | static void cleanup_dmi_name(char *name) | |
1743 | { | |
1744 | int i, j = 0; | |
1745 | ||
1746 | for (i = 0; name[i]; i++) { | |
1747 | if (isalnum(name[i]) || (name[i] == '.') | |
1748 | || (name[i] == '_')) | |
1749 | name[j++] = name[i]; | |
1750 | else if (name[i] == '-') | |
1751 | name[j++] = '_'; | |
1752 | } | |
1753 | ||
1754 | name[j] = '\0'; | |
1755 | } | |
1756 | ||
2c7b696a MZ |
1757 | /* |
1758 | * Check if a DMI field is valid, i.e. not containing any string | |
98faf436 ML |
1759 | * in the black list. |
1760 | */ | |
1761 | static int is_dmi_valid(const char *field) | |
1762 | { | |
1763 | int i = 0; | |
1764 | ||
1765 | while (dmi_blacklist[i]) { | |
1766 | if (strstr(field, dmi_blacklist[i])) | |
1767 | return 0; | |
1768 | i++; | |
46b5a4d2 | 1769 | } |
98faf436 ML |
1770 | |
1771 | return 1; | |
1772 | } | |
1773 | ||
345233d7 LG |
1774 | /** |
1775 | * snd_soc_set_dmi_name() - Register DMI names to card | |
1776 | * @card: The card to register DMI names | |
1777 | * @flavour: The flavour "differentiator" for the card amongst its peers. | |
1778 | * | |
1779 | * An Intel machine driver may be used by many different devices but are | |
1780 | * difficult for userspace to differentiate, since machine drivers ususally | |
1781 | * use their own name as the card short name and leave the card long name | |
1782 | * blank. To differentiate such devices and fix bugs due to lack of | |
1783 | * device-specific configurations, this function allows DMI info to be used | |
1784 | * as the sound card long name, in the format of | |
1785 | * "vendor-product-version-board" | |
1786 | * (Character '-' is used to separate different DMI fields here). | |
1787 | * This will help the user space to load the device-specific Use Case Manager | |
1788 | * (UCM) configurations for the card. | |
1789 | * | |
1790 | * Possible card long names may be: | |
1791 | * DellInc.-XPS139343-01-0310JH | |
1792 | * ASUSTeKCOMPUTERINC.-T100TA-1.0-T100TA | |
1793 | * Circuitco-MinnowboardMaxD0PLATFORM-D0-MinnowBoardMAX | |
1794 | * | |
1795 | * This function also supports flavoring the card longname to provide | |
1796 | * the extra differentiation, like "vendor-product-version-board-flavor". | |
1797 | * | |
1798 | * We only keep number and alphabet characters and a few separator characters | |
1799 | * in the card long name since UCM in the user space uses the card long names | |
1800 | * as card configuration directory names and AudoConf cannot support special | |
1801 | * charactors like SPACE. | |
1802 | * | |
1803 | * Returns 0 on success, otherwise a negative error code. | |
1804 | */ | |
1805 | int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) | |
1806 | { | |
1807 | const char *vendor, *product, *product_version, *board; | |
1808 | size_t longname_buf_size = sizeof(card->snd_card->longname); | |
1809 | size_t len; | |
1810 | ||
1811 | if (card->long_name) | |
1812 | return 0; /* long name already set by driver or from DMI */ | |
1813 | ||
1814 | /* make up dmi long name as: vendor.product.version.board */ | |
1815 | vendor = dmi_get_system_info(DMI_BOARD_VENDOR); | |
98faf436 | 1816 | if (!vendor || !is_dmi_valid(vendor)) { |
345233d7 LG |
1817 | dev_warn(card->dev, "ASoC: no DMI vendor name!\n"); |
1818 | return 0; | |
1819 | } | |
1820 | ||
1821 | snprintf(card->dmi_longname, sizeof(card->snd_card->longname), | |
1822 | "%s", vendor); | |
1823 | cleanup_dmi_name(card->dmi_longname); | |
1824 | ||
1825 | product = dmi_get_system_info(DMI_PRODUCT_NAME); | |
98faf436 | 1826 | if (product && is_dmi_valid(product)) { |
345233d7 LG |
1827 | len = strlen(card->dmi_longname); |
1828 | snprintf(card->dmi_longname + len, | |
1829 | longname_buf_size - len, | |
1830 | "-%s", product); | |
1831 | ||
1832 | len++; /* skip the separator "-" */ | |
1833 | if (len < longname_buf_size) | |
1834 | cleanup_dmi_name(card->dmi_longname + len); | |
1835 | ||
2c7b696a MZ |
1836 | /* |
1837 | * some vendors like Lenovo may only put a self-explanatory | |
345233d7 LG |
1838 | * name in the product version field |
1839 | */ | |
1840 | product_version = dmi_get_system_info(DMI_PRODUCT_VERSION); | |
98faf436 | 1841 | if (product_version && is_dmi_valid(product_version)) { |
345233d7 LG |
1842 | len = strlen(card->dmi_longname); |
1843 | snprintf(card->dmi_longname + len, | |
1844 | longname_buf_size - len, | |
1845 | "-%s", product_version); | |
1846 | ||
1847 | len++; | |
1848 | if (len < longname_buf_size) | |
1849 | cleanup_dmi_name(card->dmi_longname + len); | |
1850 | } | |
1851 | } | |
1852 | ||
1853 | board = dmi_get_system_info(DMI_BOARD_NAME); | |
98faf436 | 1854 | if (board && is_dmi_valid(board)) { |
345233d7 LG |
1855 | len = strlen(card->dmi_longname); |
1856 | snprintf(card->dmi_longname + len, | |
1857 | longname_buf_size - len, | |
1858 | "-%s", board); | |
1859 | ||
1860 | len++; | |
1861 | if (len < longname_buf_size) | |
1862 | cleanup_dmi_name(card->dmi_longname + len); | |
1863 | } else if (!product) { | |
1864 | /* fall back to using legacy name */ | |
1865 | dev_warn(card->dev, "ASoC: no DMI board/product name!\n"); | |
1866 | return 0; | |
1867 | } | |
1868 | ||
1869 | /* Add flavour to dmi long name */ | |
1870 | if (flavour) { | |
1871 | len = strlen(card->dmi_longname); | |
1872 | snprintf(card->dmi_longname + len, | |
1873 | longname_buf_size - len, | |
1874 | "-%s", flavour); | |
1875 | ||
1876 | len++; | |
1877 | if (len < longname_buf_size) | |
1878 | cleanup_dmi_name(card->dmi_longname + len); | |
1879 | } | |
1880 | ||
1881 | /* set the card long name */ | |
1882 | card->long_name = card->dmi_longname; | |
1883 | ||
1884 | return 0; | |
1885 | } | |
1886 | EXPORT_SYMBOL_GPL(snd_soc_set_dmi_name); | |
1f5a4535 | 1887 | #endif /* CONFIG_DMI */ |
345233d7 | 1888 | |
a655de80 LG |
1889 | static void soc_check_tplg_fes(struct snd_soc_card *card) |
1890 | { | |
1891 | struct snd_soc_component *component; | |
1892 | const struct snd_soc_component_driver *comp_drv; | |
1893 | struct snd_soc_dai_link *dai_link; | |
1894 | int i; | |
1895 | ||
368dee94 | 1896 | for_each_component(component) { |
a655de80 LG |
1897 | |
1898 | /* does this component override FEs ? */ | |
1899 | if (!component->driver->ignore_machine) | |
1900 | continue; | |
1901 | ||
1902 | /* for this machine ? */ | |
1903 | if (strcmp(component->driver->ignore_machine, | |
1904 | card->dev->driver->name)) | |
1905 | continue; | |
1906 | ||
1907 | /* machine matches, so override the rtd data */ | |
7fe072b4 | 1908 | for_each_card_prelinks(card, i, dai_link) { |
a655de80 LG |
1909 | |
1910 | /* ignore this FE */ | |
1911 | if (dai_link->dynamic) { | |
1912 | dai_link->ignore = true; | |
1913 | continue; | |
1914 | } | |
1915 | ||
1916 | dev_info(card->dev, "info: override FE DAI link %s\n", | |
1917 | card->dai_link[i].name); | |
1918 | ||
1919 | /* override platform component */ | |
daecf46e KM |
1920 | if (snd_soc_init_platform(card, dai_link) < 0) { |
1921 | dev_err(card->dev, "init platform error"); | |
1922 | continue; | |
1923 | } | |
1924 | dai_link->platform->name = component->name; | |
a655de80 LG |
1925 | |
1926 | /* convert non BE into BE */ | |
1927 | dai_link->no_pcm = 1; | |
1928 | ||
1929 | /* override any BE fixups */ | |
1930 | dai_link->be_hw_params_fixup = | |
1931 | component->driver->be_hw_params_fixup; | |
1932 | ||
2c7b696a MZ |
1933 | /* |
1934 | * most BE links don't set stream name, so set it to | |
a655de80 LG |
1935 | * dai link name if it's NULL to help bind widgets. |
1936 | */ | |
1937 | if (!dai_link->stream_name) | |
1938 | dai_link->stream_name = dai_link->name; | |
1939 | } | |
1940 | ||
1941 | /* Inform userspace we are using alternate topology */ | |
1942 | if (component->driver->topology_name_prefix) { | |
1943 | ||
2c7b696a | 1944 | /* topology shortname created? */ |
a655de80 LG |
1945 | if (!card->topology_shortname_created) { |
1946 | comp_drv = component->driver; | |
1947 | ||
1948 | snprintf(card->topology_shortname, 32, "%s-%s", | |
1949 | comp_drv->topology_name_prefix, | |
1950 | card->name); | |
1951 | card->topology_shortname_created = true; | |
1952 | } | |
1953 | ||
1954 | /* use topology shortname */ | |
1955 | card->name = card->topology_shortname; | |
1956 | } | |
1957 | } | |
1958 | } | |
1959 | ||
b19e6e7b | 1960 | static int snd_soc_instantiate_card(struct snd_soc_card *card) |
f0fba2ad | 1961 | { |
1a497983 | 1962 | struct snd_soc_pcm_runtime *rtd; |
61b0088b | 1963 | struct snd_soc_dai_link *dai_link; |
ce64c8b9 | 1964 | int ret, i, order; |
fe3e78e0 | 1965 | |
34e81ab4 | 1966 | mutex_lock(&client_mutex); |
01b9d99a | 1967 | mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT); |
dbe21408 | 1968 | |
a655de80 LG |
1969 | /* check whether any platform is ignore machine FE and using topology */ |
1970 | soc_check_tplg_fes(card); | |
1971 | ||
f0fba2ad | 1972 | /* bind DAIs */ |
7fe072b4 KM |
1973 | for_each_card_prelinks(card, i, dai_link) { |
1974 | ret = soc_bind_dai_link(card, dai_link); | |
b19e6e7b MB |
1975 | if (ret != 0) |
1976 | goto base_error; | |
1977 | } | |
fe3e78e0 | 1978 | |
44c69bb1 | 1979 | /* bind aux_devs too */ |
b19e6e7b | 1980 | for (i = 0; i < card->num_aux_devs; i++) { |
44c69bb1 | 1981 | ret = soc_bind_aux_dev(card, i); |
b19e6e7b MB |
1982 | if (ret != 0) |
1983 | goto base_error; | |
f0fba2ad | 1984 | } |
435c5e25 | 1985 | |
f8f80361 | 1986 | /* add predefined DAI links to the list */ |
7fe072b4 KM |
1987 | for_each_card_prelinks(card, i, dai_link) |
1988 | snd_soc_add_dai_link(card, dai_link); | |
f8f80361 | 1989 | |
f0fba2ad | 1990 | /* card bind complete so register a sound card */ |
102b5a8d | 1991 | ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, |
f0fba2ad LG |
1992 | card->owner, 0, &card->snd_card); |
1993 | if (ret < 0) { | |
10e8aa9a MM |
1994 | dev_err(card->dev, |
1995 | "ASoC: can't create sound card for card %s: %d\n", | |
1996 | card->name, ret); | |
b19e6e7b | 1997 | goto base_error; |
f0fba2ad | 1998 | } |
f0fba2ad | 1999 | |
0757d834 LPC |
2000 | soc_init_card_debugfs(card); |
2001 | ||
e37a4970 MB |
2002 | card->dapm.bias_level = SND_SOC_BIAS_OFF; |
2003 | card->dapm.dev = card->dev; | |
2004 | card->dapm.card = card; | |
2005 | list_add(&card->dapm.list, &card->dapm_list); | |
2006 | ||
d5d1e0be LPC |
2007 | #ifdef CONFIG_DEBUG_FS |
2008 | snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root); | |
2009 | #endif | |
2010 | ||
88ee1c61 | 2011 | #ifdef CONFIG_PM_SLEEP |
f0fba2ad LG |
2012 | /* deferred resume work */ |
2013 | INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); | |
2014 | #endif | |
db2a4165 | 2015 | |
9a841ebb MB |
2016 | if (card->dapm_widgets) |
2017 | snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets, | |
2018 | card->num_dapm_widgets); | |
2019 | ||
f23e860e NC |
2020 | if (card->of_dapm_widgets) |
2021 | snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets, | |
2022 | card->num_of_dapm_widgets); | |
2023 | ||
f0fba2ad LG |
2024 | /* initialise the sound card only once */ |
2025 | if (card->probe) { | |
e7361ec4 | 2026 | ret = card->probe(card); |
f0fba2ad LG |
2027 | if (ret < 0) |
2028 | goto card_probe_error; | |
2029 | } | |
fe3e78e0 | 2030 | |
62ae68fa | 2031 | /* probe all components used by DAI links on this card */ |
1a1035a9 | 2032 | for_each_comp_order(order) { |
bcb1fd1f | 2033 | for_each_card_rtds(card, rtd) { |
1a497983 | 2034 | ret = soc_probe_link_components(card, rtd, order); |
0168bf0d | 2035 | if (ret < 0) { |
f110bfc7 LG |
2036 | dev_err(card->dev, |
2037 | "ASoC: failed to instantiate card %d\n", | |
2038 | ret); | |
62ae68fa SW |
2039 | goto probe_dai_err; |
2040 | } | |
2041 | } | |
2042 | } | |
2043 | ||
f2ed6b07 ML |
2044 | /* probe auxiliary components */ |
2045 | ret = soc_probe_aux_devices(card); | |
2046 | if (ret < 0) | |
2047 | goto probe_dai_err; | |
2048 | ||
2c7b696a MZ |
2049 | /* |
2050 | * Find new DAI links added during probing components and bind them. | |
61b0088b ML |
2051 | * Components with topology may bring new DAIs and DAI links. |
2052 | */ | |
98061fdb | 2053 | for_each_card_links(card, dai_link) { |
61b0088b ML |
2054 | if (soc_is_dai_link_bound(card, dai_link)) |
2055 | continue; | |
2056 | ||
2057 | ret = soc_init_dai_link(card, dai_link); | |
2058 | if (ret) | |
2059 | goto probe_dai_err; | |
2060 | ret = soc_bind_dai_link(card, dai_link); | |
2061 | if (ret) | |
2062 | goto probe_dai_err; | |
2063 | } | |
2064 | ||
62ae68fa | 2065 | /* probe all DAI links on this card */ |
1a1035a9 | 2066 | for_each_comp_order(order) { |
bcb1fd1f | 2067 | for_each_card_rtds(card, rtd) { |
1a497983 | 2068 | ret = soc_probe_link_dais(card, rtd, order); |
62ae68fa | 2069 | if (ret < 0) { |
f110bfc7 LG |
2070 | dev_err(card->dev, |
2071 | "ASoC: failed to instantiate card %d\n", | |
2072 | ret); | |
0168bf0d LG |
2073 | goto probe_dai_err; |
2074 | } | |
f0fba2ad LG |
2075 | } |
2076 | } | |
db2a4165 | 2077 | |
888df395 | 2078 | snd_soc_dapm_link_dai_widgets(card); |
b893ea5f | 2079 | snd_soc_dapm_connect_dai_link_widgets(card); |
888df395 | 2080 | |
b7af1daf | 2081 | if (card->controls) |
2c7b696a MZ |
2082 | snd_soc_add_card_controls(card, card->controls, |
2083 | card->num_controls); | |
b7af1daf | 2084 | |
b8ad29de MB |
2085 | if (card->dapm_routes) |
2086 | snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, | |
2087 | card->num_dapm_routes); | |
2088 | ||
f23e860e NC |
2089 | if (card->of_dapm_routes) |
2090 | snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes, | |
2091 | card->num_of_dapm_routes); | |
75d9ac46 | 2092 | |
861886d3 TI |
2093 | /* try to set some sane longname if DMI is available */ |
2094 | snd_soc_set_dmi_name(card, NULL); | |
2095 | ||
f0fba2ad | 2096 | snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname), |
f0fba2ad | 2097 | "%s", card->name); |
22de71ba LG |
2098 | snprintf(card->snd_card->longname, sizeof(card->snd_card->longname), |
2099 | "%s", card->long_name ? card->long_name : card->name); | |
f0e8ed85 MB |
2100 | snprintf(card->snd_card->driver, sizeof(card->snd_card->driver), |
2101 | "%s", card->driver_name ? card->driver_name : card->name); | |
2102 | for (i = 0; i < ARRAY_SIZE(card->snd_card->driver); i++) { | |
2103 | switch (card->snd_card->driver[i]) { | |
2104 | case '_': | |
2105 | case '-': | |
2106 | case '\0': | |
2107 | break; | |
2108 | default: | |
2109 | if (!isalnum(card->snd_card->driver[i])) | |
2110 | card->snd_card->driver[i] = '_'; | |
2111 | break; | |
2112 | } | |
2113 | } | |
f0fba2ad | 2114 | |
28e9ad92 MB |
2115 | if (card->late_probe) { |
2116 | ret = card->late_probe(card); | |
2117 | if (ret < 0) { | |
f110bfc7 | 2118 | dev_err(card->dev, "ASoC: %s late_probe() failed: %d\n", |
28e9ad92 MB |
2119 | card->name, ret); |
2120 | goto probe_aux_dev_err; | |
2121 | } | |
2122 | } | |
2123 | ||
824ef826 | 2124 | snd_soc_dapm_new_widgets(card); |
8c193b8d | 2125 | |
f0fba2ad LG |
2126 | ret = snd_card_register(card->snd_card); |
2127 | if (ret < 0) { | |
f110bfc7 LG |
2128 | dev_err(card->dev, "ASoC: failed to register soundcard %d\n", |
2129 | ret); | |
6b3ed785 | 2130 | goto probe_aux_dev_err; |
db2a4165 FM |
2131 | } |
2132 | ||
f0fba2ad | 2133 | card->instantiated = 1; |
882eab6c | 2134 | dapm_mark_endpoints_dirty(card); |
4f4c0072 | 2135 | snd_soc_dapm_sync(&card->dapm); |
f0fba2ad | 2136 | mutex_unlock(&card->mutex); |
34e81ab4 | 2137 | mutex_unlock(&client_mutex); |
b19e6e7b MB |
2138 | |
2139 | return 0; | |
f0fba2ad | 2140 | |
2eea392d | 2141 | probe_aux_dev_err: |
f2ed6b07 | 2142 | soc_remove_aux_devices(card); |
2eea392d | 2143 | |
f0fba2ad | 2144 | probe_dai_err: |
0671fd8e | 2145 | soc_remove_dai_links(card); |
f0fba2ad LG |
2146 | |
2147 | card_probe_error: | |
87506549 | 2148 | if (card->remove) |
e7361ec4 | 2149 | card->remove(card); |
f0fba2ad | 2150 | |
2210438b | 2151 | snd_soc_dapm_free(&card->dapm); |
0757d834 | 2152 | soc_cleanup_card_debugfs(card); |
f0fba2ad LG |
2153 | snd_card_free(card->snd_card); |
2154 | ||
b19e6e7b | 2155 | base_error: |
1a497983 | 2156 | soc_remove_pcm_runtimes(card); |
f0fba2ad | 2157 | mutex_unlock(&card->mutex); |
34e81ab4 | 2158 | mutex_unlock(&client_mutex); |
db2a4165 | 2159 | |
b19e6e7b | 2160 | return ret; |
435c5e25 MB |
2161 | } |
2162 | ||
2163 | /* probes a new socdev */ | |
2164 | static int soc_probe(struct platform_device *pdev) | |
2165 | { | |
f0fba2ad | 2166 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
435c5e25 | 2167 | |
70a7ca34 VK |
2168 | /* |
2169 | * no card, so machine driver should be registering card | |
2170 | * we should not be here in that case so ret error | |
2171 | */ | |
2172 | if (!card) | |
2173 | return -EINVAL; | |
2174 | ||
fe4085e8 | 2175 | dev_warn(&pdev->dev, |
f110bfc7 | 2176 | "ASoC: machine %s should use snd_soc_register_card()\n", |
fe4085e8 MB |
2177 | card->name); |
2178 | ||
435c5e25 MB |
2179 | /* Bodge while we unpick instantiation */ |
2180 | card->dev = &pdev->dev; | |
f0fba2ad | 2181 | |
28d528c8 | 2182 | return snd_soc_register_card(card); |
db2a4165 FM |
2183 | } |
2184 | ||
b0e26485 | 2185 | static int soc_cleanup_card_resources(struct snd_soc_card *card) |
db2a4165 | 2186 | { |
1a497983 | 2187 | struct snd_soc_pcm_runtime *rtd; |
db2a4165 | 2188 | |
b0e26485 | 2189 | /* make sure any delayed work runs */ |
bcb1fd1f | 2190 | for_each_card_rtds(card, rtd) |
43829731 | 2191 | flush_delayed_work(&rtd->delayed_work); |
914dc182 | 2192 | |
4efda5f2 TI |
2193 | /* free the ALSA card at first; this syncs with pending operations */ |
2194 | snd_card_free(card->snd_card); | |
2195 | ||
b0e26485 | 2196 | /* remove and free each DAI */ |
0671fd8e | 2197 | soc_remove_dai_links(card); |
1a497983 | 2198 | soc_remove_pcm_runtimes(card); |
2eea392d | 2199 | |
f2ed6b07 ML |
2200 | /* remove auxiliary devices */ |
2201 | soc_remove_aux_devices(card); | |
2202 | ||
d1e81428 | 2203 | snd_soc_dapm_free(&card->dapm); |
b0e26485 | 2204 | soc_cleanup_card_debugfs(card); |
f0fba2ad | 2205 | |
b0e26485 VK |
2206 | /* remove the card */ |
2207 | if (card->remove) | |
e7361ec4 | 2208 | card->remove(card); |
a6052154 | 2209 | |
b0e26485 | 2210 | return 0; |
b0e26485 VK |
2211 | } |
2212 | ||
2213 | /* removes a socdev */ | |
2214 | static int soc_remove(struct platform_device *pdev) | |
2215 | { | |
2216 | struct snd_soc_card *card = platform_get_drvdata(pdev); | |
db2a4165 | 2217 | |
c5af3a2e | 2218 | snd_soc_unregister_card(card); |
db2a4165 FM |
2219 | return 0; |
2220 | } | |
2221 | ||
6f8ab4ac | 2222 | int snd_soc_poweroff(struct device *dev) |
51737470 | 2223 | { |
6f8ab4ac | 2224 | struct snd_soc_card *card = dev_get_drvdata(dev); |
1a497983 | 2225 | struct snd_soc_pcm_runtime *rtd; |
51737470 MB |
2226 | |
2227 | if (!card->instantiated) | |
416356fc | 2228 | return 0; |
51737470 | 2229 | |
2c7b696a MZ |
2230 | /* |
2231 | * Flush out pmdown_time work - we actually do want to run it | |
2232 | * now, we're shutting down so no imminent restart. | |
2233 | */ | |
bcb1fd1f | 2234 | for_each_card_rtds(card, rtd) |
43829731 | 2235 | flush_delayed_work(&rtd->delayed_work); |
51737470 | 2236 | |
f0fba2ad | 2237 | snd_soc_dapm_shutdown(card); |
416356fc | 2238 | |
988e8cc4 | 2239 | /* deactivate pins to sleep state */ |
bcb1fd1f | 2240 | for_each_card_rtds(card, rtd) { |
88bd870f | 2241 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
0b7990e3 | 2242 | struct snd_soc_dai *codec_dai; |
1a497983 | 2243 | int i; |
88bd870f | 2244 | |
988e8cc4 | 2245 | pinctrl_pm_select_sleep_state(cpu_dai->dev); |
0b7990e3 | 2246 | for_each_rtd_codec_dai(rtd, i, codec_dai) { |
88bd870f BC |
2247 | pinctrl_pm_select_sleep_state(codec_dai->dev); |
2248 | } | |
988e8cc4 NC |
2249 | } |
2250 | ||
416356fc | 2251 | return 0; |
51737470 | 2252 | } |
6f8ab4ac | 2253 | EXPORT_SYMBOL_GPL(snd_soc_poweroff); |
51737470 | 2254 | |
6f8ab4ac | 2255 | const struct dev_pm_ops snd_soc_pm_ops = { |
b1dd5897 VK |
2256 | .suspend = snd_soc_suspend, |
2257 | .resume = snd_soc_resume, | |
2258 | .freeze = snd_soc_suspend, | |
2259 | .thaw = snd_soc_resume, | |
6f8ab4ac | 2260 | .poweroff = snd_soc_poweroff, |
b1dd5897 | 2261 | .restore = snd_soc_resume, |
416356fc | 2262 | }; |
deb2607e | 2263 | EXPORT_SYMBOL_GPL(snd_soc_pm_ops); |
416356fc | 2264 | |
db2a4165 FM |
2265 | /* ASoC platform driver */ |
2266 | static struct platform_driver soc_driver = { | |
2267 | .driver = { | |
2268 | .name = "soc-audio", | |
6f8ab4ac | 2269 | .pm = &snd_soc_pm_ops, |
db2a4165 FM |
2270 | }, |
2271 | .probe = soc_probe, | |
2272 | .remove = soc_remove, | |
db2a4165 FM |
2273 | }; |
2274 | ||
db2a4165 FM |
2275 | /** |
2276 | * snd_soc_cnew - create new control | |
2277 | * @_template: control template | |
2278 | * @data: control private data | |
ac11a2b3 | 2279 | * @long_name: control long name |
efb7ac3f | 2280 | * @prefix: control name prefix |
db2a4165 FM |
2281 | * |
2282 | * Create a new mixer control from a template control. | |
2283 | * | |
2284 | * Returns 0 for success, else error. | |
2285 | */ | |
2286 | struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, | |
3056557f | 2287 | void *data, const char *long_name, |
efb7ac3f | 2288 | const char *prefix) |
db2a4165 FM |
2289 | { |
2290 | struct snd_kcontrol_new template; | |
efb7ac3f MB |
2291 | struct snd_kcontrol *kcontrol; |
2292 | char *name = NULL; | |
db2a4165 FM |
2293 | |
2294 | memcpy(&template, _template, sizeof(template)); | |
db2a4165 FM |
2295 | template.index = 0; |
2296 | ||
efb7ac3f MB |
2297 | if (!long_name) |
2298 | long_name = template.name; | |
2299 | ||
2300 | if (prefix) { | |
2b581074 | 2301 | name = kasprintf(GFP_KERNEL, "%s %s", prefix, long_name); |
efb7ac3f MB |
2302 | if (!name) |
2303 | return NULL; | |
2304 | ||
efb7ac3f MB |
2305 | template.name = name; |
2306 | } else { | |
2307 | template.name = long_name; | |
2308 | } | |
2309 | ||
2310 | kcontrol = snd_ctl_new1(&template, data); | |
2311 | ||
2312 | kfree(name); | |
2313 | ||
2314 | return kcontrol; | |
db2a4165 FM |
2315 | } |
2316 | EXPORT_SYMBOL_GPL(snd_soc_cnew); | |
2317 | ||
022658be LG |
2318 | static int snd_soc_add_controls(struct snd_card *card, struct device *dev, |
2319 | const struct snd_kcontrol_new *controls, int num_controls, | |
2320 | const char *prefix, void *data) | |
2321 | { | |
2322 | int err, i; | |
2323 | ||
2324 | for (i = 0; i < num_controls; i++) { | |
2325 | const struct snd_kcontrol_new *control = &controls[i]; | |
2c7b696a | 2326 | |
022658be LG |
2327 | err = snd_ctl_add(card, snd_soc_cnew(control, data, |
2328 | control->name, prefix)); | |
2329 | if (err < 0) { | |
f110bfc7 LG |
2330 | dev_err(dev, "ASoC: Failed to add %s: %d\n", |
2331 | control->name, err); | |
022658be LG |
2332 | return err; |
2333 | } | |
2334 | } | |
2335 | ||
2336 | return 0; | |
2337 | } | |
2338 | ||
4fefd698 DP |
2339 | struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card, |
2340 | const char *name) | |
2341 | { | |
2342 | struct snd_card *card = soc_card->snd_card; | |
2343 | struct snd_kcontrol *kctl; | |
2344 | ||
2345 | if (unlikely(!name)) | |
2346 | return NULL; | |
2347 | ||
2348 | list_for_each_entry(kctl, &card->controls, list) | |
2349 | if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) | |
2350 | return kctl; | |
2351 | return NULL; | |
2352 | } | |
2353 | EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol); | |
2354 | ||
0f2780ad LPC |
2355 | /** |
2356 | * snd_soc_add_component_controls - Add an array of controls to a component. | |
2357 | * | |
2358 | * @component: Component to add controls to | |
2359 | * @controls: Array of controls to add | |
2360 | * @num_controls: Number of elements in the array | |
2361 | * | |
2362 | * Return: 0 for success, else error. | |
2363 | */ | |
2364 | int snd_soc_add_component_controls(struct snd_soc_component *component, | |
2365 | const struct snd_kcontrol_new *controls, unsigned int num_controls) | |
2366 | { | |
2367 | struct snd_card *card = component->card->snd_card; | |
2368 | ||
2369 | return snd_soc_add_controls(card, component->dev, controls, | |
2370 | num_controls, component->name_prefix, component); | |
2371 | } | |
2372 | EXPORT_SYMBOL_GPL(snd_soc_add_component_controls); | |
2373 | ||
022658be LG |
2374 | /** |
2375 | * snd_soc_add_card_controls - add an array of controls to a SoC card. | |
2376 | * Convenience function to add a list of controls. | |
2377 | * | |
2378 | * @soc_card: SoC card to add controls to | |
2379 | * @controls: array of controls to add | |
2380 | * @num_controls: number of elements in the array | |
2381 | * | |
2382 | * Return 0 for success, else error. | |
2383 | */ | |
2384 | int snd_soc_add_card_controls(struct snd_soc_card *soc_card, | |
2385 | const struct snd_kcontrol_new *controls, int num_controls) | |
2386 | { | |
2387 | struct snd_card *card = soc_card->snd_card; | |
2388 | ||
2389 | return snd_soc_add_controls(card, soc_card->dev, controls, num_controls, | |
2390 | NULL, soc_card); | |
2391 | } | |
2392 | EXPORT_SYMBOL_GPL(snd_soc_add_card_controls); | |
2393 | ||
2394 | /** | |
2395 | * snd_soc_add_dai_controls - add an array of controls to a DAI. | |
2396 | * Convienience function to add a list of controls. | |
2397 | * | |
2398 | * @dai: DAI to add controls to | |
2399 | * @controls: array of controls to add | |
2400 | * @num_controls: number of elements in the array | |
2401 | * | |
2402 | * Return 0 for success, else error. | |
2403 | */ | |
2404 | int snd_soc_add_dai_controls(struct snd_soc_dai *dai, | |
2405 | const struct snd_kcontrol_new *controls, int num_controls) | |
2406 | { | |
313665b9 | 2407 | struct snd_card *card = dai->component->card->snd_card; |
022658be LG |
2408 | |
2409 | return snd_soc_add_controls(card, dai->dev, controls, num_controls, | |
2410 | NULL, dai); | |
2411 | } | |
2412 | EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls); | |
2413 | ||
8c6529db LG |
2414 | /** |
2415 | * snd_soc_dai_set_sysclk - configure DAI system or master clock. | |
2416 | * @dai: DAI | |
2417 | * @clk_id: DAI specific clock ID | |
2418 | * @freq: new clock frequency in Hz | |
2419 | * @dir: new clock direction - input/output. | |
2420 | * | |
2421 | * Configures the DAI master (MCLK) or system (SYSCLK) clocking. | |
2422 | */ | |
2423 | int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, | |
2424 | unsigned int freq, int dir) | |
2425 | { | |
46471925 | 2426 | if (dai->driver->ops->set_sysclk) |
f0fba2ad | 2427 | return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir); |
71ccef0d KM |
2428 | |
2429 | return snd_soc_component_set_sysclk(dai->component, clk_id, 0, | |
2430 | freq, dir); | |
8c6529db LG |
2431 | } |
2432 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); | |
2433 | ||
71ccef0d KM |
2434 | /** |
2435 | * snd_soc_component_set_sysclk - configure COMPONENT system or master clock. | |
2436 | * @component: COMPONENT | |
2437 | * @clk_id: DAI specific clock ID | |
2438 | * @source: Source for the clock | |
2439 | * @freq: new clock frequency in Hz | |
2440 | * @dir: new clock direction - input/output. | |
2441 | * | |
2442 | * Configures the CODEC master (MCLK) or system (SYSCLK) clocking. | |
2443 | */ | |
2c7b696a MZ |
2444 | int snd_soc_component_set_sysclk(struct snd_soc_component *component, |
2445 | int clk_id, int source, unsigned int freq, | |
2446 | int dir) | |
71ccef0d | 2447 | { |
71ccef0d KM |
2448 | if (component->driver->set_sysclk) |
2449 | return component->driver->set_sysclk(component, clk_id, source, | |
2450 | freq, dir); | |
2451 | ||
2452 | return -ENOTSUPP; | |
2453 | } | |
2454 | EXPORT_SYMBOL_GPL(snd_soc_component_set_sysclk); | |
2455 | ||
8c6529db LG |
2456 | /** |
2457 | * snd_soc_dai_set_clkdiv - configure DAI clock dividers. | |
2458 | * @dai: DAI | |
ac11a2b3 | 2459 | * @div_id: DAI specific clock divider ID |
8c6529db LG |
2460 | * @div: new clock divisor. |
2461 | * | |
2462 | * Configures the clock dividers. This is used to derive the best DAI bit and | |
2463 | * frame clocks from the system or master clock. It's best to set the DAI bit | |
2464 | * and frame clocks as low as possible to save system power. | |
2465 | */ | |
2466 | int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, | |
2467 | int div_id, int div) | |
2468 | { | |
46471925 | 2469 | if (dai->driver->ops->set_clkdiv) |
f0fba2ad | 2470 | return dai->driver->ops->set_clkdiv(dai, div_id, div); |
8c6529db LG |
2471 | else |
2472 | return -EINVAL; | |
2473 | } | |
2474 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); | |
2475 | ||
2476 | /** | |
2477 | * snd_soc_dai_set_pll - configure DAI PLL. | |
2478 | * @dai: DAI | |
2479 | * @pll_id: DAI specific PLL ID | |
85488037 | 2480 | * @source: DAI specific source for the PLL |
8c6529db LG |
2481 | * @freq_in: PLL input clock frequency in Hz |
2482 | * @freq_out: requested PLL output clock frequency in Hz | |
2483 | * | |
2484 | * Configures and enables PLL to generate output clock based on input clock. | |
2485 | */ | |
85488037 MB |
2486 | int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, |
2487 | unsigned int freq_in, unsigned int freq_out) | |
8c6529db | 2488 | { |
46471925 | 2489 | if (dai->driver->ops->set_pll) |
f0fba2ad | 2490 | return dai->driver->ops->set_pll(dai, pll_id, source, |
85488037 | 2491 | freq_in, freq_out); |
ef641e5d KM |
2492 | |
2493 | return snd_soc_component_set_pll(dai->component, pll_id, source, | |
2494 | freq_in, freq_out); | |
8c6529db LG |
2495 | } |
2496 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); | |
2497 | ||
ef641e5d KM |
2498 | /* |
2499 | * snd_soc_component_set_pll - configure component PLL. | |
2500 | * @component: COMPONENT | |
2501 | * @pll_id: DAI specific PLL ID | |
2502 | * @source: DAI specific source for the PLL | |
2503 | * @freq_in: PLL input clock frequency in Hz | |
2504 | * @freq_out: requested PLL output clock frequency in Hz | |
2505 | * | |
2506 | * Configures and enables PLL to generate output clock based on input clock. | |
2507 | */ | |
2508 | int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id, | |
2509 | int source, unsigned int freq_in, | |
2510 | unsigned int freq_out) | |
2511 | { | |
ef641e5d KM |
2512 | if (component->driver->set_pll) |
2513 | return component->driver->set_pll(component, pll_id, source, | |
2c7b696a | 2514 | freq_in, freq_out); |
ef641e5d KM |
2515 | |
2516 | return -EINVAL; | |
2517 | } | |
2518 | EXPORT_SYMBOL_GPL(snd_soc_component_set_pll); | |
2519 | ||
e54cf76b LG |
2520 | /** |
2521 | * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio. | |
2522 | * @dai: DAI | |
231b86b1 | 2523 | * @ratio: Ratio of BCLK to Sample rate. |
e54cf76b LG |
2524 | * |
2525 | * Configures the DAI for a preset BCLK to sample rate ratio. | |
2526 | */ | |
2527 | int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) | |
2528 | { | |
46471925 | 2529 | if (dai->driver->ops->set_bclk_ratio) |
e54cf76b LG |
2530 | return dai->driver->ops->set_bclk_ratio(dai, ratio); |
2531 | else | |
2532 | return -EINVAL; | |
2533 | } | |
2534 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio); | |
2535 | ||
8c6529db LG |
2536 | /** |
2537 | * snd_soc_dai_set_fmt - configure DAI hardware audio format. | |
2538 | * @dai: DAI | |
bb19ba2a | 2539 | * @fmt: SND_SOC_DAIFMT_* format value. |
8c6529db LG |
2540 | * |
2541 | * Configures the DAI hardware format and clocking. | |
2542 | */ | |
2543 | int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |
2544 | { | |
5e4ba569 SG |
2545 | if (dai->driver->ops->set_fmt == NULL) |
2546 | return -ENOTSUPP; | |
2547 | return dai->driver->ops->set_fmt(dai, fmt); | |
8c6529db LG |
2548 | } |
2549 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); | |
2550 | ||
89c67857 | 2551 | /** |
e5c21514 | 2552 | * snd_soc_xlate_tdm_slot - generate tx/rx slot mask. |
89c67857 XL |
2553 | * @slots: Number of slots in use. |
2554 | * @tx_mask: bitmask representing active TX slots. | |
2555 | * @rx_mask: bitmask representing active RX slots. | |
2556 | * | |
2557 | * Generates the TDM tx and rx slot default masks for DAI. | |
2558 | */ | |
e5c21514 | 2559 | static int snd_soc_xlate_tdm_slot_mask(unsigned int slots, |
2c7b696a MZ |
2560 | unsigned int *tx_mask, |
2561 | unsigned int *rx_mask) | |
89c67857 XL |
2562 | { |
2563 | if (*tx_mask || *rx_mask) | |
2564 | return 0; | |
2565 | ||
2566 | if (!slots) | |
2567 | return -EINVAL; | |
2568 | ||
2569 | *tx_mask = (1 << slots) - 1; | |
2570 | *rx_mask = (1 << slots) - 1; | |
2571 | ||
2572 | return 0; | |
2573 | } | |
2574 | ||
8c6529db | 2575 | /** |
e46c9366 LPC |
2576 | * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation |
2577 | * @dai: The DAI to configure | |
a5479e38 DR |
2578 | * @tx_mask: bitmask representing active TX slots. |
2579 | * @rx_mask: bitmask representing active RX slots. | |
8c6529db | 2580 | * @slots: Number of slots in use. |
a5479e38 | 2581 | * @slot_width: Width in bits for each slot. |
8c6529db | 2582 | * |
e46c9366 LPC |
2583 | * This function configures the specified DAI for TDM operation. @slot contains |
2584 | * the total number of slots of the TDM stream and @slot_with the width of each | |
2585 | * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the | |
2586 | * active slots of the TDM stream for the specified DAI, i.e. which slots the | |
2587 | * DAI should write to or read from. If a bit is set the corresponding slot is | |
2588 | * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to | |
2589 | * the first slot, bit 1 to the second slot and so on. The first active slot | |
2590 | * maps to the first channel of the DAI, the second active slot to the second | |
2591 | * channel and so on. | |
2592 | * | |
2593 | * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask, | |
2594 | * @rx_mask and @slot_width will be ignored. | |
2595 | * | |
2596 | * Returns 0 on success, a negative error code otherwise. | |
8c6529db LG |
2597 | */ |
2598 | int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, | |
a5479e38 | 2599 | unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) |
8c6529db | 2600 | { |
46471925 | 2601 | if (dai->driver->ops->xlate_tdm_slot_mask) |
e5c21514 | 2602 | dai->driver->ops->xlate_tdm_slot_mask(slots, |
89c67857 XL |
2603 | &tx_mask, &rx_mask); |
2604 | else | |
e5c21514 | 2605 | snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); |
89c67857 | 2606 | |
88bd870f BC |
2607 | dai->tx_mask = tx_mask; |
2608 | dai->rx_mask = rx_mask; | |
2609 | ||
46471925 | 2610 | if (dai->driver->ops->set_tdm_slot) |
f0fba2ad | 2611 | return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, |
a5479e38 | 2612 | slots, slot_width); |
8c6529db | 2613 | else |
b2cbb6e1 | 2614 | return -ENOTSUPP; |
8c6529db LG |
2615 | } |
2616 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); | |
2617 | ||
472df3cb BS |
2618 | /** |
2619 | * snd_soc_dai_set_channel_map - configure DAI audio channel map | |
2620 | * @dai: DAI | |
2621 | * @tx_num: how many TX channels | |
2622 | * @tx_slot: pointer to an array which imply the TX slot number channel | |
2623 | * 0~num-1 uses | |
2624 | * @rx_num: how many RX channels | |
2625 | * @rx_slot: pointer to an array which imply the RX slot number channel | |
2626 | * 0~num-1 uses | |
2627 | * | |
2628 | * configure the relationship between channel number and TDM slot number. | |
2629 | */ | |
2630 | int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, | |
2631 | unsigned int tx_num, unsigned int *tx_slot, | |
2632 | unsigned int rx_num, unsigned int *rx_slot) | |
2633 | { | |
46471925 | 2634 | if (dai->driver->ops->set_channel_map) |
f0fba2ad | 2635 | return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot, |
472df3cb BS |
2636 | rx_num, rx_slot); |
2637 | else | |
2638 | return -EINVAL; | |
2639 | } | |
2640 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map); | |
2641 | ||
467b061f SK |
2642 | /** |
2643 | * snd_soc_dai_get_channel_map - Get DAI audio channel map | |
2644 | * @dai: DAI | |
2645 | * @tx_num: how many TX channels | |
2646 | * @tx_slot: pointer to an array which imply the TX slot number channel | |
2647 | * 0~num-1 uses | |
2648 | * @rx_num: how many RX channels | |
2649 | * @rx_slot: pointer to an array which imply the RX slot number channel | |
2650 | * 0~num-1 uses | |
2651 | */ | |
2652 | int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai, | |
2653 | unsigned int *tx_num, unsigned int *tx_slot, | |
2654 | unsigned int *rx_num, unsigned int *rx_slot) | |
2655 | { | |
2656 | if (dai->driver->ops->get_channel_map) | |
2657 | return dai->driver->ops->get_channel_map(dai, tx_num, tx_slot, | |
2658 | rx_num, rx_slot); | |
2659 | else | |
2660 | return -ENOTSUPP; | |
2661 | } | |
2662 | EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map); | |
2663 | ||
8c6529db LG |
2664 | /** |
2665 | * snd_soc_dai_set_tristate - configure DAI system or master clock. | |
2666 | * @dai: DAI | |
2667 | * @tristate: tristate enable | |
2668 | * | |
2669 | * Tristates the DAI so that others can use it. | |
2670 | */ | |
2671 | int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) | |
2672 | { | |
46471925 | 2673 | if (dai->driver->ops->set_tristate) |
f0fba2ad | 2674 | return dai->driver->ops->set_tristate(dai, tristate); |
8c6529db LG |
2675 | else |
2676 | return -EINVAL; | |
2677 | } | |
2678 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); | |
2679 | ||
2680 | /** | |
2681 | * snd_soc_dai_digital_mute - configure DAI system or master clock. | |
2682 | * @dai: DAI | |
2683 | * @mute: mute enable | |
da18396f | 2684 | * @direction: stream to mute |
8c6529db LG |
2685 | * |
2686 | * Mutes the DAI DAC. | |
2687 | */ | |
da18396f MB |
2688 | int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, |
2689 | int direction) | |
8c6529db | 2690 | { |
da18396f MB |
2691 | if (dai->driver->ops->mute_stream) |
2692 | return dai->driver->ops->mute_stream(dai, mute, direction); | |
2693 | else if (direction == SNDRV_PCM_STREAM_PLAYBACK && | |
2694 | dai->driver->ops->digital_mute) | |
f0fba2ad | 2695 | return dai->driver->ops->digital_mute(dai, mute); |
8c6529db | 2696 | else |
04570c62 | 2697 | return -ENOTSUPP; |
8c6529db LG |
2698 | } |
2699 | EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); | |
2700 | ||
e894efef SK |
2701 | static int snd_soc_bind_card(struct snd_soc_card *card) |
2702 | { | |
2703 | struct snd_soc_pcm_runtime *rtd; | |
2704 | int ret; | |
2705 | ||
2706 | ret = snd_soc_instantiate_card(card); | |
2707 | if (ret != 0) | |
2708 | return ret; | |
2709 | ||
2710 | /* deactivate pins to sleep state */ | |
2c7b696a | 2711 | for_each_card_rtds(card, rtd) { |
e894efef SK |
2712 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
2713 | struct snd_soc_dai *codec_dai; | |
2714 | int j; | |
2715 | ||
2716 | for_each_rtd_codec_dai(rtd, j, codec_dai) { | |
2717 | if (!codec_dai->active) | |
2718 | pinctrl_pm_select_sleep_state(codec_dai->dev); | |
2719 | } | |
2720 | ||
2721 | if (!cpu_dai->active) | |
2722 | pinctrl_pm_select_sleep_state(cpu_dai->dev); | |
2723 | } | |
2724 | ||
2725 | return ret; | |
2726 | } | |
2727 | ||
c5af3a2e MB |
2728 | /** |
2729 | * snd_soc_register_card - Register a card with the ASoC core | |
2730 | * | |
ac11a2b3 | 2731 | * @card: Card to register |
c5af3a2e | 2732 | * |
c5af3a2e | 2733 | */ |
70a7ca34 | 2734 | int snd_soc_register_card(struct snd_soc_card *card) |
c5af3a2e | 2735 | { |
923c5e61 | 2736 | int i, ret; |
7fe072b4 | 2737 | struct snd_soc_dai_link *link; |
f0fba2ad | 2738 | |
c5af3a2e MB |
2739 | if (!card->name || !card->dev) |
2740 | return -EINVAL; | |
2741 | ||
7fe072b4 | 2742 | for_each_card_prelinks(card, i, link) { |
5a504963 | 2743 | |
923c5e61 | 2744 | ret = soc_init_dai_link(card, link); |
88bd870f | 2745 | if (ret) { |
923c5e61 | 2746 | dev_err(card->dev, "ASoC: failed to init link %s\n", |
10e8aa9a | 2747 | link->name); |
923c5e61 | 2748 | return ret; |
5a504963 SW |
2749 | } |
2750 | } | |
2751 | ||
ed77cc12 MB |
2752 | dev_set_drvdata(card->dev, card); |
2753 | ||
111c6419 SW |
2754 | snd_soc_initialize_card_lists(card); |
2755 | ||
f8f80361 | 2756 | INIT_LIST_HEAD(&card->dai_link_list); |
f8f80361 | 2757 | |
1a497983 ML |
2758 | INIT_LIST_HEAD(&card->rtd_list); |
2759 | card->num_rtd = 0; | |
2760 | ||
db432b41 | 2761 | INIT_LIST_HEAD(&card->dapm_dirty); |
8a978234 | 2762 | INIT_LIST_HEAD(&card->dobj_list); |
c5af3a2e | 2763 | card->instantiated = 0; |
f0fba2ad | 2764 | mutex_init(&card->mutex); |
a73fb2df | 2765 | mutex_init(&card->dapm_mutex); |
c5af3a2e | 2766 | |
e894efef SK |
2767 | return snd_soc_bind_card(card); |
2768 | } | |
2769 | EXPORT_SYMBOL_GPL(snd_soc_register_card); | |
88bd870f | 2770 | |
e894efef SK |
2771 | static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) |
2772 | { | |
2773 | if (card->instantiated) { | |
2774 | card->instantiated = false; | |
2775 | snd_soc_dapm_shutdown(card); | |
2776 | soc_cleanup_card_resources(card); | |
2777 | if (!unregister) | |
2778 | list_add(&card->list, &unbind_card_list); | |
2779 | } else { | |
2780 | if (unregister) | |
2781 | list_del(&card->list); | |
988e8cc4 | 2782 | } |
c5af3a2e MB |
2783 | } |
2784 | ||
2785 | /** | |
2786 | * snd_soc_unregister_card - Unregister a card with the ASoC core | |
2787 | * | |
ac11a2b3 | 2788 | * @card: Card to unregister |
c5af3a2e | 2789 | * |
c5af3a2e | 2790 | */ |
70a7ca34 | 2791 | int snd_soc_unregister_card(struct snd_soc_card *card) |
c5af3a2e | 2792 | { |
e894efef SK |
2793 | snd_soc_unbind_card(card, true); |
2794 | dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); | |
c5af3a2e MB |
2795 | |
2796 | return 0; | |
2797 | } | |
70a7ca34 | 2798 | EXPORT_SYMBOL_GPL(snd_soc_unregister_card); |
c5af3a2e | 2799 | |
f0fba2ad LG |
2800 | /* |
2801 | * Simplify DAI link configuration by removing ".-1" from device names | |
2802 | * and sanitizing names. | |
2803 | */ | |
0b9a214a | 2804 | static char *fmt_single_name(struct device *dev, int *id) |
f0fba2ad LG |
2805 | { |
2806 | char *found, name[NAME_SIZE]; | |
2807 | int id1, id2; | |
2808 | ||
2809 | if (dev_name(dev) == NULL) | |
2810 | return NULL; | |
2811 | ||
58818a77 | 2812 | strlcpy(name, dev_name(dev), NAME_SIZE); |
f0fba2ad LG |
2813 | |
2814 | /* are we a "%s.%d" name (platform and SPI components) */ | |
2815 | found = strstr(name, dev->driver->name); | |
2816 | if (found) { | |
2817 | /* get ID */ | |
2818 | if (sscanf(&found[strlen(dev->driver->name)], ".%d", id) == 1) { | |
2819 | ||
2820 | /* discard ID from name if ID == -1 */ | |
2821 | if (*id == -1) | |
2822 | found[strlen(dev->driver->name)] = '\0'; | |
2823 | } | |
2824 | ||
2825 | } else { | |
2c7b696a | 2826 | /* I2C component devices are named "bus-addr" */ |
f0fba2ad LG |
2827 | if (sscanf(name, "%x-%x", &id1, &id2) == 2) { |
2828 | char tmp[NAME_SIZE]; | |
2829 | ||
2830 | /* create unique ID number from I2C addr and bus */ | |
05899446 | 2831 | *id = ((id1 & 0xffff) << 16) + id2; |
f0fba2ad LG |
2832 | |
2833 | /* sanitize component name for DAI link creation */ | |
2c7b696a MZ |
2834 | snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, |
2835 | name); | |
58818a77 | 2836 | strlcpy(name, tmp, NAME_SIZE); |
f0fba2ad LG |
2837 | } else |
2838 | *id = 0; | |
2839 | } | |
2840 | ||
2841 | return kstrdup(name, GFP_KERNEL); | |
2842 | } | |
2843 | ||
2844 | /* | |
2845 | * Simplify DAI link naming for single devices with multiple DAIs by removing | |
2846 | * any ".-1" and using the DAI name (instead of device name). | |
2847 | */ | |
2848 | static inline char *fmt_multiple_name(struct device *dev, | |
2849 | struct snd_soc_dai_driver *dai_drv) | |
2850 | { | |
2851 | if (dai_drv->name == NULL) { | |
10e8aa9a MM |
2852 | dev_err(dev, |
2853 | "ASoC: error - multiple DAI %s registered with no name\n", | |
2854 | dev_name(dev)); | |
f0fba2ad LG |
2855 | return NULL; |
2856 | } | |
2857 | ||
2858 | return kstrdup(dai_drv->name, GFP_KERNEL); | |
2859 | } | |
2860 | ||
9115171a | 2861 | /** |
32c9ba54 | 2862 | * snd_soc_unregister_dai - Unregister DAIs from the ASoC core |
9115171a | 2863 | * |
32c9ba54 | 2864 | * @component: The component for which the DAIs should be unregistered |
9115171a | 2865 | */ |
32c9ba54 | 2866 | static void snd_soc_unregister_dais(struct snd_soc_component *component) |
9115171a | 2867 | { |
5c1d5f09 | 2868 | struct snd_soc_dai *dai, *_dai; |
9115171a | 2869 | |
15a0c645 | 2870 | for_each_component_dais_safe(component, dai, _dai) { |
32c9ba54 LPC |
2871 | dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n", |
2872 | dai->name); | |
5c1d5f09 | 2873 | list_del(&dai->list); |
32c9ba54 | 2874 | kfree(dai->name); |
f0fba2ad | 2875 | kfree(dai); |
f0fba2ad | 2876 | } |
9115171a | 2877 | } |
9115171a | 2878 | |
5e4fb372 ML |
2879 | /* Create a DAI and add it to the component's DAI list */ |
2880 | static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, | |
2881 | struct snd_soc_dai_driver *dai_drv, | |
2882 | bool legacy_dai_naming) | |
2883 | { | |
2884 | struct device *dev = component->dev; | |
2885 | struct snd_soc_dai *dai; | |
2886 | ||
2887 | dev_dbg(dev, "ASoC: dynamically register DAI %s\n", dev_name(dev)); | |
2888 | ||
2889 | dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); | |
2890 | if (dai == NULL) | |
2891 | return NULL; | |
2892 | ||
2893 | /* | |
2894 | * Back in the old days when we still had component-less DAIs, | |
2895 | * instead of having a static name, component-less DAIs would | |
2896 | * inherit the name of the parent device so it is possible to | |
2897 | * register multiple instances of the DAI. We still need to keep | |
2898 | * the same naming style even though those DAIs are not | |
2899 | * component-less anymore. | |
2900 | */ | |
2901 | if (legacy_dai_naming && | |
2c7b696a | 2902 | (dai_drv->id == 0 || dai_drv->name == NULL)) { |
5e4fb372 ML |
2903 | dai->name = fmt_single_name(dev, &dai->id); |
2904 | } else { | |
2905 | dai->name = fmt_multiple_name(dev, dai_drv); | |
2906 | if (dai_drv->id) | |
2907 | dai->id = dai_drv->id; | |
2908 | else | |
2909 | dai->id = component->num_dai; | |
2910 | } | |
2911 | if (dai->name == NULL) { | |
2912 | kfree(dai); | |
2913 | return NULL; | |
2914 | } | |
2915 | ||
2916 | dai->component = component; | |
2917 | dai->dev = dev; | |
2918 | dai->driver = dai_drv; | |
2919 | if (!dai->driver->ops) | |
2920 | dai->driver->ops = &null_dai_ops; | |
2921 | ||
15a0c645 | 2922 | /* see for_each_component_dais */ |
58bf4179 | 2923 | list_add_tail(&dai->list, &component->dai_list); |
5e4fb372 ML |
2924 | component->num_dai++; |
2925 | ||
2926 | dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); | |
2927 | return dai; | |
2928 | } | |
2929 | ||
9115171a | 2930 | /** |
32c9ba54 | 2931 | * snd_soc_register_dais - Register a DAI with the ASoC core |
9115171a | 2932 | * |
6106d129 LPC |
2933 | * @component: The component the DAIs are registered for |
2934 | * @dai_drv: DAI driver to use for the DAIs | |
ac11a2b3 | 2935 | * @count: Number of DAIs |
9115171a | 2936 | */ |
6106d129 | 2937 | static int snd_soc_register_dais(struct snd_soc_component *component, |
2c7b696a MZ |
2938 | struct snd_soc_dai_driver *dai_drv, |
2939 | size_t count) | |
9115171a | 2940 | { |
6106d129 | 2941 | struct device *dev = component->dev; |
f0fba2ad | 2942 | struct snd_soc_dai *dai; |
32c9ba54 LPC |
2943 | unsigned int i; |
2944 | int ret; | |
f0fba2ad | 2945 | |
5b5e0928 | 2946 | dev_dbg(dev, "ASoC: dai register %s #%zu\n", dev_name(dev), count); |
9115171a MB |
2947 | |
2948 | for (i = 0; i < count; i++) { | |
f0fba2ad | 2949 | |
2c7b696a MZ |
2950 | dai = soc_add_dai(component, dai_drv + i, count == 1 && |
2951 | !component->driver->non_legacy_dai_naming); | |
c46e0079 AL |
2952 | if (dai == NULL) { |
2953 | ret = -ENOMEM; | |
2954 | goto err; | |
2955 | } | |
9115171a | 2956 | } |
f0fba2ad | 2957 | |
9115171a | 2958 | return 0; |
f0fba2ad | 2959 | |
9115171a | 2960 | err: |
32c9ba54 | 2961 | snd_soc_unregister_dais(component); |
f0fba2ad | 2962 | |
9115171a MB |
2963 | return ret; |
2964 | } | |
9115171a | 2965 | |
68003e6c ML |
2966 | /** |
2967 | * snd_soc_register_dai - Register a DAI dynamically & create its widgets | |
2968 | * | |
2969 | * @component: The component the DAIs are registered for | |
2970 | * @dai_drv: DAI driver to use for the DAI | |
2971 | * | |
2972 | * Topology can use this API to register DAIs when probing a component. | |
2973 | * These DAIs's widgets will be freed in the card cleanup and the DAIs | |
2974 | * will be freed in the component cleanup. | |
2975 | */ | |
2976 | int snd_soc_register_dai(struct snd_soc_component *component, | |
2977 | struct snd_soc_dai_driver *dai_drv) | |
2978 | { | |
2979 | struct snd_soc_dapm_context *dapm = | |
2980 | snd_soc_component_get_dapm(component); | |
2981 | struct snd_soc_dai *dai; | |
2982 | int ret; | |
054880fe | 2983 | |
68003e6c ML |
2984 | if (dai_drv->dobj.type != SND_SOC_DOBJ_PCM) { |
2985 | dev_err(component->dev, "Invalid dai type %d\n", | |
2986 | dai_drv->dobj.type); | |
2987 | return -EINVAL; | |
9115171a MB |
2988 | } |
2989 | ||
68003e6c ML |
2990 | lockdep_assert_held(&client_mutex); |
2991 | dai = soc_add_dai(component, dai_drv, false); | |
2992 | if (!dai) | |
2993 | return -ENOMEM; | |
9115171a | 2994 | |
2c7b696a MZ |
2995 | /* |
2996 | * Create the DAI widgets here. After adding DAIs, topology may | |
68003e6c ML |
2997 | * also add routes that need these widgets as source or sink. |
2998 | */ | |
2999 | ret = snd_soc_dapm_new_dai_widgets(dapm, dai); | |
3000 | if (ret != 0) { | |
3001 | dev_err(component->dev, | |
3002 | "Failed to create DAI widgets %d\n", ret); | |
3003 | } | |
9115171a MB |
3004 | |
3005 | return ret; | |
3006 | } | |
68003e6c | 3007 | EXPORT_SYMBOL_GPL(snd_soc_register_dai); |
9115171a | 3008 | |
14e8bdeb LPC |
3009 | static void snd_soc_component_seq_notifier(struct snd_soc_dapm_context *dapm, |
3010 | enum snd_soc_dapm_type type, int subseq) | |
d191bd8d | 3011 | { |
14e8bdeb | 3012 | struct snd_soc_component *component = dapm->component; |
d191bd8d | 3013 | |
14e8bdeb LPC |
3014 | component->driver->seq_notifier(component, type, subseq); |
3015 | } | |
d191bd8d | 3016 | |
14e8bdeb LPC |
3017 | static int snd_soc_component_stream_event(struct snd_soc_dapm_context *dapm, |
3018 | int event) | |
3019 | { | |
3020 | struct snd_soc_component *component = dapm->component; | |
d191bd8d | 3021 | |
14e8bdeb LPC |
3022 | return component->driver->stream_event(component, event); |
3023 | } | |
e2c330b9 | 3024 | |
7ba236ce KM |
3025 | static int snd_soc_component_set_bias_level(struct snd_soc_dapm_context *dapm, |
3026 | enum snd_soc_bias_level level) | |
3027 | { | |
3028 | struct snd_soc_component *component = dapm->component; | |
3029 | ||
3030 | return component->driver->set_bias_level(component, level); | |
3031 | } | |
3032 | ||
bb13109d LPC |
3033 | static int snd_soc_component_initialize(struct snd_soc_component *component, |
3034 | const struct snd_soc_component_driver *driver, struct device *dev) | |
d191bd8d | 3035 | { |
ce0fc93a LPC |
3036 | struct snd_soc_dapm_context *dapm; |
3037 | ||
bb13109d LPC |
3038 | component->name = fmt_single_name(dev, &component->id); |
3039 | if (!component->name) { | |
3040 | dev_err(dev, "ASoC: Failed to allocate name\n"); | |
d191bd8d KM |
3041 | return -ENOMEM; |
3042 | } | |
3043 | ||
bb13109d LPC |
3044 | component->dev = dev; |
3045 | component->driver = driver; | |
d191bd8d | 3046 | |
88c27465 | 3047 | dapm = snd_soc_component_get_dapm(component); |
ce0fc93a LPC |
3048 | dapm->dev = dev; |
3049 | dapm->component = component; | |
3050 | dapm->bias_level = SND_SOC_BIAS_OFF; | |
7ba236ce KM |
3051 | dapm->idle_bias_off = !driver->idle_bias_on; |
3052 | dapm->suspend_bias_off = driver->suspend_bias_off; | |
14e8bdeb LPC |
3053 | if (driver->seq_notifier) |
3054 | dapm->seq_notifier = snd_soc_component_seq_notifier; | |
3055 | if (driver->stream_event) | |
3056 | dapm->stream_event = snd_soc_component_stream_event; | |
7ba236ce KM |
3057 | if (driver->set_bias_level) |
3058 | dapm->set_bias_level = snd_soc_component_set_bias_level; | |
d191bd8d | 3059 | |
bb13109d LPC |
3060 | INIT_LIST_HEAD(&component->dai_list); |
3061 | mutex_init(&component->io_mutex); | |
d191bd8d | 3062 | |
bb13109d LPC |
3063 | return 0; |
3064 | } | |
d191bd8d | 3065 | |
20feb881 | 3066 | static void snd_soc_component_setup_regmap(struct snd_soc_component *component) |
886f5692 | 3067 | { |
20feb881 LPC |
3068 | int val_bytes = regmap_get_val_bytes(component->regmap); |
3069 | ||
3070 | /* Errors are legitimate for non-integer byte multiples */ | |
3071 | if (val_bytes > 0) | |
3072 | component->val_bytes = val_bytes; | |
3073 | } | |
3074 | ||
e874bf5f LPC |
3075 | #ifdef CONFIG_REGMAP |
3076 | ||
20feb881 | 3077 | /** |
2c7b696a MZ |
3078 | * snd_soc_component_init_regmap() - Initialize regmap instance for the |
3079 | * component | |
20feb881 LPC |
3080 | * @component: The component for which to initialize the regmap instance |
3081 | * @regmap: The regmap instance that should be used by the component | |
3082 | * | |
3083 | * This function allows deferred assignment of the regmap instance that is | |
3084 | * associated with the component. Only use this if the regmap instance is not | |
3085 | * yet ready when the component is registered. The function must also be called | |
3086 | * before the first IO attempt of the component. | |
3087 | */ | |
3088 | void snd_soc_component_init_regmap(struct snd_soc_component *component, | |
3089 | struct regmap *regmap) | |
3090 | { | |
3091 | component->regmap = regmap; | |
3092 | snd_soc_component_setup_regmap(component); | |
886f5692 | 3093 | } |
20feb881 LPC |
3094 | EXPORT_SYMBOL_GPL(snd_soc_component_init_regmap); |
3095 | ||
3096 | /** | |
2c7b696a MZ |
3097 | * snd_soc_component_exit_regmap() - De-initialize regmap instance for the |
3098 | * component | |
20feb881 LPC |
3099 | * @component: The component for which to de-initialize the regmap instance |
3100 | * | |
3101 | * Calls regmap_exit() on the regmap instance associated to the component and | |
3102 | * removes the regmap instance from the component. | |
3103 | * | |
3104 | * This function should only be used if snd_soc_component_init_regmap() was used | |
3105 | * to initialize the regmap instance. | |
3106 | */ | |
3107 | void snd_soc_component_exit_regmap(struct snd_soc_component *component) | |
3108 | { | |
3109 | regmap_exit(component->regmap); | |
3110 | component->regmap = NULL; | |
3111 | } | |
3112 | EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap); | |
886f5692 | 3113 | |
e874bf5f | 3114 | #endif |
886f5692 | 3115 | |
359c71ee | 3116 | static void snd_soc_component_add(struct snd_soc_component *component) |
bb13109d | 3117 | { |
359c71ee KM |
3118 | mutex_lock(&client_mutex); |
3119 | ||
999f7f5a | 3120 | if (!component->driver->write && !component->driver->read) { |
20feb881 | 3121 | if (!component->regmap) |
2c7b696a MZ |
3122 | component->regmap = dev_get_regmap(component->dev, |
3123 | NULL); | |
20feb881 LPC |
3124 | if (component->regmap) |
3125 | snd_soc_component_setup_regmap(component); | |
3126 | } | |
886f5692 | 3127 | |
368dee94 | 3128 | /* see for_each_component */ |
bb13109d | 3129 | list_add(&component->list, &component_list); |
8a978234 | 3130 | INIT_LIST_HEAD(&component->dobj_list); |
d191bd8d | 3131 | |
d191bd8d | 3132 | mutex_unlock(&client_mutex); |
bb13109d | 3133 | } |
d191bd8d | 3134 | |
bb13109d LPC |
3135 | static void snd_soc_component_cleanup(struct snd_soc_component *component) |
3136 | { | |
3137 | snd_soc_unregister_dais(component); | |
3138 | kfree(component->name); | |
3139 | } | |
d191bd8d | 3140 | |
bb13109d LPC |
3141 | static void snd_soc_component_del_unlocked(struct snd_soc_component *component) |
3142 | { | |
c12c1aad KM |
3143 | struct snd_soc_card *card = component->card; |
3144 | ||
3145 | if (card) | |
e894efef | 3146 | snd_soc_unbind_card(card, false); |
c12c1aad | 3147 | |
bb13109d LPC |
3148 | list_del(&component->list); |
3149 | } | |
d191bd8d | 3150 | |
273d778e KM |
3151 | #define ENDIANNESS_MAP(name) \ |
3152 | (SNDRV_PCM_FMTBIT_##name##LE | SNDRV_PCM_FMTBIT_##name##BE) | |
3153 | static u64 endianness_format_map[] = { | |
3154 | ENDIANNESS_MAP(S16_), | |
3155 | ENDIANNESS_MAP(U16_), | |
3156 | ENDIANNESS_MAP(S24_), | |
3157 | ENDIANNESS_MAP(U24_), | |
3158 | ENDIANNESS_MAP(S32_), | |
3159 | ENDIANNESS_MAP(U32_), | |
3160 | ENDIANNESS_MAP(S24_3), | |
3161 | ENDIANNESS_MAP(U24_3), | |
3162 | ENDIANNESS_MAP(S20_3), | |
3163 | ENDIANNESS_MAP(U20_3), | |
3164 | ENDIANNESS_MAP(S18_3), | |
3165 | ENDIANNESS_MAP(U18_3), | |
3166 | ENDIANNESS_MAP(FLOAT_), | |
3167 | ENDIANNESS_MAP(FLOAT64_), | |
3168 | ENDIANNESS_MAP(IEC958_SUBFRAME_), | |
3169 | }; | |
3170 | ||
3171 | /* | |
3172 | * Fix up the DAI formats for endianness: codecs don't actually see | |
3173 | * the endianness of the data but we're using the CPU format | |
3174 | * definitions which do need to include endianness so we ensure that | |
3175 | * codec DAIs always have both big and little endian variants set. | |
3176 | */ | |
3177 | static void convert_endianness_formats(struct snd_soc_pcm_stream *stream) | |
3178 | { | |
3179 | int i; | |
3180 | ||
3181 | for (i = 0; i < ARRAY_SIZE(endianness_format_map); i++) | |
3182 | if (stream->formats & endianness_format_map[i]) | |
3183 | stream->formats |= endianness_format_map[i]; | |
3184 | } | |
3185 | ||
e894efef SK |
3186 | static void snd_soc_try_rebind_card(void) |
3187 | { | |
3188 | struct snd_soc_card *card, *c; | |
3189 | ||
3190 | if (!list_empty(&unbind_card_list)) { | |
3191 | list_for_each_entry_safe(card, c, &unbind_card_list, list) { | |
3192 | if (!snd_soc_bind_card(card)) | |
3193 | list_del(&card->list); | |
3194 | } | |
3195 | } | |
3196 | } | |
3197 | ||
e0dac41b KM |
3198 | int snd_soc_add_component(struct device *dev, |
3199 | struct snd_soc_component *component, | |
3200 | const struct snd_soc_component_driver *component_driver, | |
3201 | struct snd_soc_dai_driver *dai_drv, | |
3202 | int num_dai) | |
d191bd8d | 3203 | { |
bb13109d | 3204 | int ret; |
273d778e | 3205 | int i; |
d191bd8d | 3206 | |
cf9e829e | 3207 | ret = snd_soc_component_initialize(component, component_driver, dev); |
bb13109d LPC |
3208 | if (ret) |
3209 | goto err_free; | |
3210 | ||
273d778e KM |
3211 | if (component_driver->endianness) { |
3212 | for (i = 0; i < num_dai; i++) { | |
3213 | convert_endianness_formats(&dai_drv[i].playback); | |
3214 | convert_endianness_formats(&dai_drv[i].capture); | |
3215 | } | |
3216 | } | |
3217 | ||
0e7b25c6 | 3218 | ret = snd_soc_register_dais(component, dai_drv, num_dai); |
bb13109d | 3219 | if (ret < 0) { |
f42cf8d6 | 3220 | dev_err(dev, "ASoC: Failed to register DAIs: %d\n", ret); |
bb13109d LPC |
3221 | goto err_cleanup; |
3222 | } | |
d191bd8d | 3223 | |
cf9e829e | 3224 | snd_soc_component_add(component); |
e894efef | 3225 | snd_soc_try_rebind_card(); |
4da53393 | 3226 | |
bb13109d | 3227 | return 0; |
4da53393 | 3228 | |
bb13109d | 3229 | err_cleanup: |
cf9e829e | 3230 | snd_soc_component_cleanup(component); |
bb13109d | 3231 | err_free: |
bb13109d | 3232 | return ret; |
4da53393 | 3233 | } |
e0dac41b KM |
3234 | EXPORT_SYMBOL_GPL(snd_soc_add_component); |
3235 | ||
3236 | int snd_soc_register_component(struct device *dev, | |
3237 | const struct snd_soc_component_driver *component_driver, | |
3238 | struct snd_soc_dai_driver *dai_drv, | |
3239 | int num_dai) | |
3240 | { | |
3241 | struct snd_soc_component *component; | |
3242 | ||
7ecbd6a9 | 3243 | component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL); |
08e61d03 | 3244 | if (!component) |
e0dac41b | 3245 | return -ENOMEM; |
e0dac41b KM |
3246 | |
3247 | return snd_soc_add_component(dev, component, component_driver, | |
3248 | dai_drv, num_dai); | |
3249 | } | |
bb13109d | 3250 | EXPORT_SYMBOL_GPL(snd_soc_register_component); |
4da53393 | 3251 | |
d191bd8d | 3252 | /** |
2eccea8c KM |
3253 | * snd_soc_unregister_component - Unregister all related component |
3254 | * from the ASoC core | |
d191bd8d | 3255 | * |
628536ea | 3256 | * @dev: The device to unregister |
d191bd8d | 3257 | */ |
2eccea8c | 3258 | static int __snd_soc_unregister_component(struct device *dev) |
d191bd8d | 3259 | { |
cf9e829e | 3260 | struct snd_soc_component *component; |
21a03528 | 3261 | int found = 0; |
d191bd8d | 3262 | |
34e81ab4 | 3263 | mutex_lock(&client_mutex); |
368dee94 | 3264 | for_each_component(component) { |
999f7f5a | 3265 | if (dev != component->dev) |
21a03528 KM |
3266 | continue; |
3267 | ||
2c7b696a MZ |
3268 | snd_soc_tplg_component_remove(component, |
3269 | SND_SOC_TPLG_INDEX_ALL); | |
21a03528 KM |
3270 | snd_soc_component_del_unlocked(component); |
3271 | found = 1; | |
3272 | break; | |
d191bd8d | 3273 | } |
34e81ab4 | 3274 | mutex_unlock(&client_mutex); |
d191bd8d | 3275 | |
2c7b696a | 3276 | if (found) |
21a03528 | 3277 | snd_soc_component_cleanup(component); |
2eccea8c KM |
3278 | |
3279 | return found; | |
3280 | } | |
3281 | ||
3282 | void snd_soc_unregister_component(struct device *dev) | |
3283 | { | |
2c7b696a MZ |
3284 | while (__snd_soc_unregister_component(dev)) |
3285 | ; | |
d191bd8d KM |
3286 | } |
3287 | EXPORT_SYMBOL_GPL(snd_soc_unregister_component); | |
d191bd8d | 3288 | |
7dd5d0d9 KM |
3289 | struct snd_soc_component *snd_soc_lookup_component(struct device *dev, |
3290 | const char *driver_name) | |
3291 | { | |
3292 | struct snd_soc_component *component; | |
3293 | struct snd_soc_component *ret; | |
3294 | ||
3295 | ret = NULL; | |
3296 | mutex_lock(&client_mutex); | |
368dee94 | 3297 | for_each_component(component) { |
7dd5d0d9 KM |
3298 | if (dev != component->dev) |
3299 | continue; | |
3300 | ||
3301 | if (driver_name && | |
3302 | (driver_name != component->driver->name) && | |
3303 | (strcmp(component->driver->name, driver_name) != 0)) | |
3304 | continue; | |
3305 | ||
3306 | ret = component; | |
3307 | break; | |
3308 | } | |
3309 | mutex_unlock(&client_mutex); | |
3310 | ||
3311 | return ret; | |
3312 | } | |
3313 | EXPORT_SYMBOL_GPL(snd_soc_lookup_component); | |
3314 | ||
bec4fa05 | 3315 | /* Retrieve a card's name from device tree */ |
b07609ce KM |
3316 | int snd_soc_of_parse_card_name(struct snd_soc_card *card, |
3317 | const char *propname) | |
bec4fa05 | 3318 | { |
b07609ce | 3319 | struct device_node *np; |
bec4fa05 SW |
3320 | int ret; |
3321 | ||
7e07e7c0 TB |
3322 | if (!card->dev) { |
3323 | pr_err("card->dev is not set before calling %s\n", __func__); | |
3324 | return -EINVAL; | |
3325 | } | |
3326 | ||
b07609ce | 3327 | np = card->dev->of_node; |
7e07e7c0 | 3328 | |
bec4fa05 SW |
3329 | ret = of_property_read_string_index(np, propname, 0, &card->name); |
3330 | /* | |
3331 | * EINVAL means the property does not exist. This is fine providing | |
3332 | * card->name was previously set, which is checked later in | |
3333 | * snd_soc_register_card. | |
3334 | */ | |
3335 | if (ret < 0 && ret != -EINVAL) { | |
3336 | dev_err(card->dev, | |
f110bfc7 | 3337 | "ASoC: Property '%s' could not be read: %d\n", |
bec4fa05 SW |
3338 | propname, ret); |
3339 | return ret; | |
3340 | } | |
3341 | ||
3342 | return 0; | |
3343 | } | |
b07609ce | 3344 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name); |
bec4fa05 | 3345 | |
9a6d4860 XL |
3346 | static const struct snd_soc_dapm_widget simple_widgets[] = { |
3347 | SND_SOC_DAPM_MIC("Microphone", NULL), | |
3348 | SND_SOC_DAPM_LINE("Line", NULL), | |
3349 | SND_SOC_DAPM_HP("Headphone", NULL), | |
3350 | SND_SOC_DAPM_SPK("Speaker", NULL), | |
3351 | }; | |
3352 | ||
21efde50 | 3353 | int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, |
9a6d4860 XL |
3354 | const char *propname) |
3355 | { | |
21efde50 | 3356 | struct device_node *np = card->dev->of_node; |
9a6d4860 XL |
3357 | struct snd_soc_dapm_widget *widgets; |
3358 | const char *template, *wname; | |
3359 | int i, j, num_widgets, ret; | |
3360 | ||
3361 | num_widgets = of_property_count_strings(np, propname); | |
3362 | if (num_widgets < 0) { | |
3363 | dev_err(card->dev, | |
3364 | "ASoC: Property '%s' does not exist\n", propname); | |
3365 | return -EINVAL; | |
3366 | } | |
3367 | if (num_widgets & 1) { | |
3368 | dev_err(card->dev, | |
3369 | "ASoC: Property '%s' length is not even\n", propname); | |
3370 | return -EINVAL; | |
3371 | } | |
3372 | ||
3373 | num_widgets /= 2; | |
3374 | if (!num_widgets) { | |
3375 | dev_err(card->dev, "ASoC: Property '%s's length is zero\n", | |
3376 | propname); | |
3377 | return -EINVAL; | |
3378 | } | |
3379 | ||
3380 | widgets = devm_kcalloc(card->dev, num_widgets, sizeof(*widgets), | |
3381 | GFP_KERNEL); | |
3382 | if (!widgets) { | |
3383 | dev_err(card->dev, | |
3384 | "ASoC: Could not allocate memory for widgets\n"); | |
3385 | return -ENOMEM; | |
3386 | } | |
3387 | ||
3388 | for (i = 0; i < num_widgets; i++) { | |
3389 | ret = of_property_read_string_index(np, propname, | |
3390 | 2 * i, &template); | |
3391 | if (ret) { | |
3392 | dev_err(card->dev, | |
3393 | "ASoC: Property '%s' index %d read error:%d\n", | |
3394 | propname, 2 * i, ret); | |
3395 | return -EINVAL; | |
3396 | } | |
3397 | ||
3398 | for (j = 0; j < ARRAY_SIZE(simple_widgets); j++) { | |
3399 | if (!strncmp(template, simple_widgets[j].name, | |
3400 | strlen(simple_widgets[j].name))) { | |
3401 | widgets[i] = simple_widgets[j]; | |
3402 | break; | |
3403 | } | |
3404 | } | |
3405 | ||
3406 | if (j >= ARRAY_SIZE(simple_widgets)) { | |
3407 | dev_err(card->dev, | |
3408 | "ASoC: DAPM widget '%s' is not supported\n", | |
3409 | template); | |
3410 | return -EINVAL; | |
3411 | } | |
3412 | ||
3413 | ret = of_property_read_string_index(np, propname, | |
3414 | (2 * i) + 1, | |
3415 | &wname); | |
3416 | if (ret) { | |
3417 | dev_err(card->dev, | |
3418 | "ASoC: Property '%s' index %d read error:%d\n", | |
3419 | propname, (2 * i) + 1, ret); | |
3420 | return -EINVAL; | |
3421 | } | |
3422 | ||
3423 | widgets[i].name = wname; | |
3424 | } | |
3425 | ||
f23e860e NC |
3426 | card->of_dapm_widgets = widgets; |
3427 | card->num_of_dapm_widgets = num_widgets; | |
9a6d4860 XL |
3428 | |
3429 | return 0; | |
3430 | } | |
21efde50 | 3431 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets); |
9a6d4860 | 3432 | |
cbdfab3b JB |
3433 | int snd_soc_of_get_slot_mask(struct device_node *np, |
3434 | const char *prop_name, | |
3435 | unsigned int *mask) | |
6131084a JS |
3436 | { |
3437 | u32 val; | |
6c84e591 | 3438 | const __be32 *of_slot_mask = of_get_property(np, prop_name, &val); |
6131084a JS |
3439 | int i; |
3440 | ||
3441 | if (!of_slot_mask) | |
3442 | return 0; | |
3443 | val /= sizeof(u32); | |
3444 | for (i = 0; i < val; i++) | |
3445 | if (be32_to_cpup(&of_slot_mask[i])) | |
3446 | *mask |= (1 << i); | |
3447 | ||
3448 | return val; | |
3449 | } | |
cbdfab3b | 3450 | EXPORT_SYMBOL_GPL(snd_soc_of_get_slot_mask); |
6131084a | 3451 | |
89c67857 | 3452 | int snd_soc_of_parse_tdm_slot(struct device_node *np, |
6131084a JS |
3453 | unsigned int *tx_mask, |
3454 | unsigned int *rx_mask, | |
89c67857 XL |
3455 | unsigned int *slots, |
3456 | unsigned int *slot_width) | |
3457 | { | |
3458 | u32 val; | |
3459 | int ret; | |
3460 | ||
6131084a JS |
3461 | if (tx_mask) |
3462 | snd_soc_of_get_slot_mask(np, "dai-tdm-slot-tx-mask", tx_mask); | |
3463 | if (rx_mask) | |
3464 | snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", rx_mask); | |
3465 | ||
89c67857 XL |
3466 | if (of_property_read_bool(np, "dai-tdm-slot-num")) { |
3467 | ret = of_property_read_u32(np, "dai-tdm-slot-num", &val); | |
3468 | if (ret) | |
3469 | return ret; | |
3470 | ||
3471 | if (slots) | |
3472 | *slots = val; | |
3473 | } | |
3474 | ||
3475 | if (of_property_read_bool(np, "dai-tdm-slot-width")) { | |
3476 | ret = of_property_read_u32(np, "dai-tdm-slot-width", &val); | |
3477 | if (ret) | |
3478 | return ret; | |
3479 | ||
3480 | if (slot_width) | |
3481 | *slot_width = val; | |
3482 | } | |
3483 | ||
3484 | return 0; | |
3485 | } | |
3486 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot); | |
3487 | ||
440a3006 | 3488 | void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, |
5e3cdaa2 KM |
3489 | struct snd_soc_codec_conf *codec_conf, |
3490 | struct device_node *of_node, | |
3491 | const char *propname) | |
3492 | { | |
440a3006 | 3493 | struct device_node *np = card->dev->of_node; |
5e3cdaa2 KM |
3494 | const char *str; |
3495 | int ret; | |
3496 | ||
3497 | ret = of_property_read_string(np, propname, &str); | |
3498 | if (ret < 0) { | |
3499 | /* no prefix is not error */ | |
3500 | return; | |
3501 | } | |
3502 | ||
3503 | codec_conf->of_node = of_node; | |
3504 | codec_conf->name_prefix = str; | |
3505 | } | |
440a3006 | 3506 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix); |
5e3cdaa2 | 3507 | |
2bc644af | 3508 | int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, |
a4a54dd5 SW |
3509 | const char *propname) |
3510 | { | |
2bc644af | 3511 | struct device_node *np = card->dev->of_node; |
e3b1e6a1 | 3512 | int num_routes; |
a4a54dd5 SW |
3513 | struct snd_soc_dapm_route *routes; |
3514 | int i, ret; | |
3515 | ||
3516 | num_routes = of_property_count_strings(np, propname); | |
c34ce320 | 3517 | if (num_routes < 0 || num_routes & 1) { |
10e8aa9a MM |
3518 | dev_err(card->dev, |
3519 | "ASoC: Property '%s' does not exist or its length is not even\n", | |
3520 | propname); | |
a4a54dd5 SW |
3521 | return -EINVAL; |
3522 | } | |
3523 | num_routes /= 2; | |
3524 | if (!num_routes) { | |
f110bfc7 | 3525 | dev_err(card->dev, "ASoC: Property '%s's length is zero\n", |
a4a54dd5 SW |
3526 | propname); |
3527 | return -EINVAL; | |
3528 | } | |
3529 | ||
a86854d0 | 3530 | routes = devm_kcalloc(card->dev, num_routes, sizeof(*routes), |
a4a54dd5 SW |
3531 | GFP_KERNEL); |
3532 | if (!routes) { | |
3533 | dev_err(card->dev, | |
f110bfc7 | 3534 | "ASoC: Could not allocate DAPM route table\n"); |
a4a54dd5 SW |
3535 | return -EINVAL; |
3536 | } | |
3537 | ||
3538 | for (i = 0; i < num_routes; i++) { | |
3539 | ret = of_property_read_string_index(np, propname, | |
e3b1e6a1 | 3540 | 2 * i, &routes[i].sink); |
a4a54dd5 | 3541 | if (ret) { |
c871bd0b MB |
3542 | dev_err(card->dev, |
3543 | "ASoC: Property '%s' index %d could not be read: %d\n", | |
3544 | propname, 2 * i, ret); | |
a4a54dd5 SW |
3545 | return -EINVAL; |
3546 | } | |
3547 | ret = of_property_read_string_index(np, propname, | |
e3b1e6a1 | 3548 | (2 * i) + 1, &routes[i].source); |
a4a54dd5 SW |
3549 | if (ret) { |
3550 | dev_err(card->dev, | |
c871bd0b MB |
3551 | "ASoC: Property '%s' index %d could not be read: %d\n", |
3552 | propname, (2 * i) + 1, ret); | |
a4a54dd5 SW |
3553 | return -EINVAL; |
3554 | } | |
3555 | } | |
3556 | ||
f23e860e NC |
3557 | card->num_of_dapm_routes = num_routes; |
3558 | card->of_dapm_routes = routes; | |
a4a54dd5 SW |
3559 | |
3560 | return 0; | |
3561 | } | |
2bc644af | 3562 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing); |
a4a54dd5 | 3563 | |
a7930ed4 | 3564 | unsigned int snd_soc_of_parse_daifmt(struct device_node *np, |
389cb834 JS |
3565 | const char *prefix, |
3566 | struct device_node **bitclkmaster, | |
3567 | struct device_node **framemaster) | |
a7930ed4 KM |
3568 | { |
3569 | int ret, i; | |
3570 | char prop[128]; | |
3571 | unsigned int format = 0; | |
3572 | int bit, frame; | |
3573 | const char *str; | |
3574 | struct { | |
3575 | char *name; | |
3576 | unsigned int val; | |
3577 | } of_fmt_table[] = { | |
3578 | { "i2s", SND_SOC_DAIFMT_I2S }, | |
3579 | { "right_j", SND_SOC_DAIFMT_RIGHT_J }, | |
3580 | { "left_j", SND_SOC_DAIFMT_LEFT_J }, | |
3581 | { "dsp_a", SND_SOC_DAIFMT_DSP_A }, | |
3582 | { "dsp_b", SND_SOC_DAIFMT_DSP_B }, | |
3583 | { "ac97", SND_SOC_DAIFMT_AC97 }, | |
3584 | { "pdm", SND_SOC_DAIFMT_PDM}, | |
3585 | { "msb", SND_SOC_DAIFMT_MSB }, | |
3586 | { "lsb", SND_SOC_DAIFMT_LSB }, | |
a7930ed4 KM |
3587 | }; |
3588 | ||
3589 | if (!prefix) | |
3590 | prefix = ""; | |
3591 | ||
3592 | /* | |
5711c979 KM |
3593 | * check "dai-format = xxx" |
3594 | * or "[prefix]format = xxx" | |
a7930ed4 KM |
3595 | * SND_SOC_DAIFMT_FORMAT_MASK area |
3596 | */ | |
5711c979 KM |
3597 | ret = of_property_read_string(np, "dai-format", &str); |
3598 | if (ret < 0) { | |
3599 | snprintf(prop, sizeof(prop), "%sformat", prefix); | |
3600 | ret = of_property_read_string(np, prop, &str); | |
3601 | } | |
a7930ed4 KM |
3602 | if (ret == 0) { |
3603 | for (i = 0; i < ARRAY_SIZE(of_fmt_table); i++) { | |
3604 | if (strcmp(str, of_fmt_table[i].name) == 0) { | |
3605 | format |= of_fmt_table[i].val; | |
3606 | break; | |
3607 | } | |
3608 | } | |
3609 | } | |
3610 | ||
3611 | /* | |
8c2d6a9f | 3612 | * check "[prefix]continuous-clock" |
a7930ed4 KM |
3613 | * SND_SOC_DAIFMT_CLOCK_MASK area |
3614 | */ | |
8c2d6a9f | 3615 | snprintf(prop, sizeof(prop), "%scontinuous-clock", prefix); |
51930295 | 3616 | if (of_property_read_bool(np, prop)) |
8c2d6a9f KM |
3617 | format |= SND_SOC_DAIFMT_CONT; |
3618 | else | |
3619 | format |= SND_SOC_DAIFMT_GATED; | |
a7930ed4 KM |
3620 | |
3621 | /* | |
3622 | * check "[prefix]bitclock-inversion" | |
3623 | * check "[prefix]frame-inversion" | |
3624 | * SND_SOC_DAIFMT_INV_MASK area | |
3625 | */ | |
3626 | snprintf(prop, sizeof(prop), "%sbitclock-inversion", prefix); | |
3627 | bit = !!of_get_property(np, prop, NULL); | |
3628 | ||
3629 | snprintf(prop, sizeof(prop), "%sframe-inversion", prefix); | |
3630 | frame = !!of_get_property(np, prop, NULL); | |
3631 | ||
3632 | switch ((bit << 4) + frame) { | |
3633 | case 0x11: | |
3634 | format |= SND_SOC_DAIFMT_IB_IF; | |
3635 | break; | |
3636 | case 0x10: | |
3637 | format |= SND_SOC_DAIFMT_IB_NF; | |
3638 | break; | |
3639 | case 0x01: | |
3640 | format |= SND_SOC_DAIFMT_NB_IF; | |
3641 | break; | |
3642 | default: | |
3643 | /* SND_SOC_DAIFMT_NB_NF is default */ | |
3644 | break; | |
3645 | } | |
3646 | ||
3647 | /* | |
3648 | * check "[prefix]bitclock-master" | |
3649 | * check "[prefix]frame-master" | |
3650 | * SND_SOC_DAIFMT_MASTER_MASK area | |
3651 | */ | |
3652 | snprintf(prop, sizeof(prop), "%sbitclock-master", prefix); | |
3653 | bit = !!of_get_property(np, prop, NULL); | |
389cb834 JS |
3654 | if (bit && bitclkmaster) |
3655 | *bitclkmaster = of_parse_phandle(np, prop, 0); | |
a7930ed4 KM |
3656 | |
3657 | snprintf(prop, sizeof(prop), "%sframe-master", prefix); | |
3658 | frame = !!of_get_property(np, prop, NULL); | |
389cb834 JS |
3659 | if (frame && framemaster) |
3660 | *framemaster = of_parse_phandle(np, prop, 0); | |
a7930ed4 KM |
3661 | |
3662 | switch ((bit << 4) + frame) { | |
3663 | case 0x11: | |
3664 | format |= SND_SOC_DAIFMT_CBM_CFM; | |
3665 | break; | |
3666 | case 0x10: | |
3667 | format |= SND_SOC_DAIFMT_CBM_CFS; | |
3668 | break; | |
3669 | case 0x01: | |
3670 | format |= SND_SOC_DAIFMT_CBS_CFM; | |
3671 | break; | |
3672 | default: | |
3673 | format |= SND_SOC_DAIFMT_CBS_CFS; | |
3674 | break; | |
3675 | } | |
3676 | ||
3677 | return format; | |
3678 | } | |
3679 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); | |
3680 | ||
a180e8b9 KM |
3681 | int snd_soc_get_dai_id(struct device_node *ep) |
3682 | { | |
3683 | struct snd_soc_component *pos; | |
3684 | struct device_node *node; | |
3685 | int ret; | |
3686 | ||
3687 | node = of_graph_get_port_parent(ep); | |
3688 | ||
3689 | /* | |
3690 | * For example HDMI case, HDMI has video/sound port, | |
3691 | * but ALSA SoC needs sound port number only. | |
3692 | * Thus counting HDMI DT port/endpoint doesn't work. | |
3693 | * Then, it should have .of_xlate_dai_id | |
3694 | */ | |
3695 | ret = -ENOTSUPP; | |
3696 | mutex_lock(&client_mutex); | |
368dee94 | 3697 | for_each_component(pos) { |
a180e8b9 KM |
3698 | struct device_node *component_of_node = pos->dev->of_node; |
3699 | ||
3700 | if (!component_of_node && pos->dev->parent) | |
3701 | component_of_node = pos->dev->parent->of_node; | |
3702 | ||
3703 | if (component_of_node != node) | |
3704 | continue; | |
3705 | ||
3706 | if (pos->driver->of_xlate_dai_id) | |
3707 | ret = pos->driver->of_xlate_dai_id(pos, ep); | |
3708 | ||
3709 | break; | |
3710 | } | |
3711 | mutex_unlock(&client_mutex); | |
3712 | ||
c0a480d1 TL |
3713 | of_node_put(node); |
3714 | ||
a180e8b9 KM |
3715 | return ret; |
3716 | } | |
3717 | EXPORT_SYMBOL_GPL(snd_soc_get_dai_id); | |
3718 | ||
1ad8ec53 | 3719 | int snd_soc_get_dai_name(struct of_phandle_args *args, |
93b0f3ee | 3720 | const char **dai_name) |
cb470087 KM |
3721 | { |
3722 | struct snd_soc_component *pos; | |
3e0aa8d8 | 3723 | struct device_node *component_of_node; |
93b0f3ee | 3724 | int ret = -EPROBE_DEFER; |
cb470087 KM |
3725 | |
3726 | mutex_lock(&client_mutex); | |
368dee94 | 3727 | for_each_component(pos) { |
3e0aa8d8 JS |
3728 | component_of_node = pos->dev->of_node; |
3729 | if (!component_of_node && pos->dev->parent) | |
3730 | component_of_node = pos->dev->parent->of_node; | |
3731 | ||
3732 | if (component_of_node != args->np) | |
cb470087 KM |
3733 | continue; |
3734 | ||
6833c452 | 3735 | if (pos->driver->of_xlate_dai_name) { |
93b0f3ee JFM |
3736 | ret = pos->driver->of_xlate_dai_name(pos, |
3737 | args, | |
3738 | dai_name); | |
6833c452 | 3739 | } else { |
58bf4179 | 3740 | struct snd_soc_dai *dai; |
6833c452 KM |
3741 | int id = -1; |
3742 | ||
93b0f3ee | 3743 | switch (args->args_count) { |
6833c452 KM |
3744 | case 0: |
3745 | id = 0; /* same as dai_drv[0] */ | |
3746 | break; | |
3747 | case 1: | |
93b0f3ee | 3748 | id = args->args[0]; |
6833c452 KM |
3749 | break; |
3750 | default: | |
3751 | /* not supported */ | |
3752 | break; | |
3753 | } | |
3754 | ||
3755 | if (id < 0 || id >= pos->num_dai) { | |
3756 | ret = -EINVAL; | |
3dcba280 | 3757 | continue; |
6833c452 | 3758 | } |
e41975ed XL |
3759 | |
3760 | ret = 0; | |
3761 | ||
58bf4179 | 3762 | /* find target DAI */ |
15a0c645 | 3763 | for_each_component_dais(pos, dai) { |
58bf4179 KM |
3764 | if (id == 0) |
3765 | break; | |
3766 | id--; | |
3767 | } | |
3768 | ||
3769 | *dai_name = dai->driver->name; | |
e41975ed XL |
3770 | if (!*dai_name) |
3771 | *dai_name = pos->name; | |
cb470087 KM |
3772 | } |
3773 | ||
cb470087 KM |
3774 | break; |
3775 | } | |
3776 | mutex_unlock(&client_mutex); | |
93b0f3ee JFM |
3777 | return ret; |
3778 | } | |
1ad8ec53 | 3779 | EXPORT_SYMBOL_GPL(snd_soc_get_dai_name); |
93b0f3ee JFM |
3780 | |
3781 | int snd_soc_of_get_dai_name(struct device_node *of_node, | |
3782 | const char **dai_name) | |
3783 | { | |
3784 | struct of_phandle_args args; | |
3785 | int ret; | |
3786 | ||
3787 | ret = of_parse_phandle_with_args(of_node, "sound-dai", | |
3788 | "#sound-dai-cells", 0, &args); | |
3789 | if (ret) | |
3790 | return ret; | |
3791 | ||
3792 | ret = snd_soc_get_dai_name(&args, dai_name); | |
cb470087 KM |
3793 | |
3794 | of_node_put(args.np); | |
3795 | ||
3796 | return ret; | |
3797 | } | |
3798 | EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name); | |
3799 | ||
94685763 SN |
3800 | /* |
3801 | * snd_soc_of_put_dai_link_codecs - Dereference device nodes in the codecs array | |
3802 | * @dai_link: DAI link | |
3803 | * | |
3804 | * Dereference device nodes acquired by snd_soc_of_get_dai_link_codecs(). | |
3805 | */ | |
3806 | void snd_soc_of_put_dai_link_codecs(struct snd_soc_dai_link *dai_link) | |
3807 | { | |
3db769f1 | 3808 | struct snd_soc_dai_link_component *component; |
94685763 SN |
3809 | int index; |
3810 | ||
3db769f1 | 3811 | for_each_link_codecs(dai_link, index, component) { |
94685763 SN |
3812 | if (!component->of_node) |
3813 | break; | |
3814 | of_node_put(component->of_node); | |
3815 | component->of_node = NULL; | |
3816 | } | |
3817 | } | |
3818 | EXPORT_SYMBOL_GPL(snd_soc_of_put_dai_link_codecs); | |
3819 | ||
93b0f3ee JFM |
3820 | /* |
3821 | * snd_soc_of_get_dai_link_codecs - Parse a list of CODECs in the devicetree | |
3822 | * @dev: Card device | |
3823 | * @of_node: Device node | |
3824 | * @dai_link: DAI link | |
3825 | * | |
3826 | * Builds an array of CODEC DAI components from the DAI link property | |
3827 | * 'sound-dai'. | |
3828 | * The array is set in the DAI link and the number of DAIs is set accordingly. | |
94685763 SN |
3829 | * The device nodes in the array (of_node) must be dereferenced by calling |
3830 | * snd_soc_of_put_dai_link_codecs() on @dai_link. | |
93b0f3ee JFM |
3831 | * |
3832 | * Returns 0 for success | |
3833 | */ | |
3834 | int snd_soc_of_get_dai_link_codecs(struct device *dev, | |
3835 | struct device_node *of_node, | |
3836 | struct snd_soc_dai_link *dai_link) | |
3837 | { | |
3838 | struct of_phandle_args args; | |
3839 | struct snd_soc_dai_link_component *component; | |
3840 | char *name; | |
3841 | int index, num_codecs, ret; | |
3842 | ||
3843 | /* Count the number of CODECs */ | |
3844 | name = "sound-dai"; | |
3845 | num_codecs = of_count_phandle_with_args(of_node, name, | |
3846 | "#sound-dai-cells"); | |
3847 | if (num_codecs <= 0) { | |
3848 | if (num_codecs == -ENOENT) | |
3849 | dev_err(dev, "No 'sound-dai' property\n"); | |
3850 | else | |
3851 | dev_err(dev, "Bad phandle in 'sound-dai'\n"); | |
3852 | return num_codecs; | |
3853 | } | |
a86854d0 KC |
3854 | component = devm_kcalloc(dev, |
3855 | num_codecs, sizeof(*component), | |
93b0f3ee JFM |
3856 | GFP_KERNEL); |
3857 | if (!component) | |
3858 | return -ENOMEM; | |
3859 | dai_link->codecs = component; | |
3860 | dai_link->num_codecs = num_codecs; | |
3861 | ||
3862 | /* Parse the list */ | |
3db769f1 | 3863 | for_each_link_codecs(dai_link, index, component) { |
93b0f3ee JFM |
3864 | ret = of_parse_phandle_with_args(of_node, name, |
3865 | "#sound-dai-cells", | |
2c7b696a | 3866 | index, &args); |
93b0f3ee JFM |
3867 | if (ret) |
3868 | goto err; | |
3869 | component->of_node = args.np; | |
3870 | ret = snd_soc_get_dai_name(&args, &component->dai_name); | |
3871 | if (ret < 0) | |
3872 | goto err; | |
3873 | } | |
3874 | return 0; | |
3875 | err: | |
94685763 | 3876 | snd_soc_of_put_dai_link_codecs(dai_link); |
93b0f3ee JFM |
3877 | dai_link->codecs = NULL; |
3878 | dai_link->num_codecs = 0; | |
3879 | return ret; | |
3880 | } | |
3881 | EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_link_codecs); | |
3882 | ||
c9b3a40f | 3883 | static int __init snd_soc_init(void) |
db2a4165 | 3884 | { |
6553bf06 | 3885 | snd_soc_debugfs_init(); |
fb257897 MB |
3886 | snd_soc_util_init(); |
3887 | ||
db2a4165 FM |
3888 | return platform_driver_register(&soc_driver); |
3889 | } | |
4abe8e16 | 3890 | module_init(snd_soc_init); |
db2a4165 | 3891 | |
7d8c16a6 | 3892 | static void __exit snd_soc_exit(void) |
db2a4165 | 3893 | { |
fb257897 | 3894 | snd_soc_util_exit(); |
6553bf06 | 3895 | snd_soc_debugfs_exit(); |
fb257897 | 3896 | |
3ff3f64b | 3897 | platform_driver_unregister(&soc_driver); |
db2a4165 | 3898 | } |
db2a4165 FM |
3899 | module_exit(snd_soc_exit); |
3900 | ||
3901 | /* Module information */ | |
d331124d | 3902 | MODULE_AUTHOR("Liam Girdwood, [email protected]"); |
db2a4165 FM |
3903 | MODULE_DESCRIPTION("ALSA SoC Core"); |
3904 | MODULE_LICENSE("GPL"); | |
8b45a209 | 3905 | MODULE_ALIAS("platform:soc-audio"); |