xref: /openbmc/linux/sound/soc/soc-core.c (revision 8a6a6a38f86885982891197840e7b8eccad5ef50)
1873486edSKuninori Morimoto // SPDX-License-Identifier: GPL-2.0+
2873486edSKuninori Morimoto //
3873486edSKuninori Morimoto // soc-core.c  --  ALSA SoC Audio Layer
4873486edSKuninori Morimoto //
5873486edSKuninori Morimoto // Copyright 2005 Wolfson Microelectronics PLC.
6873486edSKuninori Morimoto // Copyright 2005 Openedhand Ltd.
7873486edSKuninori Morimoto // Copyright (C) 2010 Slimlogic Ltd.
8873486edSKuninori Morimoto // Copyright (C) 2010 Texas Instruments Inc.
9873486edSKuninori Morimoto //
10873486edSKuninori Morimoto // Author: Liam Girdwood <lrg@slimlogic.co.uk>
11873486edSKuninori Morimoto //         with code, comments and ideas from :-
12873486edSKuninori Morimoto //         Richard Purdie <richard@openedhand.com>
13873486edSKuninori Morimoto //
14873486edSKuninori Morimoto //  TODO:
15873486edSKuninori Morimoto //   o Add hw rules to enforce rates, etc.
16873486edSKuninori Morimoto //   o More testing with other codecs/machines.
17873486edSKuninori Morimoto //   o Add more codecs and platforms to ensure good API coverage.
18873486edSKuninori Morimoto //   o Support TDM on PCM and I2S
19db2a4165SFrank Mandarino 
20db2a4165SFrank Mandarino #include <linux/module.h>
21db2a4165SFrank Mandarino #include <linux/moduleparam.h>
22db2a4165SFrank Mandarino #include <linux/init.h>
23db2a4165SFrank Mandarino #include <linux/delay.h>
24db2a4165SFrank Mandarino #include <linux/pm.h>
25db2a4165SFrank Mandarino #include <linux/bitops.h>
2612ef193dSTroy Kisky #include <linux/debugfs.h>
27db2a4165SFrank Mandarino #include <linux/platform_device.h>
28741a509fSMarkus Pargmann #include <linux/pinctrl/consumer.h>
29f0e8ed85SMark Brown #include <linux/ctype.h>
305a0e3ad6STejun Heo #include <linux/slab.h>
31bec4fa05SStephen Warren #include <linux/of.h>
32a180e8b9SKuninori Morimoto #include <linux/of_graph.h>
33345233d7SLiam Girdwood #include <linux/dmi.h>
34db2a4165SFrank Mandarino #include <sound/core.h>
353028eb8cSMark Brown #include <sound/jack.h>
36db2a4165SFrank Mandarino #include <sound/pcm.h>
37db2a4165SFrank Mandarino #include <sound/pcm_params.h>
38db2a4165SFrank Mandarino #include <sound/soc.h>
3901d7584cSLiam Girdwood #include <sound/soc-dpcm.h>
408a978234SLiam Girdwood #include <sound/soc-topology.h>
41db2a4165SFrank Mandarino #include <sound/initval.h>
42db2a4165SFrank Mandarino 
43a8b1d34fSMark Brown #define CREATE_TRACE_POINTS
44a8b1d34fSMark Brown #include <trace/events/asoc.h>
45a8b1d34fSMark Brown 
46f0fba2adSLiam Girdwood #define NAME_SIZE	32
47f0fba2adSLiam Girdwood 
48384c89e2SMark Brown #ifdef CONFIG_DEBUG_FS
498a9dab1aSMark Brown struct dentry *snd_soc_debugfs_root;
508a9dab1aSMark Brown EXPORT_SYMBOL_GPL(snd_soc_debugfs_root);
51384c89e2SMark Brown #endif
52384c89e2SMark Brown 
53c5af3a2eSMark Brown static DEFINE_MUTEX(client_mutex);
54030e79f6SKuninori Morimoto static LIST_HEAD(component_list);
55e894efefSSrinivas Kandagatla static LIST_HEAD(unbind_card_list);
56c5af3a2eSMark Brown 
57368dee94SKuninori Morimoto #define for_each_component(component)			\
58368dee94SKuninori Morimoto 	list_for_each_entry(component, &component_list, list)
59368dee94SKuninori Morimoto 
60db2a4165SFrank Mandarino /*
61587c9844SKuninori Morimoto  * This is used if driver don't need to have CPU/Codec/Platform
62587c9844SKuninori Morimoto  * dai_link. see soc.h
63587c9844SKuninori Morimoto  */
64587c9844SKuninori Morimoto struct snd_soc_dai_link_component null_dailink_component[0];
65587c9844SKuninori Morimoto EXPORT_SYMBOL_GPL(null_dailink_component);
66587c9844SKuninori Morimoto 
67587c9844SKuninori Morimoto /*
68db2a4165SFrank Mandarino  * This is a timeout to do a DAPM powerdown after a stream is closed().
69db2a4165SFrank Mandarino  * It can be used to eliminate pops between different playback streams, e.g.
70db2a4165SFrank Mandarino  * between two audio tracks.
71db2a4165SFrank Mandarino  */
72db2a4165SFrank Mandarino static int pmdown_time = 5000;
73db2a4165SFrank Mandarino module_param(pmdown_time, int, 0);
74db2a4165SFrank Mandarino MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)");
75db2a4165SFrank Mandarino 
76dbe21408SMark Brown static ssize_t pmdown_time_show(struct device *dev,
77dbe21408SMark Brown 				struct device_attribute *attr, char *buf)
78dbe21408SMark Brown {
7936ae1a96SMark Brown 	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
80dbe21408SMark Brown 
81f0fba2adSLiam Girdwood 	return sprintf(buf, "%ld\n", rtd->pmdown_time);
82dbe21408SMark Brown }
83dbe21408SMark Brown 
84dbe21408SMark Brown static ssize_t pmdown_time_set(struct device *dev,
85dbe21408SMark Brown 			       struct device_attribute *attr,
86dbe21408SMark Brown 			       const char *buf, size_t count)
87dbe21408SMark Brown {
8836ae1a96SMark Brown 	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
89c593b520SMark Brown 	int ret;
90dbe21408SMark Brown 
91b785a492SJingoo Han 	ret = kstrtol(buf, 10, &rtd->pmdown_time);
92c593b520SMark Brown 	if (ret)
93c593b520SMark Brown 		return ret;
94dbe21408SMark Brown 
95dbe21408SMark Brown 	return count;
96dbe21408SMark Brown }
97dbe21408SMark Brown 
98dbe21408SMark Brown static DEVICE_ATTR(pmdown_time, 0644, pmdown_time_show, pmdown_time_set);
99dbe21408SMark Brown 
100d29697dcSTakashi Iwai static struct attribute *soc_dev_attrs[] = {
101d29697dcSTakashi Iwai 	&dev_attr_pmdown_time.attr,
102d29697dcSTakashi Iwai 	NULL
103d29697dcSTakashi Iwai };
104d29697dcSTakashi Iwai 
105d29697dcSTakashi Iwai static umode_t soc_dev_attr_is_visible(struct kobject *kobj,
106d29697dcSTakashi Iwai 				       struct attribute *attr, int idx)
107d29697dcSTakashi Iwai {
108d29697dcSTakashi Iwai 	struct device *dev = kobj_to_dev(kobj);
109d29697dcSTakashi Iwai 	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
110d29697dcSTakashi Iwai 
111d918a376SKuninori Morimoto 	if (!rtd)
112d918a376SKuninori Morimoto 		return 0;
113d918a376SKuninori Morimoto 
114d29697dcSTakashi Iwai 	if (attr == &dev_attr_pmdown_time.attr)
115d29697dcSTakashi Iwai 		return attr->mode; /* always visible */
1163b6eed8dSKuninori Morimoto 	return rtd->num_codecs ? attr->mode : 0; /* enabled only with codec */
117d29697dcSTakashi Iwai }
118d29697dcSTakashi Iwai 
119d29697dcSTakashi Iwai static const struct attribute_group soc_dapm_dev_group = {
120d29697dcSTakashi Iwai 	.attrs = soc_dapm_dev_attrs,
121d29697dcSTakashi Iwai 	.is_visible = soc_dev_attr_is_visible,
122d29697dcSTakashi Iwai };
123d29697dcSTakashi Iwai 
124f7e73b26SMark Brown static const struct attribute_group soc_dev_group = {
125d29697dcSTakashi Iwai 	.attrs = soc_dev_attrs,
126d29697dcSTakashi Iwai 	.is_visible = soc_dev_attr_is_visible,
127d29697dcSTakashi Iwai };
128d29697dcSTakashi Iwai 
129d29697dcSTakashi Iwai static const struct attribute_group *soc_dev_attr_groups[] = {
130d29697dcSTakashi Iwai 	&soc_dapm_dev_group,
131f7e73b26SMark Brown 	&soc_dev_group,
132d29697dcSTakashi Iwai 	NULL
133d29697dcSTakashi Iwai };
134d29697dcSTakashi Iwai 
1352624d5faSMark Brown #ifdef CONFIG_DEBUG_FS
13681c7cfd1SLars-Peter Clausen static void soc_init_component_debugfs(struct snd_soc_component *component)
137e73f3de5SRussell King {
1386553bf06SLars-Peter Clausen 	if (!component->card->debugfs_card_root)
1396553bf06SLars-Peter Clausen 		return;
1406553bf06SLars-Peter Clausen 
14181c7cfd1SLars-Peter Clausen 	if (component->debugfs_prefix) {
14281c7cfd1SLars-Peter Clausen 		char *name;
143e73f3de5SRussell King 
14481c7cfd1SLars-Peter Clausen 		name = kasprintf(GFP_KERNEL, "%s:%s",
14581c7cfd1SLars-Peter Clausen 			component->debugfs_prefix, component->name);
14681c7cfd1SLars-Peter Clausen 		if (name) {
14781c7cfd1SLars-Peter Clausen 			component->debugfs_root = debugfs_create_dir(name,
14881c7cfd1SLars-Peter Clausen 				component->card->debugfs_card_root);
14981c7cfd1SLars-Peter Clausen 			kfree(name);
15081c7cfd1SLars-Peter Clausen 		}
15181c7cfd1SLars-Peter Clausen 	} else {
15281c7cfd1SLars-Peter Clausen 		component->debugfs_root = debugfs_create_dir(component->name,
15381c7cfd1SLars-Peter Clausen 				component->card->debugfs_card_root);
154e73f3de5SRussell King 	}
155e73f3de5SRussell King 
15681c7cfd1SLars-Peter Clausen 	snd_soc_dapm_debugfs_init(snd_soc_component_get_dapm(component),
15781c7cfd1SLars-Peter Clausen 		component->debugfs_root);
15881c7cfd1SLars-Peter Clausen }
15981c7cfd1SLars-Peter Clausen 
16081c7cfd1SLars-Peter Clausen static void soc_cleanup_component_debugfs(struct snd_soc_component *component)
16181c7cfd1SLars-Peter Clausen {
162ad64bfbdSKuninori Morimoto 	if (!component->debugfs_root)
163ad64bfbdSKuninori Morimoto 		return;
16481c7cfd1SLars-Peter Clausen 	debugfs_remove_recursive(component->debugfs_root);
165ad64bfbdSKuninori Morimoto 	component->debugfs_root = NULL;
16681c7cfd1SLars-Peter Clausen }
16781c7cfd1SLars-Peter Clausen 
168c15b2a1dSPeng Donglin static int dai_list_show(struct seq_file *m, void *v)
169f3208780SMark Brown {
1701438c2f6SLars-Peter Clausen 	struct snd_soc_component *component;
171f3208780SMark Brown 	struct snd_soc_dai *dai;
172f3208780SMark Brown 
17334e81ab4SLars-Peter Clausen 	mutex_lock(&client_mutex);
17434e81ab4SLars-Peter Clausen 
175368dee94SKuninori Morimoto 	for_each_component(component)
17615a0c645SKuninori Morimoto 		for_each_component_dais(component, dai)
177700c17caSDonglin Peng 			seq_printf(m, "%s\n", dai->name);
178f3208780SMark Brown 
17934e81ab4SLars-Peter Clausen 	mutex_unlock(&client_mutex);
18034e81ab4SLars-Peter Clausen 
181700c17caSDonglin Peng 	return 0;
182700c17caSDonglin Peng }
183c15b2a1dSPeng Donglin DEFINE_SHOW_ATTRIBUTE(dai_list);
184f3208780SMark Brown 
185db795f9bSKuninori Morimoto static int component_list_show(struct seq_file *m, void *v)
186db795f9bSKuninori Morimoto {
187db795f9bSKuninori Morimoto 	struct snd_soc_component *component;
188db795f9bSKuninori Morimoto 
189db795f9bSKuninori Morimoto 	mutex_lock(&client_mutex);
190db795f9bSKuninori Morimoto 
191368dee94SKuninori Morimoto 	for_each_component(component)
192db795f9bSKuninori Morimoto 		seq_printf(m, "%s\n", component->name);
193db795f9bSKuninori Morimoto 
194db795f9bSKuninori Morimoto 	mutex_unlock(&client_mutex);
195db795f9bSKuninori Morimoto 
196db795f9bSKuninori Morimoto 	return 0;
197db795f9bSKuninori Morimoto }
198db795f9bSKuninori Morimoto DEFINE_SHOW_ATTRIBUTE(component_list);
199db795f9bSKuninori Morimoto 
200a6052154SJarkko Nikula static void soc_init_card_debugfs(struct snd_soc_card *card)
201a6052154SJarkko Nikula {
202a6052154SJarkko Nikula 	card->debugfs_card_root = debugfs_create_dir(card->name,
2038a9dab1aSMark Brown 						     snd_soc_debugfs_root);
2043a45b867SJarkko Nikula 
205fee531d6SGreg Kroah-Hartman 	debugfs_create_u32("dapm_pop_time", 0644, card->debugfs_card_root,
2063a45b867SJarkko Nikula 			   &card->pop_time);
207d8ca7a0aSKuninori Morimoto 
208d8ca7a0aSKuninori Morimoto 	snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root);
209a6052154SJarkko Nikula }
210a6052154SJarkko Nikula 
211a6052154SJarkko Nikula static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
212a6052154SJarkko Nikula {
213a6052154SJarkko Nikula 	debugfs_remove_recursive(card->debugfs_card_root);
21429040d1aSKuninori Morimoto 	card->debugfs_card_root = NULL;
215a6052154SJarkko Nikula }
216a6052154SJarkko Nikula 
2176553bf06SLars-Peter Clausen static void snd_soc_debugfs_init(void)
2186553bf06SLars-Peter Clausen {
2196553bf06SLars-Peter Clausen 	snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL);
2206553bf06SLars-Peter Clausen 
221fee531d6SGreg Kroah-Hartman 	debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL,
222fee531d6SGreg Kroah-Hartman 			    &dai_list_fops);
223db795f9bSKuninori Morimoto 
224fee531d6SGreg Kroah-Hartman 	debugfs_create_file("components", 0444, snd_soc_debugfs_root, NULL,
225fee531d6SGreg Kroah-Hartman 			    &component_list_fops);
2266553bf06SLars-Peter Clausen }
2276553bf06SLars-Peter Clausen 
2286553bf06SLars-Peter Clausen static void snd_soc_debugfs_exit(void)
2296553bf06SLars-Peter Clausen {
2306553bf06SLars-Peter Clausen 	debugfs_remove_recursive(snd_soc_debugfs_root);
2316553bf06SLars-Peter Clausen }
2326553bf06SLars-Peter Clausen 
2332624d5faSMark Brown #else
2342624d5faSMark Brown 
23581c7cfd1SLars-Peter Clausen static inline void soc_init_component_debugfs(
23681c7cfd1SLars-Peter Clausen 	struct snd_soc_component *component)
2372624d5faSMark Brown {
2382624d5faSMark Brown }
2392624d5faSMark Brown 
24081c7cfd1SLars-Peter Clausen static inline void soc_cleanup_component_debugfs(
24181c7cfd1SLars-Peter Clausen 	struct snd_soc_component *component)
242731f1ab2SSebastien Guiriec {
243731f1ab2SSebastien Guiriec }
244731f1ab2SSebastien Guiriec 
245b95fccbcSAxel Lin static inline void soc_init_card_debugfs(struct snd_soc_card *card)
246b95fccbcSAxel Lin {
247b95fccbcSAxel Lin }
248b95fccbcSAxel Lin 
249b95fccbcSAxel Lin static inline void soc_cleanup_card_debugfs(struct snd_soc_card *card)
250b95fccbcSAxel Lin {
251b95fccbcSAxel Lin }
2526553bf06SLars-Peter Clausen 
2536553bf06SLars-Peter Clausen static inline void snd_soc_debugfs_init(void)
2546553bf06SLars-Peter Clausen {
2556553bf06SLars-Peter Clausen }
2566553bf06SLars-Peter Clausen 
2576553bf06SLars-Peter Clausen static inline void snd_soc_debugfs_exit(void)
2586553bf06SLars-Peter Clausen {
2596553bf06SLars-Peter Clausen }
2606553bf06SLars-Peter Clausen 
2612624d5faSMark Brown #endif
2622624d5faSMark Brown 
2638ec241c4SKuninori Morimoto /*
2648ec241c4SKuninori Morimoto  * This is glue code between snd_pcm_lib_ioctl() and
2658ec241c4SKuninori Morimoto  * snd_soc_component_driver :: ioctl
2668ec241c4SKuninori Morimoto  */
2678ec241c4SKuninori Morimoto int snd_soc_pcm_lib_ioctl(struct snd_soc_component *component,
2688ec241c4SKuninori Morimoto 			  struct snd_pcm_substream *substream,
2698ec241c4SKuninori Morimoto 			  unsigned int cmd, void *arg)
2708ec241c4SKuninori Morimoto {
2718ec241c4SKuninori Morimoto 	return snd_pcm_lib_ioctl(substream, cmd, arg);
2728ec241c4SKuninori Morimoto }
2738ec241c4SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_pcm_lib_ioctl);
2748ec241c4SKuninori Morimoto 
275a0ac4411SKuninori Morimoto static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd,
276a0ac4411SKuninori Morimoto 			      struct snd_soc_component *component)
277a0ac4411SKuninori Morimoto {
278a0ac4411SKuninori Morimoto 	struct snd_soc_rtdcom_list *rtdcom;
2792b544dd7SKuninori Morimoto 	struct snd_soc_component *comp;
280a0ac4411SKuninori Morimoto 
2812b544dd7SKuninori Morimoto 	for_each_rtd_components(rtd, rtdcom, comp) {
282a0ac4411SKuninori Morimoto 		/* already connected */
2832b544dd7SKuninori Morimoto 		if (comp == component)
284a0ac4411SKuninori Morimoto 			return 0;
285a0ac4411SKuninori Morimoto 	}
286a0ac4411SKuninori Morimoto 
287353e16bfSKuninori Morimoto 	/*
288353e16bfSKuninori Morimoto 	 * created rtdcom here will be freed when rtd->dev was freed.
289353e16bfSKuninori Morimoto 	 * see
290353e16bfSKuninori Morimoto 	 *	soc_free_pcm_runtime() :: device_unregister(rtd->dev)
291353e16bfSKuninori Morimoto 	 */
292353e16bfSKuninori Morimoto 	rtdcom = devm_kzalloc(rtd->dev, sizeof(*rtdcom), GFP_KERNEL);
29332d2c172SKuninori Morimoto 	if (!rtdcom)
294a0ac4411SKuninori Morimoto 		return -ENOMEM;
295a0ac4411SKuninori Morimoto 
29632d2c172SKuninori Morimoto 	rtdcom->component = component;
29732d2c172SKuninori Morimoto 	INIT_LIST_HEAD(&rtdcom->list);
298a0ac4411SKuninori Morimoto 
299353e16bfSKuninori Morimoto 	/*
300353e16bfSKuninori Morimoto 	 * When rtd was freed, created rtdcom here will be
301353e16bfSKuninori Morimoto 	 * also freed.
302353e16bfSKuninori Morimoto 	 * And we don't need to call list_del(&rtdcom->list)
303353e16bfSKuninori Morimoto 	 * when freed, because rtd is also freed.
304353e16bfSKuninori Morimoto 	 */
30532d2c172SKuninori Morimoto 	list_add_tail(&rtdcom->list, &rtd->component_list);
306a0ac4411SKuninori Morimoto 
307a0ac4411SKuninori Morimoto 	return 0;
308a0ac4411SKuninori Morimoto }
309a0ac4411SKuninori Morimoto 
310a0ac4411SKuninori Morimoto struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd,
311a0ac4411SKuninori Morimoto 						const char *driver_name)
312a0ac4411SKuninori Morimoto {
313a0ac4411SKuninori Morimoto 	struct snd_soc_rtdcom_list *rtdcom;
3142b544dd7SKuninori Morimoto 	struct snd_soc_component *component;
315a0ac4411SKuninori Morimoto 
316971da24cSKuninori Morimoto 	if (!driver_name)
317971da24cSKuninori Morimoto 		return NULL;
318971da24cSKuninori Morimoto 
319a33c0d16SKuninori Morimoto 	/*
320a33c0d16SKuninori Morimoto 	 * NOTE
321a33c0d16SKuninori Morimoto 	 *
322a33c0d16SKuninori Morimoto 	 * snd_soc_rtdcom_lookup() will find component from rtd by using
323a33c0d16SKuninori Morimoto 	 * specified driver name.
324a33c0d16SKuninori Morimoto 	 * But, if many components which have same driver name are connected
325a33c0d16SKuninori Morimoto 	 * to 1 rtd, this function will return 1st found component.
326a33c0d16SKuninori Morimoto 	 */
3272b544dd7SKuninori Morimoto 	for_each_rtd_components(rtd, rtdcom, component) {
3282b544dd7SKuninori Morimoto 		const char *component_name = component->driver->name;
329971da24cSKuninori Morimoto 
330971da24cSKuninori Morimoto 		if (!component_name)
331971da24cSKuninori Morimoto 			continue;
332971da24cSKuninori Morimoto 
333971da24cSKuninori Morimoto 		if ((component_name == driver_name) ||
334971da24cSKuninori Morimoto 		    strcmp(component_name, driver_name) == 0)
335a0ac4411SKuninori Morimoto 			return rtdcom->component;
336a0ac4411SKuninori Morimoto 	}
337a0ac4411SKuninori Morimoto 
338a0ac4411SKuninori Morimoto 	return NULL;
339a0ac4411SKuninori Morimoto }
340031734b7SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_rtdcom_lookup);
341a0ac4411SKuninori Morimoto 
34218dd66eaSKuninori Morimoto static struct snd_soc_component
34318dd66eaSKuninori Morimoto *snd_soc_lookup_component_nolocked(struct device *dev, const char *driver_name)
344b8132657SKuninori Morimoto {
345b8132657SKuninori Morimoto 	struct snd_soc_component *component;
3465bd7e08bSKuninori Morimoto 	struct snd_soc_component *found_component;
347b8132657SKuninori Morimoto 
3485bd7e08bSKuninori Morimoto 	found_component = NULL;
349b8132657SKuninori Morimoto 	for_each_component(component) {
3505bd7e08bSKuninori Morimoto 		if ((dev == component->dev) &&
3515bd7e08bSKuninori Morimoto 		    (!driver_name ||
3525bd7e08bSKuninori Morimoto 		     (driver_name == component->driver->name) ||
3535bd7e08bSKuninori Morimoto 		     (strcmp(component->driver->name, driver_name) == 0))) {
3545bd7e08bSKuninori Morimoto 			found_component = component;
355b8132657SKuninori Morimoto 			break;
356b8132657SKuninori Morimoto 		}
3575bd7e08bSKuninori Morimoto 	}
358b8132657SKuninori Morimoto 
3595bd7e08bSKuninori Morimoto 	return found_component;
360b8132657SKuninori Morimoto }
36118dd66eaSKuninori Morimoto 
36218dd66eaSKuninori Morimoto struct snd_soc_component *snd_soc_lookup_component(struct device *dev,
36318dd66eaSKuninori Morimoto 						   const char *driver_name)
36418dd66eaSKuninori Morimoto {
36518dd66eaSKuninori Morimoto 	struct snd_soc_component *component;
36618dd66eaSKuninori Morimoto 
36718dd66eaSKuninori Morimoto 	mutex_lock(&client_mutex);
36818dd66eaSKuninori Morimoto 	component = snd_soc_lookup_component_nolocked(dev, driver_name);
36918dd66eaSKuninori Morimoto 	mutex_unlock(&client_mutex);
37018dd66eaSKuninori Morimoto 
37118dd66eaSKuninori Morimoto 	return component;
37218dd66eaSKuninori Morimoto }
373b8132657SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_lookup_component);
374b8132657SKuninori Morimoto 
37575ab9eb6SKuninori Morimoto static const struct snd_soc_ops null_snd_soc_ops;
37675ab9eb6SKuninori Morimoto 
37794def8eaSKuninori Morimoto struct snd_soc_pcm_runtime
37894def8eaSKuninori Morimoto *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
3794468189fSKuninori Morimoto 			 struct snd_soc_dai_link *dai_link)
38094def8eaSKuninori Morimoto {
38194def8eaSKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd;
38294def8eaSKuninori Morimoto 
38394def8eaSKuninori Morimoto 	for_each_card_rtds(card, rtd) {
3844468189fSKuninori Morimoto 		if (rtd->dai_link == dai_link)
38594def8eaSKuninori Morimoto 			return rtd;
38694def8eaSKuninori Morimoto 	}
3874468189fSKuninori Morimoto 	dev_dbg(card->dev, "ASoC: failed to find rtd %s\n", dai_link->name);
38894def8eaSKuninori Morimoto 	return NULL;
38994def8eaSKuninori Morimoto }
39094def8eaSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime);
39194def8eaSKuninori Morimoto 
3926e864344SKuninori Morimoto static void soc_release_rtd_dev(struct device *dev)
3936e864344SKuninori Morimoto {
3946e864344SKuninori Morimoto 	/* "dev" means "rtd->dev" */
3956e864344SKuninori Morimoto 	kfree(dev);
3966e864344SKuninori Morimoto }
3976e864344SKuninori Morimoto 
3981c93a9e0SKuninori Morimoto static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd)
3991c93a9e0SKuninori Morimoto {
4006e864344SKuninori Morimoto 	if (!rtd)
4016e864344SKuninori Morimoto 		return;
4026e864344SKuninori Morimoto 
403753ace0aSKuninori Morimoto 	list_del(&rtd->list);
404b7c5bc45SKuninori Morimoto 
4059c9b6520SCurtis Malainey 	if (delayed_work_pending(&rtd->delayed_work))
4060ced7b05SKuninori Morimoto 		flush_delayed_work(&rtd->delayed_work);
4070ced7b05SKuninori Morimoto 	snd_soc_pcm_component_free(rtd);
4080ced7b05SKuninori Morimoto 
409b7c5bc45SKuninori Morimoto 	/*
410b7c5bc45SKuninori Morimoto 	 * we don't need to call kfree() for rtd->dev
411b7c5bc45SKuninori Morimoto 	 * see
412b7c5bc45SKuninori Morimoto 	 *	soc_release_rtd_dev()
413d918a376SKuninori Morimoto 	 *
414d918a376SKuninori Morimoto 	 * We don't need rtd->dev NULL check, because
415d918a376SKuninori Morimoto 	 * it is alloced *before* rtd.
416d918a376SKuninori Morimoto 	 * see
417d918a376SKuninori Morimoto 	 *	soc_new_pcm_runtime()
418b7c5bc45SKuninori Morimoto 	 */
419b7c5bc45SKuninori Morimoto 	device_unregister(rtd->dev);
4201c93a9e0SKuninori Morimoto }
4211c93a9e0SKuninori Morimoto 
4224bf2e385SCurtis Malainey static void close_delayed_work(struct work_struct *work) {
4234bf2e385SCurtis Malainey 	struct snd_soc_pcm_runtime *rtd =
4244bf2e385SCurtis Malainey 			container_of(work, struct snd_soc_pcm_runtime,
4254bf2e385SCurtis Malainey 				     delayed_work.work);
4264bf2e385SCurtis Malainey 
4274bf2e385SCurtis Malainey 	if (rtd->close_delayed_work_func)
4284bf2e385SCurtis Malainey 		rtd->close_delayed_work_func(rtd);
4294bf2e385SCurtis Malainey }
4304bf2e385SCurtis Malainey 
4311a497983SMengdong Lin static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
4321a497983SMengdong Lin 	struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
4331a497983SMengdong Lin {
4341a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
435d918a376SKuninori Morimoto 	struct device *dev;
4366e864344SKuninori Morimoto 	int ret;
4371a497983SMengdong Lin 
4386e864344SKuninori Morimoto 	/*
439d918a376SKuninori Morimoto 	 * for rtd->dev
440d918a376SKuninori Morimoto 	 */
441d918a376SKuninori Morimoto 	dev = kzalloc(sizeof(struct device), GFP_KERNEL);
442d918a376SKuninori Morimoto 	if (!dev)
443d918a376SKuninori Morimoto 		return NULL;
444d918a376SKuninori Morimoto 
445d918a376SKuninori Morimoto 	dev->parent	= card->dev;
446d918a376SKuninori Morimoto 	dev->release	= soc_release_rtd_dev;
447d918a376SKuninori Morimoto 	dev->groups	= soc_dev_attr_groups;
448d918a376SKuninori Morimoto 
449d918a376SKuninori Morimoto 	dev_set_name(dev, "%s", dai_link->name);
450d918a376SKuninori Morimoto 
451d918a376SKuninori Morimoto 	ret = device_register(dev);
452d918a376SKuninori Morimoto 	if (ret < 0) {
453d918a376SKuninori Morimoto 		put_device(dev); /* soc_release_rtd_dev */
454d918a376SKuninori Morimoto 		return NULL;
455d918a376SKuninori Morimoto 	}
456d918a376SKuninori Morimoto 
457d918a376SKuninori Morimoto 	/*
4586e864344SKuninori Morimoto 	 * for rtd
4596e864344SKuninori Morimoto 	 */
4604dc0e7dfSKuninori Morimoto 	rtd = devm_kzalloc(dev, sizeof(*rtd), GFP_KERNEL);
4611a497983SMengdong Lin 	if (!rtd)
4626e864344SKuninori Morimoto 		goto free_rtd;
4631a497983SMengdong Lin 
464d918a376SKuninori Morimoto 	rtd->dev = dev;
465d918a376SKuninori Morimoto 	dev_set_drvdata(dev, rtd);
4664bf2e385SCurtis Malainey 	INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
467d918a376SKuninori Morimoto 
4686e864344SKuninori Morimoto 	/*
4696e864344SKuninori Morimoto 	 * for rtd->codec_dais
4706e864344SKuninori Morimoto 	 */
4714dc0e7dfSKuninori Morimoto 	rtd->codec_dais = devm_kcalloc(dev, dai_link->num_codecs,
4726396bb22SKees Cook 					sizeof(struct snd_soc_dai *),
4731a497983SMengdong Lin 					GFP_KERNEL);
4746e864344SKuninori Morimoto 	if (!rtd->codec_dais)
4756e864344SKuninori Morimoto 		goto free_rtd;
4766e864344SKuninori Morimoto 
4776e864344SKuninori Morimoto 	/*
4786e864344SKuninori Morimoto 	 * rtd remaining settings
4796e864344SKuninori Morimoto 	 */
480929deb84SKuninori Morimoto 	INIT_LIST_HEAD(&rtd->component_list);
4816e864344SKuninori Morimoto 	INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients);
4826e864344SKuninori Morimoto 	INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients);
4836e864344SKuninori Morimoto 	INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].fe_clients);
4846e864344SKuninori Morimoto 	INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients);
4856e864344SKuninori Morimoto 
486929deb84SKuninori Morimoto 	rtd->card = card;
487929deb84SKuninori Morimoto 	rtd->dai_link = dai_link;
488929deb84SKuninori Morimoto 	if (!rtd->dai_link->ops)
489929deb84SKuninori Morimoto 		rtd->dai_link->ops = &null_snd_soc_ops;
490929deb84SKuninori Morimoto 
4916634e3d6SKuninori Morimoto 	/* see for_each_card_rtds */
4921a497983SMengdong Lin 	list_add_tail(&rtd->list, &card->rtd_list);
4931a497983SMengdong Lin 	rtd->num = card->num_rtd;
4941a497983SMengdong Lin 	card->num_rtd++;
495a848125eSKuninori Morimoto 
496a848125eSKuninori Morimoto 	return rtd;
4976e864344SKuninori Morimoto 
4986e864344SKuninori Morimoto free_rtd:
4996e864344SKuninori Morimoto 	soc_free_pcm_runtime(rtd);
5006e864344SKuninori Morimoto 	return NULL;
5011a497983SMengdong Lin }
5021a497983SMengdong Lin 
50365462e44SKuninori Morimoto static void snd_soc_flush_all_delayed_work(struct snd_soc_card *card)
50465462e44SKuninori Morimoto {
50565462e44SKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd;
50665462e44SKuninori Morimoto 
50765462e44SKuninori Morimoto 	for_each_card_rtds(card, rtd)
50865462e44SKuninori Morimoto 		flush_delayed_work(&rtd->delayed_work);
50965462e44SKuninori Morimoto }
51065462e44SKuninori Morimoto 
5116f8ab4acSMark Brown #ifdef CONFIG_PM_SLEEP
512db2a4165SFrank Mandarino /* powers down audio subsystem for suspend */
5136f8ab4acSMark Brown int snd_soc_suspend(struct device *dev)
514db2a4165SFrank Mandarino {
5156f8ab4acSMark Brown 	struct snd_soc_card *card = dev_get_drvdata(dev);
516d9fc4063SKuninori Morimoto 	struct snd_soc_component *component;
5171a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
5181a497983SMengdong Lin 	int i;
519db2a4165SFrank Mandarino 
520c5599b87SLars-Peter Clausen 	/* If the card is not initialized yet there is nothing to do */
521c5599b87SLars-Peter Clausen 	if (!card->instantiated)
522e3509ff0SDaniel Mack 		return 0;
523e3509ff0SDaniel Mack 
5242c7b696aSMarcel Ziswiler 	/*
5252c7b696aSMarcel Ziswiler 	 * Due to the resume being scheduled into a workqueue we could
5266ed25978SAndy Green 	 * suspend before that's finished - wait for it to complete.
5276ed25978SAndy Green 	 */
528f0fba2adSLiam Girdwood 	snd_power_wait(card->snd_card, SNDRV_CTL_POWER_D0);
5296ed25978SAndy Green 
5306ed25978SAndy Green 	/* we're going to block userspace touching us until resume completes */
531f0fba2adSLiam Girdwood 	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
5326ed25978SAndy Green 
533a00f90f9SMark Brown 	/* mute any active DACs */
534bcb1fd1fSKuninori Morimoto 	for_each_card_rtds(card, rtd) {
5350b7990e3SKuninori Morimoto 		struct snd_soc_dai *dai;
5363efab7dcSMark Brown 
5371a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
5383efab7dcSMark Brown 			continue;
5393efab7dcSMark Brown 
5400b7990e3SKuninori Morimoto 		for_each_rtd_codec_dai(rtd, i, dai) {
54188fdffa2SKuninori Morimoto 			if (dai->playback_active)
54288fdffa2SKuninori Morimoto 				snd_soc_dai_digital_mute(dai, 1,
54388fdffa2SKuninori Morimoto 						SNDRV_PCM_STREAM_PLAYBACK);
544db2a4165SFrank Mandarino 		}
54588bd870fSBenoit Cousson 	}
546db2a4165SFrank Mandarino 
5474ccab3e7SLiam Girdwood 	/* suspend all pcms */
548bcb1fd1fSKuninori Morimoto 	for_each_card_rtds(card, rtd) {
5491a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
5503efab7dcSMark Brown 			continue;
5513efab7dcSMark Brown 
5521a497983SMengdong Lin 		snd_pcm_suspend_all(rtd->pcm);
5533efab7dcSMark Brown 	}
5544ccab3e7SLiam Girdwood 
55587506549SMark Brown 	if (card->suspend_pre)
55670b2ac12SMark Brown 		card->suspend_pre(card);
557db2a4165SFrank Mandarino 
558bcb1fd1fSKuninori Morimoto 	for_each_card_rtds(card, rtd) {
5591a497983SMengdong Lin 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
5603efab7dcSMark Brown 
5611a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
5623efab7dcSMark Brown 			continue;
5633efab7dcSMark Brown 
564e0f22622SKuninori Morimoto 		if (!cpu_dai->driver->bus_control)
565e0f22622SKuninori Morimoto 			snd_soc_dai_suspend(cpu_dai);
566db2a4165SFrank Mandarino 	}
567db2a4165SFrank Mandarino 
56837660b6dSLars-Peter Clausen 	/* close any waiting streams */
56965462e44SKuninori Morimoto 	snd_soc_flush_all_delayed_work(card);
570db2a4165SFrank Mandarino 
571bcb1fd1fSKuninori Morimoto 	for_each_card_rtds(card, rtd) {
5723efab7dcSMark Brown 
5731a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
5743efab7dcSMark Brown 			continue;
5753efab7dcSMark Brown 
5761a497983SMengdong Lin 		snd_soc_dapm_stream_event(rtd,
5777bd3a6f3SMark Brown 					  SNDRV_PCM_STREAM_PLAYBACK,
578db2a4165SFrank Mandarino 					  SND_SOC_DAPM_STREAM_SUSPEND);
579f0fba2adSLiam Girdwood 
5801a497983SMengdong Lin 		snd_soc_dapm_stream_event(rtd,
5817bd3a6f3SMark Brown 					  SNDRV_PCM_STREAM_CAPTURE,
582db2a4165SFrank Mandarino 					  SND_SOC_DAPM_STREAM_SUSPEND);
583db2a4165SFrank Mandarino 	}
584db2a4165SFrank Mandarino 
5858be4da29SLars-Peter Clausen 	/* Recheck all endpoints too, their state is affected by suspend */
5868be4da29SLars-Peter Clausen 	dapm_mark_endpoints_dirty(card);
587e2d32ff6SMark Brown 	snd_soc_dapm_sync(&card->dapm);
588e2d32ff6SMark Brown 
5899178feb4SKuninori Morimoto 	/* suspend all COMPONENTs */
590f70f18f7SKuninori Morimoto 	for_each_card_components(card, component) {
5912c7b696aSMarcel Ziswiler 		struct snd_soc_dapm_context *dapm =
5922c7b696aSMarcel Ziswiler 				snd_soc_component_get_dapm(component);
593d9fc4063SKuninori Morimoto 
5942c7b696aSMarcel Ziswiler 		/*
5952c7b696aSMarcel Ziswiler 		 * If there are paths active then the COMPONENT will be held
5962c7b696aSMarcel Ziswiler 		 * with bias _ON and should not be suspended.
5972c7b696aSMarcel Ziswiler 		 */
598e40fadbcSKuninori Morimoto 		if (!snd_soc_component_is_suspended(component)) {
5994890140fSLars-Peter Clausen 			switch (snd_soc_dapm_get_bias_level(dapm)) {
6001547aba9SMark Brown 			case SND_SOC_BIAS_STANDBY:
601125a25daSMark Brown 				/*
6029178feb4SKuninori Morimoto 				 * If the COMPONENT is capable of idle
603125a25daSMark Brown 				 * bias off then being in STANDBY
604125a25daSMark Brown 				 * means it's doing something,
605125a25daSMark Brown 				 * otherwise fall through.
606125a25daSMark Brown 				 */
6074890140fSLars-Peter Clausen 				if (dapm->idle_bias_off) {
6089178feb4SKuninori Morimoto 					dev_dbg(component->dev,
60910e8aa9aSMichał Mirosław 						"ASoC: idle_bias_off CODEC on over suspend\n");
610125a25daSMark Brown 					break;
611125a25daSMark Brown 				}
6121a12d5dcSGustavo A. R. Silva 				/* fall through */
613a8093297SLars-Peter Clausen 
6141547aba9SMark Brown 			case SND_SOC_BIAS_OFF:
61566c51573SKuninori Morimoto 				snd_soc_component_suspend(component);
6169178feb4SKuninori Morimoto 				if (component->regmap)
6179178feb4SKuninori Morimoto 					regcache_mark_dirty(component->regmap);
618988e8cc4SNicolin Chen 				/* deactivate pins to sleep state */
6199178feb4SKuninori Morimoto 				pinctrl_pm_select_sleep_state(component->dev);
6201547aba9SMark Brown 				break;
6211547aba9SMark Brown 			default:
6229178feb4SKuninori Morimoto 				dev_dbg(component->dev,
6239178feb4SKuninori Morimoto 					"ASoC: COMPONENT is on over suspend\n");
6241547aba9SMark Brown 				break;
6251547aba9SMark Brown 			}
6261547aba9SMark Brown 		}
627f0fba2adSLiam Girdwood 	}
628db2a4165SFrank Mandarino 
629bcb1fd1fSKuninori Morimoto 	for_each_card_rtds(card, rtd) {
6301a497983SMengdong Lin 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
6313efab7dcSMark Brown 
6321a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
6333efab7dcSMark Brown 			continue;
6343efab7dcSMark Brown 
635e0f22622SKuninori Morimoto 		if (cpu_dai->driver->bus_control)
636e0f22622SKuninori Morimoto 			snd_soc_dai_suspend(cpu_dai);
637988e8cc4SNicolin Chen 
638988e8cc4SNicolin Chen 		/* deactivate pins to sleep state */
639988e8cc4SNicolin Chen 		pinctrl_pm_select_sleep_state(cpu_dai->dev);
640db2a4165SFrank Mandarino 	}
641db2a4165SFrank Mandarino 
64287506549SMark Brown 	if (card->suspend_post)
64370b2ac12SMark Brown 		card->suspend_post(card);
644db2a4165SFrank Mandarino 
645db2a4165SFrank Mandarino 	return 0;
646db2a4165SFrank Mandarino }
6476f8ab4acSMark Brown EXPORT_SYMBOL_GPL(snd_soc_suspend);
648db2a4165SFrank Mandarino 
6492c7b696aSMarcel Ziswiler /*
6502c7b696aSMarcel Ziswiler  * deferred resume work, so resume can complete before we finished
6516ed25978SAndy Green  * setting our codec back up, which can be very slow on I2C
6526ed25978SAndy Green  */
6536ed25978SAndy Green static void soc_resume_deferred(struct work_struct *work)
654db2a4165SFrank Mandarino {
655f0fba2adSLiam Girdwood 	struct snd_soc_card *card =
6562c7b696aSMarcel Ziswiler 			container_of(work, struct snd_soc_card,
6572c7b696aSMarcel Ziswiler 				     deferred_resume_work);
6581a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
659d9fc4063SKuninori Morimoto 	struct snd_soc_component *component;
6601a497983SMengdong Lin 	int i;
661db2a4165SFrank Mandarino 
6622c7b696aSMarcel Ziswiler 	/*
6632c7b696aSMarcel Ziswiler 	 * our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
6646ed25978SAndy Green 	 * so userspace apps are blocked from touching us
6656ed25978SAndy Green 	 */
6666ed25978SAndy Green 
667f110bfc7SLiam Girdwood 	dev_dbg(card->dev, "ASoC: starting resume work\n");
6686ed25978SAndy Green 
6699949788bSMark Brown 	/* Bring us up into D2 so that DAPM starts enabling things */
670f0fba2adSLiam Girdwood 	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D2);
6719949788bSMark Brown 
67287506549SMark Brown 	if (card->resume_pre)
67370b2ac12SMark Brown 		card->resume_pre(card);
674db2a4165SFrank Mandarino 
675bc263214SLars-Peter Clausen 	/* resume control bus DAIs */
676bcb1fd1fSKuninori Morimoto 	for_each_card_rtds(card, rtd) {
6771a497983SMengdong Lin 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
6783efab7dcSMark Brown 
6791a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
6803efab7dcSMark Brown 			continue;
6813efab7dcSMark Brown 
68224b09d05SKuninori Morimoto 		if (cpu_dai->driver->bus_control)
68324b09d05SKuninori Morimoto 			snd_soc_dai_resume(cpu_dai);
684db2a4165SFrank Mandarino 	}
685db2a4165SFrank Mandarino 
686f70f18f7SKuninori Morimoto 	for_each_card_components(card, component) {
687e40fadbcSKuninori Morimoto 		if (snd_soc_component_is_suspended(component))
6889a840cbaSKuninori Morimoto 			snd_soc_component_resume(component);
6891547aba9SMark Brown 	}
690db2a4165SFrank Mandarino 
691bcb1fd1fSKuninori Morimoto 	for_each_card_rtds(card, rtd) {
6923efab7dcSMark Brown 
6931a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
6943efab7dcSMark Brown 			continue;
6953efab7dcSMark Brown 
6961a497983SMengdong Lin 		snd_soc_dapm_stream_event(rtd,
697d9b0951bSLiam Girdwood 					  SNDRV_PCM_STREAM_PLAYBACK,
698db2a4165SFrank Mandarino 					  SND_SOC_DAPM_STREAM_RESUME);
699f0fba2adSLiam Girdwood 
7001a497983SMengdong Lin 		snd_soc_dapm_stream_event(rtd,
701d9b0951bSLiam Girdwood 					  SNDRV_PCM_STREAM_CAPTURE,
702db2a4165SFrank Mandarino 					  SND_SOC_DAPM_STREAM_RESUME);
703db2a4165SFrank Mandarino 	}
704db2a4165SFrank Mandarino 
7053ff3f64bSMark Brown 	/* unmute any active DACs */
706bcb1fd1fSKuninori Morimoto 	for_each_card_rtds(card, rtd) {
7070b7990e3SKuninori Morimoto 		struct snd_soc_dai *dai;
7083efab7dcSMark Brown 
7091a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
7103efab7dcSMark Brown 			continue;
7113efab7dcSMark Brown 
7120b7990e3SKuninori Morimoto 		for_each_rtd_codec_dai(rtd, i, dai) {
71388fdffa2SKuninori Morimoto 			if (dai->playback_active)
71488fdffa2SKuninori Morimoto 				snd_soc_dai_digital_mute(dai, 0,
71588fdffa2SKuninori Morimoto 						SNDRV_PCM_STREAM_PLAYBACK);
716db2a4165SFrank Mandarino 		}
71788bd870fSBenoit Cousson 	}
718db2a4165SFrank Mandarino 
719bcb1fd1fSKuninori Morimoto 	for_each_card_rtds(card, rtd) {
7201a497983SMengdong Lin 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
7213efab7dcSMark Brown 
7221a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
7233efab7dcSMark Brown 			continue;
7243efab7dcSMark Brown 
72524b09d05SKuninori Morimoto 		if (!cpu_dai->driver->bus_control)
72624b09d05SKuninori Morimoto 			snd_soc_dai_resume(cpu_dai);
727db2a4165SFrank Mandarino 	}
728db2a4165SFrank Mandarino 
72987506549SMark Brown 	if (card->resume_post)
73070b2ac12SMark Brown 		card->resume_post(card);
731db2a4165SFrank Mandarino 
732f110bfc7SLiam Girdwood 	dev_dbg(card->dev, "ASoC: resume work completed\n");
7336ed25978SAndy Green 
7348be4da29SLars-Peter Clausen 	/* Recheck all endpoints too, their state is affected by suspend */
7358be4da29SLars-Peter Clausen 	dapm_mark_endpoints_dirty(card);
736e2d32ff6SMark Brown 	snd_soc_dapm_sync(&card->dapm);
7371a7aaa58SJeeja KP 
7381a7aaa58SJeeja KP 	/* userspace can access us now we are back as we were before */
7391a7aaa58SJeeja KP 	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0);
7406ed25978SAndy Green }
7416ed25978SAndy Green 
7426ed25978SAndy Green /* powers up audio subsystem after a suspend */
7436f8ab4acSMark Brown int snd_soc_resume(struct device *dev)
7446ed25978SAndy Green {
7456f8ab4acSMark Brown 	struct snd_soc_card *card = dev_get_drvdata(dev);
746bc263214SLars-Peter Clausen 	bool bus_control = false;
7471a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
74822d251a5SKuninori Morimoto 	struct snd_soc_dai *codec_dai;
74922d251a5SKuninori Morimoto 	int i;
750b9dd94a8SPeter Ujfalusi 
751c5599b87SLars-Peter Clausen 	/* If the card is not initialized yet there is nothing to do */
752c5599b87SLars-Peter Clausen 	if (!card->instantiated)
7535ff1ddf2SEric Miao 		return 0;
7545ff1ddf2SEric Miao 
755988e8cc4SNicolin Chen 	/* activate pins from sleep state */
756bcb1fd1fSKuninori Morimoto 	for_each_card_rtds(card, rtd) {
75788bd870fSBenoit Cousson 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
75888bd870fSBenoit Cousson 
759988e8cc4SNicolin Chen 		if (cpu_dai->active)
760988e8cc4SNicolin Chen 			pinctrl_pm_select_default_state(cpu_dai->dev);
76188bd870fSBenoit Cousson 
76222d251a5SKuninori Morimoto 		for_each_rtd_codec_dai(rtd, i, codec_dai) {
763988e8cc4SNicolin Chen 			if (codec_dai->active)
764988e8cc4SNicolin Chen 				pinctrl_pm_select_default_state(codec_dai->dev);
765988e8cc4SNicolin Chen 		}
76688bd870fSBenoit Cousson 	}
767988e8cc4SNicolin Chen 
768bc263214SLars-Peter Clausen 	/*
769bc263214SLars-Peter Clausen 	 * DAIs that also act as the control bus master might have other drivers
770bc263214SLars-Peter Clausen 	 * hanging off them so need to resume immediately. Other drivers don't
771bc263214SLars-Peter Clausen 	 * have that problem and may take a substantial amount of time to resume
77264ab9baaSMark Brown 	 * due to I/O costs and anti-pop so handle them out of line.
77364ab9baaSMark Brown 	 */
774bcb1fd1fSKuninori Morimoto 	for_each_card_rtds(card, rtd) {
7751a497983SMengdong Lin 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
7762c7b696aSMarcel Ziswiler 
777bc263214SLars-Peter Clausen 		bus_control |= cpu_dai->driver->bus_control;
77882e14e8bSStephen Warren 	}
779bc263214SLars-Peter Clausen 	if (bus_control) {
780bc263214SLars-Peter Clausen 		dev_dbg(dev, "ASoC: Resuming control bus master immediately\n");
78164ab9baaSMark Brown 		soc_resume_deferred(&card->deferred_resume_work);
78264ab9baaSMark Brown 	} else {
783f110bfc7SLiam Girdwood 		dev_dbg(dev, "ASoC: Scheduling resume work\n");
7846308419aSMark Brown 		if (!schedule_work(&card->deferred_resume_work))
785f110bfc7SLiam Girdwood 			dev_err(dev, "ASoC: resume work item may be lost\n");
786f0fba2adSLiam Girdwood 	}
7876ed25978SAndy Green 
788db2a4165SFrank Mandarino 	return 0;
789db2a4165SFrank Mandarino }
7906f8ab4acSMark Brown EXPORT_SYMBOL_GPL(snd_soc_resume);
791b3da4251SKuninori Morimoto 
792b3da4251SKuninori Morimoto static void soc_resume_init(struct snd_soc_card *card)
793b3da4251SKuninori Morimoto {
794b3da4251SKuninori Morimoto 	/* deferred resume work */
795b3da4251SKuninori Morimoto 	INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
796b3da4251SKuninori Morimoto }
797db2a4165SFrank Mandarino #else
7986f8ab4acSMark Brown #define snd_soc_suspend NULL
7996f8ab4acSMark Brown #define snd_soc_resume NULL
800b3da4251SKuninori Morimoto static inline void soc_resume_init(struct snd_soc_card *card)
801b3da4251SKuninori Morimoto {
802b3da4251SKuninori Morimoto }
803db2a4165SFrank Mandarino #endif
804db2a4165SFrank Mandarino 
80585e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops null_dai_ops = {
80602a06d30SBarry Song };
80702a06d30SBarry Song 
808c0834440SKuninori Morimoto static struct device_node
809c0834440SKuninori Morimoto *soc_component_to_node(struct snd_soc_component *component)
81012023a9aSMisael Lopez Cruz {
811c0834440SKuninori Morimoto 	struct device_node *of_node;
81212023a9aSMisael Lopez Cruz 
813c0834440SKuninori Morimoto 	of_node = component->dev->of_node;
814c0834440SKuninori Morimoto 	if (!of_node && component->dev->parent)
815c0834440SKuninori Morimoto 		of_node = component->dev->parent->of_node;
81634e81ab4SLars-Peter Clausen 
817c0834440SKuninori Morimoto 	return of_node;
81812023a9aSMisael Lopez Cruz }
81912023a9aSMisael Lopez Cruz 
820be6ac0a9SKuninori Morimoto static int snd_soc_is_matching_component(
821be6ac0a9SKuninori Morimoto 	const struct snd_soc_dai_link_component *dlc,
822be6ac0a9SKuninori Morimoto 	struct snd_soc_component *component)
823be6ac0a9SKuninori Morimoto {
824be6ac0a9SKuninori Morimoto 	struct device_node *component_of_node;
825be6ac0a9SKuninori Morimoto 
8267d7db5d3SKuninori Morimoto 	if (!dlc)
8277d7db5d3SKuninori Morimoto 		return 0;
8287d7db5d3SKuninori Morimoto 
8297d7db5d3SKuninori Morimoto 	component_of_node = soc_component_to_node(component);
830be6ac0a9SKuninori Morimoto 
831be6ac0a9SKuninori Morimoto 	if (dlc->of_node && component_of_node != dlc->of_node)
832be6ac0a9SKuninori Morimoto 		return 0;
833be6ac0a9SKuninori Morimoto 	if (dlc->name && strcmp(component->name, dlc->name))
834be6ac0a9SKuninori Morimoto 		return 0;
835be6ac0a9SKuninori Morimoto 
836be6ac0a9SKuninori Morimoto 	return 1;
837be6ac0a9SKuninori Morimoto }
838be6ac0a9SKuninori Morimoto 
839db2a4165SFrank Mandarino static struct snd_soc_component *soc_find_component(
840c1e230f0SKuninori Morimoto 	const struct snd_soc_dai_link_component *dlc)
841db2a4165SFrank Mandarino {
842db2a4165SFrank Mandarino 	struct snd_soc_component *component;
843db2a4165SFrank Mandarino 
844db2a4165SFrank Mandarino 	lockdep_assert_held(&client_mutex);
845db2a4165SFrank Mandarino 
846e3303268SKuninori Morimoto 	/*
847e3303268SKuninori Morimoto 	 * NOTE
848e3303268SKuninori Morimoto 	 *
849e3303268SKuninori Morimoto 	 * It returns *1st* found component, but some driver
850e3303268SKuninori Morimoto 	 * has few components by same of_node/name
851e3303268SKuninori Morimoto 	 * ex)
852e3303268SKuninori Morimoto 	 *	CPU component and generic DMAEngine component
853e3303268SKuninori Morimoto 	 */
854c1e230f0SKuninori Morimoto 	for_each_component(component)
855c1e230f0SKuninori Morimoto 		if (snd_soc_is_matching_component(dlc, component))
856db2a4165SFrank Mandarino 			return component;
857db2a4165SFrank Mandarino 
858db2a4165SFrank Mandarino 	return NULL;
85912023a9aSMisael Lopez Cruz }
86012023a9aSMisael Lopez Cruz 
861fbb88b5cSMengdong Lin /**
862fbb88b5cSMengdong Lin  * snd_soc_find_dai - Find a registered DAI
863fbb88b5cSMengdong Lin  *
8644958471bSJeffy Chen  * @dlc: name of the DAI or the DAI driver and optional component info to match
865fbb88b5cSMengdong Lin  *
866ad61dd30SStephen Boyd  * This function will search all registered components and their DAIs to
867fbb88b5cSMengdong Lin  * find the DAI of the same name. The component's of_node and name
868fbb88b5cSMengdong Lin  * should also match if being specified.
869fbb88b5cSMengdong Lin  *
870fbb88b5cSMengdong Lin  * Return: pointer of DAI, or NULL if not found.
871fbb88b5cSMengdong Lin  */
872305e9020SMengdong Lin struct snd_soc_dai *snd_soc_find_dai(
87314621c7eSLars-Peter Clausen 	const struct snd_soc_dai_link_component *dlc)
87412023a9aSMisael Lopez Cruz {
87514621c7eSLars-Peter Clausen 	struct snd_soc_component *component;
87614621c7eSLars-Peter Clausen 	struct snd_soc_dai *dai;
87712023a9aSMisael Lopez Cruz 
87834e81ab4SLars-Peter Clausen 	lockdep_assert_held(&client_mutex);
87934e81ab4SLars-Peter Clausen 
88014621c7eSLars-Peter Clausen 	/* Find CPU DAI from registered DAIs */
881368dee94SKuninori Morimoto 	for_each_component(component) {
882be6ac0a9SKuninori Morimoto 		if (!snd_soc_is_matching_component(dlc, component))
88312023a9aSMisael Lopez Cruz 			continue;
88415a0c645SKuninori Morimoto 		for_each_component_dais(component, dai) {
8854958471bSJeffy Chen 			if (dlc->dai_name && strcmp(dai->name, dlc->dai_name)
8866a6dafdaSJeffy Chen 			    && (!dai->driver->name
8876a6dafdaSJeffy Chen 				|| strcmp(dai->driver->name, dlc->dai_name)))
88814621c7eSLars-Peter Clausen 				continue;
88912023a9aSMisael Lopez Cruz 
89014621c7eSLars-Peter Clausen 			return dai;
89112023a9aSMisael Lopez Cruz 		}
89212023a9aSMisael Lopez Cruz 	}
89312023a9aSMisael Lopez Cruz 
89412023a9aSMisael Lopez Cruz 	return NULL;
89512023a9aSMisael Lopez Cruz }
896305e9020SMengdong Lin EXPORT_SYMBOL_GPL(snd_soc_find_dai);
89712023a9aSMisael Lopez Cruz 
898bfce78a5SKuninori Morimoto static int soc_dai_link_sanity_check(struct snd_soc_card *card,
89936794902SKuninori Morimoto 				     struct snd_soc_dai_link *link)
90036794902SKuninori Morimoto {
90136794902SKuninori Morimoto 	int i;
90236794902SKuninori Morimoto 	struct snd_soc_dai_link_component *codec, *platform;
90336794902SKuninori Morimoto 
90436794902SKuninori Morimoto 	for_each_link_codecs(link, i, codec) {
90536794902SKuninori Morimoto 		/*
90636794902SKuninori Morimoto 		 * Codec must be specified by 1 of name or OF node,
90736794902SKuninori Morimoto 		 * not both or neither.
90836794902SKuninori Morimoto 		 */
90936794902SKuninori Morimoto 		if (!!codec->name == !!codec->of_node) {
91036794902SKuninori Morimoto 			dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n",
91136794902SKuninori Morimoto 				link->name);
91236794902SKuninori Morimoto 			return -EINVAL;
91336794902SKuninori Morimoto 		}
91436794902SKuninori Morimoto 
91536794902SKuninori Morimoto 		/* Codec DAI name must be specified */
91636794902SKuninori Morimoto 		if (!codec->dai_name) {
91736794902SKuninori Morimoto 			dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n",
91836794902SKuninori Morimoto 				link->name);
91936794902SKuninori Morimoto 			return -EINVAL;
92036794902SKuninori Morimoto 		}
92136794902SKuninori Morimoto 
92236794902SKuninori Morimoto 		/*
92336794902SKuninori Morimoto 		 * Defer card registration if codec component is not added to
92436794902SKuninori Morimoto 		 * component list.
92536794902SKuninori Morimoto 		 */
92636794902SKuninori Morimoto 		if (!soc_find_component(codec))
92736794902SKuninori Morimoto 			return -EPROBE_DEFER;
92836794902SKuninori Morimoto 	}
92936794902SKuninori Morimoto 
93036794902SKuninori Morimoto 	for_each_link_platforms(link, i, platform) {
93136794902SKuninori Morimoto 		/*
93236794902SKuninori Morimoto 		 * Platform may be specified by either name or OF node, but it
93336794902SKuninori Morimoto 		 * can be left unspecified, then no components will be inserted
93436794902SKuninori Morimoto 		 * in the rtdcom list
93536794902SKuninori Morimoto 		 */
93636794902SKuninori Morimoto 		if (!!platform->name == !!platform->of_node) {
93736794902SKuninori Morimoto 			dev_err(card->dev,
93836794902SKuninori Morimoto 				"ASoC: Neither/both platform name/of_node are set for %s\n",
93936794902SKuninori Morimoto 				link->name);
94036794902SKuninori Morimoto 			return -EINVAL;
94136794902SKuninori Morimoto 		}
94236794902SKuninori Morimoto 
94336794902SKuninori Morimoto 		/*
94436794902SKuninori Morimoto 		 * Defer card registration if platform component is not added to
94536794902SKuninori Morimoto 		 * component list.
94636794902SKuninori Morimoto 		 */
94736794902SKuninori Morimoto 		if (!soc_find_component(platform))
94836794902SKuninori Morimoto 			return -EPROBE_DEFER;
94936794902SKuninori Morimoto 	}
95036794902SKuninori Morimoto 
95136794902SKuninori Morimoto 	/* FIXME */
95236794902SKuninori Morimoto 	if (link->num_cpus > 1) {
95336794902SKuninori Morimoto 		dev_err(card->dev,
95436794902SKuninori Morimoto 			"ASoC: multi cpu is not yet supported %s\n",
95536794902SKuninori Morimoto 			link->name);
95636794902SKuninori Morimoto 		return -EINVAL;
95736794902SKuninori Morimoto 	}
95836794902SKuninori Morimoto 
95936794902SKuninori Morimoto 	/*
96036794902SKuninori Morimoto 	 * CPU device may be specified by either name or OF node, but
96136794902SKuninori Morimoto 	 * can be left unspecified, and will be matched based on DAI
96236794902SKuninori Morimoto 	 * name alone..
96336794902SKuninori Morimoto 	 */
96436794902SKuninori Morimoto 	if (link->cpus->name && link->cpus->of_node) {
96536794902SKuninori Morimoto 		dev_err(card->dev,
96636794902SKuninori Morimoto 			"ASoC: Neither/both cpu name/of_node are set for %s\n",
96736794902SKuninori Morimoto 			link->name);
96836794902SKuninori Morimoto 		return -EINVAL;
96936794902SKuninori Morimoto 	}
97036794902SKuninori Morimoto 
97136794902SKuninori Morimoto 	/*
972cd3c5ad7SKuninori Morimoto 	 * Defer card registration if cpu dai component is not added to
97336794902SKuninori Morimoto 	 * component list.
97436794902SKuninori Morimoto 	 */
97536794902SKuninori Morimoto 	if ((link->cpus->of_node || link->cpus->name) &&
97636794902SKuninori Morimoto 	    !soc_find_component(link->cpus))
97736794902SKuninori Morimoto 		return -EPROBE_DEFER;
97836794902SKuninori Morimoto 
97936794902SKuninori Morimoto 	/*
98036794902SKuninori Morimoto 	 * At least one of CPU DAI name or CPU device name/node must be
98136794902SKuninori Morimoto 	 * specified
98236794902SKuninori Morimoto 	 */
98336794902SKuninori Morimoto 	if (!link->cpus->dai_name &&
98436794902SKuninori Morimoto 	    !(link->cpus->name || link->cpus->of_node)) {
98536794902SKuninori Morimoto 		dev_err(card->dev,
98636794902SKuninori Morimoto 			"ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n",
98736794902SKuninori Morimoto 			link->name);
98836794902SKuninori Morimoto 		return -EINVAL;
98936794902SKuninori Morimoto 	}
99036794902SKuninori Morimoto 
99136794902SKuninori Morimoto 	return 0;
99236794902SKuninori Morimoto }
99336794902SKuninori Morimoto 
994da704f26SKuninori Morimoto /**
99550cd9b53SKuninori Morimoto  * snd_soc_remove_pcm_runtime - Remove a pcm_runtime from card
99650cd9b53SKuninori Morimoto  * @card: The ASoC card to which the pcm_runtime has
99750cd9b53SKuninori Morimoto  * @rtd: The pcm_runtime to remove
998da704f26SKuninori Morimoto  *
99950cd9b53SKuninori Morimoto  * This function removes a pcm_runtime from the ASoC card.
1000da704f26SKuninori Morimoto  */
100150cd9b53SKuninori Morimoto void snd_soc_remove_pcm_runtime(struct snd_soc_card *card,
100250cd9b53SKuninori Morimoto 				struct snd_soc_pcm_runtime *rtd)
1003bc7a9091SKuninori Morimoto {
1004da704f26SKuninori Morimoto 	lockdep_assert_held(&client_mutex);
1005da704f26SKuninori Morimoto 
1006da704f26SKuninori Morimoto 	/*
1007da704f26SKuninori Morimoto 	 * Notify the machine driver for extra destruction
1008da704f26SKuninori Morimoto 	 */
1009da704f26SKuninori Morimoto 	if (card->remove_dai_link)
101050cd9b53SKuninori Morimoto 		card->remove_dai_link(card, rtd->dai_link);
1011da704f26SKuninori Morimoto 
1012bc7a9091SKuninori Morimoto 	soc_free_pcm_runtime(rtd);
1013bc7a9091SKuninori Morimoto }
101450cd9b53SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_remove_pcm_runtime);
1015bc7a9091SKuninori Morimoto 
101663dc47daSKuninori Morimoto /**
10170c048004SKuninori Morimoto  * snd_soc_add_pcm_runtime - Add a pcm_runtime dynamically via dai_link
10180c048004SKuninori Morimoto  * @card: The ASoC card to which the pcm_runtime is added
10190c048004SKuninori Morimoto  * @dai_link: The DAI link to find pcm_runtime
102063dc47daSKuninori Morimoto  *
10210c048004SKuninori Morimoto  * This function adds a pcm_runtime ASoC card by using dai_link.
102263dc47daSKuninori Morimoto  *
10230c048004SKuninori Morimoto  * Note: Topology can use this API to add pcm_runtime when probing the
102463dc47daSKuninori Morimoto  * topology component. And machine drivers can still define static
102563dc47daSKuninori Morimoto  * DAI links in dai_link array.
102663dc47daSKuninori Morimoto  */
10270c048004SKuninori Morimoto int snd_soc_add_pcm_runtime(struct snd_soc_card *card,
10286f2f1ff0SMengdong Lin 			    struct snd_soc_dai_link *dai_link)
1029db2a4165SFrank Mandarino {
10301a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
103134614739SJerome Brunet 	struct snd_soc_dai_link_component *codec, *platform;
103290be711eSKuninori Morimoto 	struct snd_soc_component *component;
1033bfce78a5SKuninori Morimoto 	int i, ret;
1034db2a4165SFrank Mandarino 
103563dc47daSKuninori Morimoto 	lockdep_assert_held(&client_mutex);
103663dc47daSKuninori Morimoto 
103763dc47daSKuninori Morimoto 	/*
103863dc47daSKuninori Morimoto 	 * Notify the machine driver for extra initialization
103963dc47daSKuninori Morimoto 	 */
104063dc47daSKuninori Morimoto 	if (card->add_dai_link)
104163dc47daSKuninori Morimoto 		card->add_dai_link(card, dai_link);
104263dc47daSKuninori Morimoto 
1043a655de80SLiam Girdwood 	if (dai_link->ignore)
1044a655de80SLiam Girdwood 		return 0;
1045a655de80SLiam Girdwood 
10466f2f1ff0SMengdong Lin 	dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name);
10476308419aSMark Brown 
1048bfce78a5SKuninori Morimoto 	ret = soc_dai_link_sanity_check(card, dai_link);
1049bfce78a5SKuninori Morimoto 	if (ret < 0)
1050bfce78a5SKuninori Morimoto 		return ret;
1051bfce78a5SKuninori Morimoto 
1052513cb311SSudip Mukherjee 	rtd = soc_new_pcm_runtime(card, dai_link);
1053513cb311SSudip Mukherjee 	if (!rtd)
1054513cb311SSudip Mukherjee 		return -ENOMEM;
1055513cb311SSudip Mukherjee 
105608a5841eSKuninori Morimoto 	/* FIXME: we need multi CPU support in the future */
105708a5841eSKuninori Morimoto 	rtd->cpu_dai = snd_soc_find_dai(dai_link->cpus);
1058b19e6e7bSMark Brown 	if (!rtd->cpu_dai) {
10596b490879SMartin Hundebøll 		dev_info(card->dev, "ASoC: CPU DAI %s not registered\n",
106008a5841eSKuninori Morimoto 			 dai_link->cpus->dai_name);
10611a497983SMengdong Lin 		goto _err_defer;
1062c5af3a2eSMark Brown 	}
106390be711eSKuninori Morimoto 	snd_soc_rtdcom_add(rtd, rtd->cpu_dai->component);
1064c5af3a2eSMark Brown 
106588bd870fSBenoit Cousson 	/* Find CODEC from registered CODECs */
1066e2b30edfSKuninori Morimoto 	rtd->num_codecs = dai_link->num_codecs;
106734614739SJerome Brunet 	for_each_link_codecs(dai_link, i, codec) {
106834614739SJerome Brunet 		rtd->codec_dais[i] = snd_soc_find_dai(codec);
10690a2cfcd9SKuninori Morimoto 		if (!rtd->codec_dais[i]) {
10707c7e2d6aSStefan Agner 			dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n",
107134614739SJerome Brunet 				 codec->dai_name);
10721a497983SMengdong Lin 			goto _err_defer;
107312023a9aSMisael Lopez Cruz 		}
107434614739SJerome Brunet 
10750a2cfcd9SKuninori Morimoto 		snd_soc_rtdcom_add(rtd, rtd->codec_dais[i]->component);
107688bd870fSBenoit Cousson 	}
107788bd870fSBenoit Cousson 
107888bd870fSBenoit Cousson 	/* Single codec links expect codec and codec_dai in runtime data */
10790a2cfcd9SKuninori Morimoto 	rtd->codec_dai = rtd->codec_dais[0];
108012023a9aSMisael Lopez Cruz 
1081e2b30edfSKuninori Morimoto 	/* Find PLATFORM from registered PLATFORMs */
108234614739SJerome Brunet 	for_each_link_platforms(dai_link, i, platform) {
1083368dee94SKuninori Morimoto 		for_each_component(component) {
108434614739SJerome Brunet 			if (!snd_soc_is_matching_component(platform, component))
108590be711eSKuninori Morimoto 				continue;
108690be711eSKuninori Morimoto 
108790be711eSKuninori Morimoto 			snd_soc_rtdcom_add(rtd, component);
108890be711eSKuninori Morimoto 		}
108934614739SJerome Brunet 	}
109090be711eSKuninori Morimoto 
1091b19e6e7bSMark Brown 	return 0;
10921a497983SMengdong Lin 
10931a497983SMengdong Lin _err_defer:
109450cd9b53SKuninori Morimoto 	snd_soc_remove_pcm_runtime(card, rtd);
10951a497983SMengdong Lin 	return -EPROBE_DEFER;
10966b05eda6SMark Brown }
10970c048004SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_add_pcm_runtime);
10986b05eda6SMark Brown 
1099bfa0dd89SKuninori Morimoto static int soc_dai_pcm_new(struct snd_soc_dai **dais, int num_dais,
11009e9c70a5SKuninori Morimoto 			   struct snd_soc_pcm_runtime *rtd)
11019e9c70a5SKuninori Morimoto {
11029e9c70a5SKuninori Morimoto 	int i, ret = 0;
11039e9c70a5SKuninori Morimoto 
11049e9c70a5SKuninori Morimoto 	for (i = 0; i < num_dais; ++i) {
11059e9c70a5SKuninori Morimoto 		struct snd_soc_dai_driver *drv = dais[i]->driver;
11069e9c70a5SKuninori Morimoto 
11079e9c70a5SKuninori Morimoto 		if (drv->pcm_new)
11089e9c70a5SKuninori Morimoto 			ret = drv->pcm_new(rtd, dais[i]);
11099e9c70a5SKuninori Morimoto 		if (ret < 0) {
11109e9c70a5SKuninori Morimoto 			dev_err(dais[i]->dev,
11119e9c70a5SKuninori Morimoto 				"ASoC: Failed to bind %s with pcm device\n",
11129e9c70a5SKuninori Morimoto 				dais[i]->name);
11139e9c70a5SKuninori Morimoto 			return ret;
11149e9c70a5SKuninori Morimoto 		}
11159e9c70a5SKuninori Morimoto 	}
11169e9c70a5SKuninori Morimoto 
11179e9c70a5SKuninori Morimoto 	return 0;
11189e9c70a5SKuninori Morimoto }
11199e9c70a5SKuninori Morimoto 
1120eaffeefbSKuninori Morimoto static int soc_init_pcm_runtime(struct snd_soc_card *card,
112146496acbSKuninori Morimoto 				struct snd_soc_pcm_runtime *rtd)
112246496acbSKuninori Morimoto {
112346496acbSKuninori Morimoto 	struct snd_soc_dai_link *dai_link = rtd->dai_link;
112446496acbSKuninori Morimoto 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
112546496acbSKuninori Morimoto 	struct snd_soc_rtdcom_list *rtdcom;
112646496acbSKuninori Morimoto 	struct snd_soc_component *component;
112746496acbSKuninori Morimoto 	int ret, num;
112846496acbSKuninori Morimoto 
112946496acbSKuninori Morimoto 	/* set default power off timeout */
113046496acbSKuninori Morimoto 	rtd->pmdown_time = pmdown_time;
113146496acbSKuninori Morimoto 
113246496acbSKuninori Morimoto 	/* do machine specific initialization */
113346496acbSKuninori Morimoto 	if (dai_link->init) {
113446496acbSKuninori Morimoto 		ret = dai_link->init(rtd);
113546496acbSKuninori Morimoto 		if (ret < 0) {
113646496acbSKuninori Morimoto 			dev_err(card->dev, "ASoC: failed to init %s: %d\n",
113746496acbSKuninori Morimoto 				dai_link->name, ret);
113846496acbSKuninori Morimoto 			return ret;
113946496acbSKuninori Morimoto 		}
114046496acbSKuninori Morimoto 	}
114146496acbSKuninori Morimoto 
114246496acbSKuninori Morimoto 	if (dai_link->dai_fmt) {
114346496acbSKuninori Morimoto 		ret = snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt);
114446496acbSKuninori Morimoto 		if (ret)
114546496acbSKuninori Morimoto 			return ret;
114646496acbSKuninori Morimoto 	}
114746496acbSKuninori Morimoto 
114846496acbSKuninori Morimoto 	/* add DPCM sysfs entries */
114946496acbSKuninori Morimoto 	soc_dpcm_debugfs_add(rtd);
115046496acbSKuninori Morimoto 
115146496acbSKuninori Morimoto 	num = rtd->num;
115246496acbSKuninori Morimoto 
115346496acbSKuninori Morimoto 	/*
115446496acbSKuninori Morimoto 	 * most drivers will register their PCMs using DAI link ordering but
115546496acbSKuninori Morimoto 	 * topology based drivers can use the DAI link id field to set PCM
115646496acbSKuninori Morimoto 	 * device number and then use rtd + a base offset of the BEs.
115746496acbSKuninori Morimoto 	 */
115846496acbSKuninori Morimoto 	for_each_rtd_components(rtd, rtdcom, component) {
115946496acbSKuninori Morimoto 		if (!component->driver->use_dai_pcm_id)
116046496acbSKuninori Morimoto 			continue;
116146496acbSKuninori Morimoto 
116246496acbSKuninori Morimoto 		if (rtd->dai_link->no_pcm)
116346496acbSKuninori Morimoto 			num += component->driver->be_pcm_base;
116446496acbSKuninori Morimoto 		else
116546496acbSKuninori Morimoto 			num = rtd->dai_link->id;
116646496acbSKuninori Morimoto 	}
116746496acbSKuninori Morimoto 
116846496acbSKuninori Morimoto 	/* create compress_device if possible */
116946496acbSKuninori Morimoto 	ret = snd_soc_dai_compress_new(cpu_dai, rtd, num);
117046496acbSKuninori Morimoto 	if (ret != -ENOTSUPP) {
117146496acbSKuninori Morimoto 		if (ret < 0)
117246496acbSKuninori Morimoto 			dev_err(card->dev, "ASoC: can't create compress %s\n",
117346496acbSKuninori Morimoto 				dai_link->stream_name);
117446496acbSKuninori Morimoto 		return ret;
117546496acbSKuninori Morimoto 	}
117646496acbSKuninori Morimoto 
117746496acbSKuninori Morimoto 	/* create the pcm */
117846496acbSKuninori Morimoto 	ret = soc_new_pcm(rtd, num);
117946496acbSKuninori Morimoto 	if (ret < 0) {
118046496acbSKuninori Morimoto 		dev_err(card->dev, "ASoC: can't create pcm %s :%d\n",
118146496acbSKuninori Morimoto 			dai_link->stream_name, ret);
118246496acbSKuninori Morimoto 		return ret;
118346496acbSKuninori Morimoto 	}
118446496acbSKuninori Morimoto 	ret = soc_dai_pcm_new(&cpu_dai, 1, rtd);
118546496acbSKuninori Morimoto 	if (ret < 0)
118646496acbSKuninori Morimoto 		return ret;
118746496acbSKuninori Morimoto 	ret = soc_dai_pcm_new(rtd->codec_dais,
118846496acbSKuninori Morimoto 			      rtd->num_codecs, rtd);
118946496acbSKuninori Morimoto 	return ret;
119046496acbSKuninori Morimoto }
119146496acbSKuninori Morimoto 
1192ffd60fbaSKuninori Morimoto static void soc_set_name_prefix(struct snd_soc_card *card,
1193ffd60fbaSKuninori Morimoto 				struct snd_soc_component *component)
1194ffd60fbaSKuninori Morimoto {
1195aec3ff99SKuninori Morimoto 	struct device_node *of_node = soc_component_to_node(component);
119629d9fc7aSKuninori Morimoto 	const char *str;
119729d9fc7aSKuninori Morimoto 	int ret, i;
1198ffd60fbaSKuninori Morimoto 
11994702f991SKuninori Morimoto 	for (i = 0; i < card->num_configs; i++) {
1200ffd60fbaSKuninori Morimoto 		struct snd_soc_codec_conf *map = &card->codec_conf[i];
1201ffd60fbaSKuninori Morimoto 
1202ffd60fbaSKuninori Morimoto 		if (map->of_node && of_node != map->of_node)
1203ffd60fbaSKuninori Morimoto 			continue;
1204ffd60fbaSKuninori Morimoto 		if (map->dev_name && strcmp(component->name, map->dev_name))
1205ffd60fbaSKuninori Morimoto 			continue;
1206ffd60fbaSKuninori Morimoto 		component->name_prefix = map->name_prefix;
1207ffd60fbaSKuninori Morimoto 		return;
1208ffd60fbaSKuninori Morimoto 	}
1209ffd60fbaSKuninori Morimoto 
1210ffd60fbaSKuninori Morimoto 	/*
1211ffd60fbaSKuninori Morimoto 	 * If there is no configuration table or no match in the table,
1212ffd60fbaSKuninori Morimoto 	 * check if a prefix is provided in the node
1213ffd60fbaSKuninori Morimoto 	 */
121429d9fc7aSKuninori Morimoto 	ret = of_property_read_string(of_node, "sound-name-prefix", &str);
121529d9fc7aSKuninori Morimoto 	if (ret < 0)
121629d9fc7aSKuninori Morimoto 		return;
121729d9fc7aSKuninori Morimoto 
121829d9fc7aSKuninori Morimoto 	component->name_prefix = str;
1219ffd60fbaSKuninori Morimoto }
1220ffd60fbaSKuninori Morimoto 
1221c6619b72SKuninori Morimoto static void soc_remove_component(struct snd_soc_component *component,
1222c6619b72SKuninori Morimoto 				 int probed)
122322d14231SKuninori Morimoto {
1224c6619b72SKuninori Morimoto 
1225c6619b72SKuninori Morimoto 	if (!component->card)
1226c6619b72SKuninori Morimoto 		return;
1227c6619b72SKuninori Morimoto 
1228c6619b72SKuninori Morimoto 	if (probed)
1229c6619b72SKuninori Morimoto 		snd_soc_component_remove(component);
1230c6619b72SKuninori Morimoto 
123104f770d9SKuninori Morimoto 	/* For framework level robustness */
12323bb936f5SAmadeusz Sławiński 	snd_soc_component_set_jack(component, NULL, NULL);
123304f770d9SKuninori Morimoto 
12347a5d9815SBard liao 	list_del_init(&component->card_list);
123522d14231SKuninori Morimoto 	snd_soc_dapm_free(snd_soc_component_get_dapm(component));
123622d14231SKuninori Morimoto 	soc_cleanup_component_debugfs(component);
123722d14231SKuninori Morimoto 	component->card = NULL;
12380e36f36bSPierre-Louis Bossart 	snd_soc_component_module_put_when_remove(component);
123922d14231SKuninori Morimoto }
124022d14231SKuninori Morimoto 
1241ffd60fbaSKuninori Morimoto static int soc_probe_component(struct snd_soc_card *card,
1242ffd60fbaSKuninori Morimoto 			       struct snd_soc_component *component)
1243ffd60fbaSKuninori Morimoto {
1244ffd60fbaSKuninori Morimoto 	struct snd_soc_dapm_context *dapm =
1245ffd60fbaSKuninori Morimoto 		snd_soc_component_get_dapm(component);
1246ffd60fbaSKuninori Morimoto 	struct snd_soc_dai *dai;
1247c6619b72SKuninori Morimoto 	int probed = 0;
1248ffd60fbaSKuninori Morimoto 	int ret;
1249ffd60fbaSKuninori Morimoto 
1250ffd60fbaSKuninori Morimoto 	if (!strcmp(component->name, "snd-soc-dummy"))
1251ffd60fbaSKuninori Morimoto 		return 0;
1252ffd60fbaSKuninori Morimoto 
1253ffd60fbaSKuninori Morimoto 	if (component->card) {
1254ffd60fbaSKuninori Morimoto 		if (component->card != card) {
1255ffd60fbaSKuninori Morimoto 			dev_err(component->dev,
1256ffd60fbaSKuninori Morimoto 				"Trying to bind component to card \"%s\" but is already bound to card \"%s\"\n",
1257ffd60fbaSKuninori Morimoto 				card->name, component->card->name);
1258ffd60fbaSKuninori Morimoto 			return -ENODEV;
1259ffd60fbaSKuninori Morimoto 		}
1260ffd60fbaSKuninori Morimoto 		return 0;
1261ffd60fbaSKuninori Morimoto 	}
1262ffd60fbaSKuninori Morimoto 
1263ffd60fbaSKuninori Morimoto 	ret = snd_soc_component_module_get_when_probe(component);
1264ffd60fbaSKuninori Morimoto 	if (ret < 0)
1265ffd60fbaSKuninori Morimoto 		return ret;
1266ffd60fbaSKuninori Morimoto 
1267ffd60fbaSKuninori Morimoto 	component->card = card;
1268ffd60fbaSKuninori Morimoto 	soc_set_name_prefix(card, component);
1269ffd60fbaSKuninori Morimoto 
1270ffd60fbaSKuninori Morimoto 	soc_init_component_debugfs(component);
1271ffd60fbaSKuninori Morimoto 
127295c267ddSKuninori Morimoto 	snd_soc_dapm_init(dapm, card, component);
1273b614beafSKuninori Morimoto 
1274ffd60fbaSKuninori Morimoto 	ret = snd_soc_dapm_new_controls(dapm,
1275ffd60fbaSKuninori Morimoto 					component->driver->dapm_widgets,
1276ffd60fbaSKuninori Morimoto 					component->driver->num_dapm_widgets);
1277ffd60fbaSKuninori Morimoto 
1278ffd60fbaSKuninori Morimoto 	if (ret != 0) {
1279ffd60fbaSKuninori Morimoto 		dev_err(component->dev,
1280ffd60fbaSKuninori Morimoto 			"Failed to create new controls %d\n", ret);
1281ffd60fbaSKuninori Morimoto 		goto err_probe;
1282ffd60fbaSKuninori Morimoto 	}
1283ffd60fbaSKuninori Morimoto 
1284ffd60fbaSKuninori Morimoto 	for_each_component_dais(component, dai) {
1285ffd60fbaSKuninori Morimoto 		ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
1286ffd60fbaSKuninori Morimoto 		if (ret != 0) {
1287ffd60fbaSKuninori Morimoto 			dev_err(component->dev,
1288ffd60fbaSKuninori Morimoto 				"Failed to create DAI widgets %d\n", ret);
1289ffd60fbaSKuninori Morimoto 			goto err_probe;
1290ffd60fbaSKuninori Morimoto 		}
1291ffd60fbaSKuninori Morimoto 	}
1292ffd60fbaSKuninori Morimoto 
1293ffd60fbaSKuninori Morimoto 	ret = snd_soc_component_probe(component);
1294ffd60fbaSKuninori Morimoto 	if (ret < 0) {
1295ffd60fbaSKuninori Morimoto 		dev_err(component->dev,
1296ffd60fbaSKuninori Morimoto 			"ASoC: failed to probe component %d\n", ret);
1297ffd60fbaSKuninori Morimoto 		goto err_probe;
1298ffd60fbaSKuninori Morimoto 	}
1299ffd60fbaSKuninori Morimoto 	WARN(dapm->idle_bias_off &&
1300ffd60fbaSKuninori Morimoto 	     dapm->bias_level != SND_SOC_BIAS_OFF,
1301ffd60fbaSKuninori Morimoto 	     "codec %s can not start from non-off bias with idle_bias_off==1\n",
1302ffd60fbaSKuninori Morimoto 	     component->name);
1303c6619b72SKuninori Morimoto 	probed = 1;
1304ffd60fbaSKuninori Morimoto 
1305ffd60fbaSKuninori Morimoto 	/* machine specific init */
1306ffd60fbaSKuninori Morimoto 	if (component->init) {
1307ffd60fbaSKuninori Morimoto 		ret = component->init(component);
1308ffd60fbaSKuninori Morimoto 		if (ret < 0) {
1309ffd60fbaSKuninori Morimoto 			dev_err(component->dev,
1310ffd60fbaSKuninori Morimoto 				"Failed to do machine specific init %d\n", ret);
1311ffd60fbaSKuninori Morimoto 			goto err_probe;
1312ffd60fbaSKuninori Morimoto 		}
1313ffd60fbaSKuninori Morimoto 	}
1314ffd60fbaSKuninori Morimoto 
1315ffd60fbaSKuninori Morimoto 	ret = snd_soc_add_component_controls(component,
1316ffd60fbaSKuninori Morimoto 					     component->driver->controls,
1317ffd60fbaSKuninori Morimoto 					     component->driver->num_controls);
1318ffd60fbaSKuninori Morimoto 	if (ret < 0)
1319ffd60fbaSKuninori Morimoto 		goto err_probe;
1320ffd60fbaSKuninori Morimoto 
1321ffd60fbaSKuninori Morimoto 	ret = snd_soc_dapm_add_routes(dapm,
1322ffd60fbaSKuninori Morimoto 				      component->driver->dapm_routes,
1323ffd60fbaSKuninori Morimoto 				      component->driver->num_dapm_routes);
1324ffd60fbaSKuninori Morimoto 	if (ret < 0)
1325ffd60fbaSKuninori Morimoto 		goto err_probe;
1326ffd60fbaSKuninori Morimoto 
1327ffd60fbaSKuninori Morimoto 	/* see for_each_card_components */
1328ffd60fbaSKuninori Morimoto 	list_add(&component->card_list, &card->component_dev_list);
1329ffd60fbaSKuninori Morimoto 
1330ffd60fbaSKuninori Morimoto err_probe:
1331ffd60fbaSKuninori Morimoto 	if (ret < 0)
1332c6619b72SKuninori Morimoto 		soc_remove_component(component, probed);
1333ffd60fbaSKuninori Morimoto 
1334ffd60fbaSKuninori Morimoto 	return ret;
1335ffd60fbaSKuninori Morimoto }
1336ffd60fbaSKuninori Morimoto 
1337e60cd14fSLars-Peter Clausen static void soc_remove_dai(struct snd_soc_dai *dai, int order)
1338589c3563SJarkko Nikula {
1339589c3563SJarkko Nikula 	int err;
1340589c3563SJarkko Nikula 
134152abe6ccSGuennadi Liakhovetski 	if (!dai || !dai->probed || !dai->driver ||
13422eda3cb1SKuninori Morimoto 	    dai->driver->remove_order != order)
13432eda3cb1SKuninori Morimoto 		return;
13442eda3cb1SKuninori Morimoto 
1345dcdab582SKuninori Morimoto 	err = snd_soc_dai_remove(dai);
1346589c3563SJarkko Nikula 	if (err < 0)
1347e60cd14fSLars-Peter Clausen 		dev_err(dai->dev,
1348b0aa88afSMisael Lopez Cruz 			"ASoC: failed to remove %s: %d\n",
1349e60cd14fSLars-Peter Clausen 			dai->name, err);
1350dcdab582SKuninori Morimoto 
1351e60cd14fSLars-Peter Clausen 	dai->probed = 0;
1352b0aa88afSMisael Lopez Cruz }
1353b0aa88afSMisael Lopez Cruz 
1354a7d44f78SKuninori Morimoto static int soc_probe_dai(struct snd_soc_dai *dai, int order)
1355a7d44f78SKuninori Morimoto {
1356a7d44f78SKuninori Morimoto 	int ret;
1357a7d44f78SKuninori Morimoto 
1358a7d44f78SKuninori Morimoto 	if (dai->probed ||
1359a7d44f78SKuninori Morimoto 	    dai->driver->probe_order != order)
1360a7d44f78SKuninori Morimoto 		return 0;
1361a7d44f78SKuninori Morimoto 
1362a7d44f78SKuninori Morimoto 	ret = snd_soc_dai_probe(dai);
1363a7d44f78SKuninori Morimoto 	if (ret < 0) {
1364a7d44f78SKuninori Morimoto 		dev_err(dai->dev, "ASoC: failed to probe DAI %s: %d\n",
1365a7d44f78SKuninori Morimoto 			dai->name, ret);
1366a7d44f78SKuninori Morimoto 		return ret;
1367a7d44f78SKuninori Morimoto 	}
1368a7d44f78SKuninori Morimoto 
1369a7d44f78SKuninori Morimoto 	dai->probed = 1;
1370a7d44f78SKuninori Morimoto 
1371a7d44f78SKuninori Morimoto 	return 0;
1372a7d44f78SKuninori Morimoto }
1373a7d44f78SKuninori Morimoto 
13744ca47d21SKuninori Morimoto static void soc_remove_link_dais(struct snd_soc_card *card)
1375f0fba2adSLiam Girdwood {
1376e60cd14fSLars-Peter Clausen 	int i;
13770b7990e3SKuninori Morimoto 	struct snd_soc_dai *codec_dai;
13784ca47d21SKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd;
13794ca47d21SKuninori Morimoto 	int order;
13804ca47d21SKuninori Morimoto 
13814ca47d21SKuninori Morimoto 	for_each_comp_order(order) {
13824ca47d21SKuninori Morimoto 		for_each_card_rtds(card, rtd) {
1383f0fba2adSLiam Girdwood 			/* remove the CODEC DAI */
13840b7990e3SKuninori Morimoto 			for_each_rtd_codec_dai(rtd, i, codec_dai)
13850b7990e3SKuninori Morimoto 				soc_remove_dai(codec_dai, order);
1386f0fba2adSLiam Girdwood 
1387e60cd14fSLars-Peter Clausen 			soc_remove_dai(rtd->cpu_dai, order);
1388f0fba2adSLiam Girdwood 		}
13894ca47d21SKuninori Morimoto 	}
13904ca47d21SKuninori Morimoto }
1391f0fba2adSLiam Girdwood 
1392bc7c16c2SKuninori Morimoto static int soc_probe_link_dais(struct snd_soc_card *card)
1393bc7c16c2SKuninori Morimoto {
1394bc7c16c2SKuninori Morimoto 	struct snd_soc_dai *codec_dai;
1395bc7c16c2SKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd;
1396bc7c16c2SKuninori Morimoto 	int i, order, ret;
1397bc7c16c2SKuninori Morimoto 
1398bc7c16c2SKuninori Morimoto 	for_each_comp_order(order) {
1399bc7c16c2SKuninori Morimoto 		for_each_card_rtds(card, rtd) {
1400bc7c16c2SKuninori Morimoto 
1401bc7c16c2SKuninori Morimoto 			dev_dbg(card->dev,
1402bc7c16c2SKuninori Morimoto 				"ASoC: probe %s dai link %d late %d\n",
1403bc7c16c2SKuninori Morimoto 				card->name, rtd->num, order);
1404bc7c16c2SKuninori Morimoto 
1405bc7c16c2SKuninori Morimoto 			ret = soc_probe_dai(rtd->cpu_dai, order);
1406bc7c16c2SKuninori Morimoto 			if (ret)
1407bc7c16c2SKuninori Morimoto 				return ret;
1408bc7c16c2SKuninori Morimoto 
1409bc7c16c2SKuninori Morimoto 			/* probe the CODEC DAI */
1410bc7c16c2SKuninori Morimoto 			for_each_rtd_codec_dai(rtd, i, codec_dai) {
1411bc7c16c2SKuninori Morimoto 				ret = soc_probe_dai(codec_dai, order);
1412bc7c16c2SKuninori Morimoto 				if (ret)
1413bc7c16c2SKuninori Morimoto 					return ret;
1414bc7c16c2SKuninori Morimoto 			}
1415bc7c16c2SKuninori Morimoto 		}
1416bc7c16c2SKuninori Morimoto 	}
1417bc7c16c2SKuninori Morimoto 
1418bc7c16c2SKuninori Morimoto 	return 0;
1419bc7c16c2SKuninori Morimoto }
1420bc7c16c2SKuninori Morimoto 
1421b006c0c6SKuninori Morimoto static void soc_remove_link_components(struct snd_soc_card *card)
142262ae68faSStephen Warren {
142361aca564SLars-Peter Clausen 	struct snd_soc_component *component;
1424b006c0c6SKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd;
142590be711eSKuninori Morimoto 	struct snd_soc_rtdcom_list *rtdcom;
1426b006c0c6SKuninori Morimoto 	int order;
142762ae68faSStephen Warren 
1428b006c0c6SKuninori Morimoto 	for_each_comp_order(order) {
1429b006c0c6SKuninori Morimoto 		for_each_card_rtds(card, rtd) {
14302b544dd7SKuninori Morimoto 			for_each_rtd_components(rtd, rtdcom, component) {
1431b006c0c6SKuninori Morimoto 				if (component->driver->remove_order != order)
1432b006c0c6SKuninori Morimoto 					continue;
1433b006c0c6SKuninori Morimoto 
1434c6619b72SKuninori Morimoto 				soc_remove_component(component, 1);
143562ae68faSStephen Warren 			}
143662ae68faSStephen Warren 		}
1437b006c0c6SKuninori Morimoto 	}
1438b006c0c6SKuninori Morimoto }
143962ae68faSStephen Warren 
144062f07a6bSKuninori Morimoto static int soc_probe_link_components(struct snd_soc_card *card)
14416fb03550SKuninori Morimoto {
14426fb03550SKuninori Morimoto 	struct snd_soc_component *component;
144362f07a6bSKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd;
14446fb03550SKuninori Morimoto 	struct snd_soc_rtdcom_list *rtdcom;
144562f07a6bSKuninori Morimoto 	int ret, order;
14466fb03550SKuninori Morimoto 
144762f07a6bSKuninori Morimoto 	for_each_comp_order(order) {
144862f07a6bSKuninori Morimoto 		for_each_card_rtds(card, rtd) {
14492b544dd7SKuninori Morimoto 			for_each_rtd_components(rtd, rtdcom, component) {
145062f07a6bSKuninori Morimoto 				if (component->driver->probe_order != order)
145162f07a6bSKuninori Morimoto 					continue;
145262f07a6bSKuninori Morimoto 
14536fb03550SKuninori Morimoto 				ret = soc_probe_component(card, component);
14546fb03550SKuninori Morimoto 				if (ret < 0)
14556fb03550SKuninori Morimoto 					return ret;
14566fb03550SKuninori Morimoto 			}
14576fb03550SKuninori Morimoto 		}
145862f07a6bSKuninori Morimoto 	}
14596fb03550SKuninori Morimoto 
14606fb03550SKuninori Morimoto 	return 0;
14616fb03550SKuninori Morimoto }
14626fb03550SKuninori Morimoto 
1463e8fbd250SKuninori Morimoto static void soc_unbind_aux_dev(struct snd_soc_card *card)
14644893a2ebSKuninori Morimoto {
1465e8fbd250SKuninori Morimoto 	struct snd_soc_component *component, *_component;
1466e8fbd250SKuninori Morimoto 
1467e8fbd250SKuninori Morimoto 	for_each_card_auxs_safe(card, component, _component) {
14684893a2ebSKuninori Morimoto 		component->init = NULL;
14694893a2ebSKuninori Morimoto 		list_del(&component->card_aux_list);
14704893a2ebSKuninori Morimoto 	}
1471e8fbd250SKuninori Morimoto }
14724893a2ebSKuninori Morimoto 
1473bee886f1SKuninori Morimoto static int soc_bind_aux_dev(struct snd_soc_card *card)
1474b19e6e7bSMark Brown {
1475f2ed6b07SMengdong Lin 	struct snd_soc_component *component;
1476bee886f1SKuninori Morimoto 	struct snd_soc_aux_dev *aux;
1477bee886f1SKuninori Morimoto 	int i;
14783ca041edSSebastian Reichel 
1479bee886f1SKuninori Morimoto 	for_each_card_pre_auxs(card, i, aux) {
1480f2ed6b07SMengdong Lin 		/* codecs, usually analog devices */
1481bee886f1SKuninori Morimoto 		component = soc_find_component(&aux->dlc);
1482f2ed6b07SMengdong Lin 		if (!component)
14833dc29b8bSKuninori Morimoto 			return -EPROBE_DEFER;
14843ca041edSSebastian Reichel 
1485bee886f1SKuninori Morimoto 		component->init = aux->init;
1486c2b71c71SKuninori Morimoto 		/* see for_each_card_auxs */
1487d2e3a135SSylwester Nawrocki 		list_add(&component->card_aux_list, &card->aux_comp_list);
1488bee886f1SKuninori Morimoto 	}
1489f2ed6b07SMengdong Lin 	return 0;
1490b19e6e7bSMark Brown }
1491b19e6e7bSMark Brown 
1492f2ed6b07SMengdong Lin static int soc_probe_aux_devices(struct snd_soc_card *card)
1493f2ed6b07SMengdong Lin {
149474bd3f92SKuninori Morimoto 	struct snd_soc_component *component;
1495f2ed6b07SMengdong Lin 	int order;
1496f2ed6b07SMengdong Lin 	int ret;
1497f2ed6b07SMengdong Lin 
14981a1035a9SKuninori Morimoto 	for_each_comp_order(order) {
149974bd3f92SKuninori Morimoto 		for_each_card_auxs(card, component) {
150074bd3f92SKuninori Morimoto 			if (component->driver->probe_order != order)
150174bd3f92SKuninori Morimoto 				continue;
150274bd3f92SKuninori Morimoto 
150374bd3f92SKuninori Morimoto 			ret = soc_probe_component(card,	component);
150474bd3f92SKuninori Morimoto 			if (ret < 0)
1505f2ed6b07SMengdong Lin 				return ret;
1506f2ed6b07SMengdong Lin 		}
1507f2ed6b07SMengdong Lin 	}
150865d9361fSLars-Peter Clausen 
150944c69bb1SLars-Peter Clausen 	return 0;
15103ca041edSSebastian Reichel }
15112eea392dSJarkko Nikula 
1512f2ed6b07SMengdong Lin static void soc_remove_aux_devices(struct snd_soc_card *card)
151344c69bb1SLars-Peter Clausen {
1514f2ed6b07SMengdong Lin 	struct snd_soc_component *comp, *_comp;
1515f2ed6b07SMengdong Lin 	int order;
151644c69bb1SLars-Peter Clausen 
15171a1035a9SKuninori Morimoto 	for_each_comp_order(order) {
1518c2b71c71SKuninori Morimoto 		for_each_card_auxs_safe(card, comp, _comp) {
1519e8fbd250SKuninori Morimoto 			if (comp->driver->remove_order == order)
1520c6619b72SKuninori Morimoto 				soc_remove_component(comp, 1);
15215f3484acSLars-Peter Clausen 		}
15222eea392dSJarkko Nikula 	}
15232eea392dSJarkko Nikula }
15242eea392dSJarkko Nikula 
1525ce64c8b9SLars-Peter Clausen /**
1526ce64c8b9SLars-Peter Clausen  * snd_soc_runtime_set_dai_fmt() - Change DAI link format for a ASoC runtime
1527ce64c8b9SLars-Peter Clausen  * @rtd: The runtime for which the DAI link format should be changed
1528ce64c8b9SLars-Peter Clausen  * @dai_fmt: The new DAI link format
1529ce64c8b9SLars-Peter Clausen  *
1530ce64c8b9SLars-Peter Clausen  * This function updates the DAI link format for all DAIs connected to the DAI
1531ce64c8b9SLars-Peter Clausen  * link for the specified runtime.
1532ce64c8b9SLars-Peter Clausen  *
1533ce64c8b9SLars-Peter Clausen  * Note: For setups with a static format set the dai_fmt field in the
1534ce64c8b9SLars-Peter Clausen  * corresponding snd_dai_link struct instead of using this function.
1535ce64c8b9SLars-Peter Clausen  *
1536ce64c8b9SLars-Peter Clausen  * Returns 0 on success, otherwise a negative error code.
1537ce64c8b9SLars-Peter Clausen  */
1538ce64c8b9SLars-Peter Clausen int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
1539ce64c8b9SLars-Peter Clausen 	unsigned int dai_fmt)
1540ce64c8b9SLars-Peter Clausen {
1541ce64c8b9SLars-Peter Clausen 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
15420b7990e3SKuninori Morimoto 	struct snd_soc_dai *codec_dai;
1543ce64c8b9SLars-Peter Clausen 	unsigned int i;
1544ce64c8b9SLars-Peter Clausen 	int ret;
1545ce64c8b9SLars-Peter Clausen 
15460b7990e3SKuninori Morimoto 	for_each_rtd_codec_dai(rtd, i, codec_dai) {
1547ce64c8b9SLars-Peter Clausen 		ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
1548ce64c8b9SLars-Peter Clausen 		if (ret != 0 && ret != -ENOTSUPP) {
1549ce64c8b9SLars-Peter Clausen 			dev_warn(codec_dai->dev,
1550ce64c8b9SLars-Peter Clausen 				 "ASoC: Failed to set DAI format: %d\n", ret);
1551ce64c8b9SLars-Peter Clausen 			return ret;
1552ce64c8b9SLars-Peter Clausen 		}
1553ce64c8b9SLars-Peter Clausen 	}
1554ce64c8b9SLars-Peter Clausen 
15552c7b696aSMarcel Ziswiler 	/*
15562c7b696aSMarcel Ziswiler 	 * Flip the polarity for the "CPU" end of a CODEC<->CODEC link
15572c7b696aSMarcel Ziswiler 	 * the component which has non_legacy_dai_naming is Codec
15582c7b696aSMarcel Ziswiler 	 */
1559999f7f5aSKuninori Morimoto 	if (cpu_dai->component->driver->non_legacy_dai_naming) {
1560ce64c8b9SLars-Peter Clausen 		unsigned int inv_dai_fmt;
1561ce64c8b9SLars-Peter Clausen 
1562ce64c8b9SLars-Peter Clausen 		inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_MASTER_MASK;
1563ce64c8b9SLars-Peter Clausen 		switch (dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1564ce64c8b9SLars-Peter Clausen 		case SND_SOC_DAIFMT_CBM_CFM:
1565ce64c8b9SLars-Peter Clausen 			inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
1566ce64c8b9SLars-Peter Clausen 			break;
1567ce64c8b9SLars-Peter Clausen 		case SND_SOC_DAIFMT_CBM_CFS:
1568ce64c8b9SLars-Peter Clausen 			inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFM;
1569ce64c8b9SLars-Peter Clausen 			break;
1570ce64c8b9SLars-Peter Clausen 		case SND_SOC_DAIFMT_CBS_CFM:
1571ce64c8b9SLars-Peter Clausen 			inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFS;
1572ce64c8b9SLars-Peter Clausen 			break;
1573ce64c8b9SLars-Peter Clausen 		case SND_SOC_DAIFMT_CBS_CFS:
1574ce64c8b9SLars-Peter Clausen 			inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
1575ce64c8b9SLars-Peter Clausen 			break;
1576ce64c8b9SLars-Peter Clausen 		}
1577ce64c8b9SLars-Peter Clausen 
1578ce64c8b9SLars-Peter Clausen 		dai_fmt = inv_dai_fmt;
1579ce64c8b9SLars-Peter Clausen 	}
1580ce64c8b9SLars-Peter Clausen 
1581ce64c8b9SLars-Peter Clausen 	ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
1582ce64c8b9SLars-Peter Clausen 	if (ret != 0 && ret != -ENOTSUPP) {
1583ce64c8b9SLars-Peter Clausen 		dev_warn(cpu_dai->dev,
1584ce64c8b9SLars-Peter Clausen 			 "ASoC: Failed to set DAI format: %d\n", ret);
1585ce64c8b9SLars-Peter Clausen 		return ret;
1586ce64c8b9SLars-Peter Clausen 	}
1587ce64c8b9SLars-Peter Clausen 
1588ce64c8b9SLars-Peter Clausen 	return 0;
1589ce64c8b9SLars-Peter Clausen }
1590ddaca25aSLars-Peter Clausen EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt);
1591ce64c8b9SLars-Peter Clausen 
15921f5a4535STakashi Iwai #ifdef CONFIG_DMI
15932c7b696aSMarcel Ziswiler /*
1594*8a6a6a38SKuninori Morimoto  * If a DMI filed contain strings in this blacklist (e.g.
1595*8a6a6a38SKuninori Morimoto  * "Type2 - Board Manufacturer" or "Type1 - TBD by OEM"), it will be taken
1596*8a6a6a38SKuninori Morimoto  * as invalid and dropped when setting the card long name from DMI info.
1597*8a6a6a38SKuninori Morimoto  */
1598*8a6a6a38SKuninori Morimoto static const char * const dmi_blacklist[] = {
1599*8a6a6a38SKuninori Morimoto 	"To be filled by OEM",
1600*8a6a6a38SKuninori Morimoto 	"TBD by OEM",
1601*8a6a6a38SKuninori Morimoto 	"Default String",
1602*8a6a6a38SKuninori Morimoto 	"Board Manufacturer",
1603*8a6a6a38SKuninori Morimoto 	"Board Vendor Name",
1604*8a6a6a38SKuninori Morimoto 	"Board Product Name",
1605*8a6a6a38SKuninori Morimoto 	NULL,	/* terminator */
1606*8a6a6a38SKuninori Morimoto };
1607*8a6a6a38SKuninori Morimoto 
1608*8a6a6a38SKuninori Morimoto /*
16092c7b696aSMarcel Ziswiler  * Trim special characters, and replace '-' with '_' since '-' is used to
1610345233d7SLiam Girdwood  * separate different DMI fields in the card long name. Only number and
1611345233d7SLiam Girdwood  * alphabet characters and a few separator characters are kept.
1612345233d7SLiam Girdwood  */
1613345233d7SLiam Girdwood static void cleanup_dmi_name(char *name)
1614345233d7SLiam Girdwood {
1615345233d7SLiam Girdwood 	int i, j = 0;
1616345233d7SLiam Girdwood 
1617345233d7SLiam Girdwood 	for (i = 0; name[i]; i++) {
1618345233d7SLiam Girdwood 		if (isalnum(name[i]) || (name[i] == '.')
1619345233d7SLiam Girdwood 		    || (name[i] == '_'))
1620345233d7SLiam Girdwood 			name[j++] = name[i];
1621345233d7SLiam Girdwood 		else if (name[i] == '-')
1622345233d7SLiam Girdwood 			name[j++] = '_';
1623345233d7SLiam Girdwood 	}
1624345233d7SLiam Girdwood 
1625345233d7SLiam Girdwood 	name[j] = '\0';
1626345233d7SLiam Girdwood }
1627345233d7SLiam Girdwood 
16282c7b696aSMarcel Ziswiler /*
16292c7b696aSMarcel Ziswiler  * Check if a DMI field is valid, i.e. not containing any string
163098faf436SMengdong Lin  * in the black list.
163198faf436SMengdong Lin  */
163298faf436SMengdong Lin static int is_dmi_valid(const char *field)
163398faf436SMengdong Lin {
163498faf436SMengdong Lin 	int i = 0;
163598faf436SMengdong Lin 
163698faf436SMengdong Lin 	while (dmi_blacklist[i]) {
163798faf436SMengdong Lin 		if (strstr(field, dmi_blacklist[i]))
163898faf436SMengdong Lin 			return 0;
163998faf436SMengdong Lin 		i++;
164046b5a4d2SWu Fengguang 	}
164198faf436SMengdong Lin 
164298faf436SMengdong Lin 	return 1;
164398faf436SMengdong Lin }
164498faf436SMengdong Lin 
16454e01e5dbSJaroslav Kysela /*
16464e01e5dbSJaroslav Kysela  * Append a string to card->dmi_longname with character cleanups.
16474e01e5dbSJaroslav Kysela  */
16484e01e5dbSJaroslav Kysela static void append_dmi_string(struct snd_soc_card *card, const char *str)
16494e01e5dbSJaroslav Kysela {
16504e01e5dbSJaroslav Kysela 	char *dst = card->dmi_longname;
16514e01e5dbSJaroslav Kysela 	size_t dst_len = sizeof(card->dmi_longname);
16524e01e5dbSJaroslav Kysela 	size_t len;
16534e01e5dbSJaroslav Kysela 
16544e01e5dbSJaroslav Kysela 	len = strlen(dst);
16554e01e5dbSJaroslav Kysela 	snprintf(dst + len, dst_len - len, "-%s", str);
16564e01e5dbSJaroslav Kysela 
16574e01e5dbSJaroslav Kysela 	len++;	/* skip the separator "-" */
16584e01e5dbSJaroslav Kysela 	if (len < dst_len)
16594e01e5dbSJaroslav Kysela 		cleanup_dmi_name(dst + len);
16604e01e5dbSJaroslav Kysela }
16614e01e5dbSJaroslav Kysela 
1662345233d7SLiam Girdwood /**
1663345233d7SLiam Girdwood  * snd_soc_set_dmi_name() - Register DMI names to card
1664345233d7SLiam Girdwood  * @card: The card to register DMI names
1665345233d7SLiam Girdwood  * @flavour: The flavour "differentiator" for the card amongst its peers.
1666345233d7SLiam Girdwood  *
1667345233d7SLiam Girdwood  * An Intel machine driver may be used by many different devices but are
1668345233d7SLiam Girdwood  * difficult for userspace to differentiate, since machine drivers ususally
1669345233d7SLiam Girdwood  * use their own name as the card short name and leave the card long name
1670345233d7SLiam Girdwood  * blank. To differentiate such devices and fix bugs due to lack of
1671345233d7SLiam Girdwood  * device-specific configurations, this function allows DMI info to be used
1672345233d7SLiam Girdwood  * as the sound card long name, in the format of
1673345233d7SLiam Girdwood  * "vendor-product-version-board"
1674345233d7SLiam Girdwood  * (Character '-' is used to separate different DMI fields here).
1675345233d7SLiam Girdwood  * This will help the user space to load the device-specific Use Case Manager
1676345233d7SLiam Girdwood  * (UCM) configurations for the card.
1677345233d7SLiam Girdwood  *
1678345233d7SLiam Girdwood  * Possible card long names may be:
1679345233d7SLiam Girdwood  * DellInc.-XPS139343-01-0310JH
1680345233d7SLiam Girdwood  * ASUSTeKCOMPUTERINC.-T100TA-1.0-T100TA
1681345233d7SLiam Girdwood  * Circuitco-MinnowboardMaxD0PLATFORM-D0-MinnowBoardMAX
1682345233d7SLiam Girdwood  *
1683345233d7SLiam Girdwood  * This function also supports flavoring the card longname to provide
1684345233d7SLiam Girdwood  * the extra differentiation, like "vendor-product-version-board-flavor".
1685345233d7SLiam Girdwood  *
1686345233d7SLiam Girdwood  * We only keep number and alphabet characters and a few separator characters
1687345233d7SLiam Girdwood  * in the card long name since UCM in the user space uses the card long names
1688345233d7SLiam Girdwood  * as card configuration directory names and AudoConf cannot support special
1689345233d7SLiam Girdwood  * charactors like SPACE.
1690345233d7SLiam Girdwood  *
1691345233d7SLiam Girdwood  * Returns 0 on success, otherwise a negative error code.
1692345233d7SLiam Girdwood  */
1693345233d7SLiam Girdwood int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour)
1694345233d7SLiam Girdwood {
1695345233d7SLiam Girdwood 	const char *vendor, *product, *product_version, *board;
1696345233d7SLiam Girdwood 
1697345233d7SLiam Girdwood 	if (card->long_name)
1698345233d7SLiam Girdwood 		return 0; /* long name already set by driver or from DMI */
1699345233d7SLiam Girdwood 
17004e01e5dbSJaroslav Kysela 	/* make up dmi long name as: vendor-product-version-board */
1701345233d7SLiam Girdwood 	vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
170298faf436SMengdong Lin 	if (!vendor || !is_dmi_valid(vendor)) {
1703345233d7SLiam Girdwood 		dev_warn(card->dev, "ASoC: no DMI vendor name!\n");
1704345233d7SLiam Girdwood 		return 0;
1705345233d7SLiam Girdwood 	}
1706345233d7SLiam Girdwood 
17074e01e5dbSJaroslav Kysela 	snprintf(card->dmi_longname, sizeof(card->dmi_longname), "%s", vendor);
1708345233d7SLiam Girdwood 	cleanup_dmi_name(card->dmi_longname);
1709345233d7SLiam Girdwood 
1710345233d7SLiam Girdwood 	product = dmi_get_system_info(DMI_PRODUCT_NAME);
171198faf436SMengdong Lin 	if (product && is_dmi_valid(product)) {
17124e01e5dbSJaroslav Kysela 		append_dmi_string(card, product);
1713345233d7SLiam Girdwood 
17142c7b696aSMarcel Ziswiler 		/*
17152c7b696aSMarcel Ziswiler 		 * some vendors like Lenovo may only put a self-explanatory
1716345233d7SLiam Girdwood 		 * name in the product version field
1717345233d7SLiam Girdwood 		 */
1718345233d7SLiam Girdwood 		product_version = dmi_get_system_info(DMI_PRODUCT_VERSION);
17194e01e5dbSJaroslav Kysela 		if (product_version && is_dmi_valid(product_version))
17204e01e5dbSJaroslav Kysela 			append_dmi_string(card, product_version);
1721345233d7SLiam Girdwood 	}
1722345233d7SLiam Girdwood 
1723345233d7SLiam Girdwood 	board = dmi_get_system_info(DMI_BOARD_NAME);
172498faf436SMengdong Lin 	if (board && is_dmi_valid(board)) {
172539870b0dSJaroslav Kysela 		if (!product || strcasecmp(board, product))
17264e01e5dbSJaroslav Kysela 			append_dmi_string(card, board);
1727345233d7SLiam Girdwood 	} else if (!product) {
1728345233d7SLiam Girdwood 		/* fall back to using legacy name */
1729345233d7SLiam Girdwood 		dev_warn(card->dev, "ASoC: no DMI board/product name!\n");
1730345233d7SLiam Girdwood 		return 0;
1731345233d7SLiam Girdwood 	}
1732345233d7SLiam Girdwood 
1733345233d7SLiam Girdwood 	/* Add flavour to dmi long name */
17344e01e5dbSJaroslav Kysela 	if (flavour)
17354e01e5dbSJaroslav Kysela 		append_dmi_string(card, flavour);
1736345233d7SLiam Girdwood 
1737345233d7SLiam Girdwood 	/* set the card long name */
1738345233d7SLiam Girdwood 	card->long_name = card->dmi_longname;
1739345233d7SLiam Girdwood 
1740345233d7SLiam Girdwood 	return 0;
1741345233d7SLiam Girdwood }
1742345233d7SLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_set_dmi_name);
17431f5a4535STakashi Iwai #endif /* CONFIG_DMI */
1744345233d7SLiam Girdwood 
1745a655de80SLiam Girdwood static void soc_check_tplg_fes(struct snd_soc_card *card)
1746a655de80SLiam Girdwood {
1747a655de80SLiam Girdwood 	struct snd_soc_component *component;
1748a655de80SLiam Girdwood 	const struct snd_soc_component_driver *comp_drv;
1749a655de80SLiam Girdwood 	struct snd_soc_dai_link *dai_link;
1750a655de80SLiam Girdwood 	int i;
1751a655de80SLiam Girdwood 
1752368dee94SKuninori Morimoto 	for_each_component(component) {
1753a655de80SLiam Girdwood 
175449f9c4f2SDaniel Baluta 		/* does this component override BEs ? */
1755a655de80SLiam Girdwood 		if (!component->driver->ignore_machine)
1756a655de80SLiam Girdwood 			continue;
1757a655de80SLiam Girdwood 
1758a655de80SLiam Girdwood 		/* for this machine ? */
1759e194098bSPierre-Louis Bossart 		if (!strcmp(component->driver->ignore_machine,
1760a655de80SLiam Girdwood 			    card->dev->driver->name))
1761e194098bSPierre-Louis Bossart 			goto match;
1762e194098bSPierre-Louis Bossart 		if (strcmp(component->driver->ignore_machine,
1763e194098bSPierre-Louis Bossart 			   dev_name(card->dev)))
1764a655de80SLiam Girdwood 			continue;
1765e194098bSPierre-Louis Bossart match:
1766a655de80SLiam Girdwood 		/* machine matches, so override the rtd data */
17677fe072b4SKuninori Morimoto 		for_each_card_prelinks(card, i, dai_link) {
1768a655de80SLiam Girdwood 
1769a655de80SLiam Girdwood 			/* ignore this FE */
1770a655de80SLiam Girdwood 			if (dai_link->dynamic) {
1771a655de80SLiam Girdwood 				dai_link->ignore = true;
1772a655de80SLiam Girdwood 				continue;
1773a655de80SLiam Girdwood 			}
1774a655de80SLiam Girdwood 
177549f9c4f2SDaniel Baluta 			dev_info(card->dev, "info: override BE DAI link %s\n",
1776a655de80SLiam Girdwood 				 card->dai_link[i].name);
1777a655de80SLiam Girdwood 
1778a655de80SLiam Girdwood 			/* override platform component */
1779adb76b5bSKuninori Morimoto 			if (!dai_link->platforms) {
1780daecf46eSKuninori Morimoto 				dev_err(card->dev, "init platform error");
1781daecf46eSKuninori Morimoto 				continue;
1782daecf46eSKuninori Morimoto 			}
1783910fdcabSKuninori Morimoto 			dai_link->platforms->name = component->name;
1784a655de80SLiam Girdwood 
1785a655de80SLiam Girdwood 			/* convert non BE into BE */
1786a655de80SLiam Girdwood 			dai_link->no_pcm = 1;
1787a655de80SLiam Girdwood 
1788a655de80SLiam Girdwood 			/* override any BE fixups */
1789a655de80SLiam Girdwood 			dai_link->be_hw_params_fixup =
1790a655de80SLiam Girdwood 				component->driver->be_hw_params_fixup;
1791a655de80SLiam Girdwood 
17922c7b696aSMarcel Ziswiler 			/*
17932c7b696aSMarcel Ziswiler 			 * most BE links don't set stream name, so set it to
1794a655de80SLiam Girdwood 			 * dai link name if it's NULL to help bind widgets.
1795a655de80SLiam Girdwood 			 */
1796a655de80SLiam Girdwood 			if (!dai_link->stream_name)
1797a655de80SLiam Girdwood 				dai_link->stream_name = dai_link->name;
1798a655de80SLiam Girdwood 		}
1799a655de80SLiam Girdwood 
1800a655de80SLiam Girdwood 		/* Inform userspace we are using alternate topology */
1801a655de80SLiam Girdwood 		if (component->driver->topology_name_prefix) {
1802a655de80SLiam Girdwood 
1803a655de80SLiam Girdwood 			/* topology shortname created? */
1804a655de80SLiam Girdwood 			if (!card->topology_shortname_created) {
1805a655de80SLiam Girdwood 				comp_drv = component->driver;
1806a655de80SLiam Girdwood 
1807a655de80SLiam Girdwood 				snprintf(card->topology_shortname, 32, "%s-%s",
1808a655de80SLiam Girdwood 					 comp_drv->topology_name_prefix,
1809a655de80SLiam Girdwood 					 card->name);
1810a655de80SLiam Girdwood 				card->topology_shortname_created = true;
1811a655de80SLiam Girdwood 			}
1812a655de80SLiam Girdwood 
1813a655de80SLiam Girdwood 			/* use topology shortname */
1814a655de80SLiam Girdwood 			card->name = card->topology_shortname;
1815a655de80SLiam Girdwood 		}
1816a655de80SLiam Girdwood 	}
1817a655de80SLiam Girdwood }
1818a655de80SLiam Girdwood 
18190f23f718SKuninori Morimoto #define soc_setup_card_name(name, name1, name2, norm)		\
18200f23f718SKuninori Morimoto 	__soc_setup_card_name(name, sizeof(name), name1, name2, norm)
18210f23f718SKuninori Morimoto static void __soc_setup_card_name(char *name, int len,
18220f23f718SKuninori Morimoto 				  const char *name1, const char *name2,
18230f23f718SKuninori Morimoto 				  int normalization)
18240f23f718SKuninori Morimoto {
18250f23f718SKuninori Morimoto 	int i;
18260f23f718SKuninori Morimoto 
18270f23f718SKuninori Morimoto 	snprintf(name, len, "%s", name1 ? name1 : name2);
18280f23f718SKuninori Morimoto 
18290f23f718SKuninori Morimoto 	if (!normalization)
18300f23f718SKuninori Morimoto 		return;
18310f23f718SKuninori Morimoto 
18320f23f718SKuninori Morimoto 	/*
18330f23f718SKuninori Morimoto 	 * Name normalization
18340f23f718SKuninori Morimoto 	 *
18350f23f718SKuninori Morimoto 	 * The driver name is somewhat special, as it's used as a key for
18360f23f718SKuninori Morimoto 	 * searches in the user-space.
18370f23f718SKuninori Morimoto 	 *
18380f23f718SKuninori Morimoto 	 * ex)
18390f23f718SKuninori Morimoto 	 *	"abcd??efg" -> "abcd__efg"
18400f23f718SKuninori Morimoto 	 */
18410f23f718SKuninori Morimoto 	for (i = 0; i < len; i++) {
18420f23f718SKuninori Morimoto 		switch (name[i]) {
18430f23f718SKuninori Morimoto 		case '_':
18440f23f718SKuninori Morimoto 		case '-':
18450f23f718SKuninori Morimoto 		case '\0':
18460f23f718SKuninori Morimoto 			break;
18470f23f718SKuninori Morimoto 		default:
18480f23f718SKuninori Morimoto 			if (!isalnum(name[i]))
18490f23f718SKuninori Morimoto 				name[i] = '_';
18500f23f718SKuninori Morimoto 			break;
18510f23f718SKuninori Morimoto 		}
18520f23f718SKuninori Morimoto 	}
18530f23f718SKuninori Morimoto }
18540f23f718SKuninori Morimoto 
1855ce21401cSKuninori Morimoto static void soc_cleanup_card_resources(struct snd_soc_card *card,
1856ce21401cSKuninori Morimoto 				       int card_probed)
185753e947a0SKuninori Morimoto {
1858cc733900SKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd, *n;
18597ce6088fSKuninori Morimoto 
18600ced7b05SKuninori Morimoto 	if (card->snd_card)
18610ced7b05SKuninori Morimoto 		snd_card_disconnect_sync(card->snd_card);
186253e947a0SKuninori Morimoto 
18632a6f0892SKuninori Morimoto 	snd_soc_dapm_shutdown(card);
18642a6f0892SKuninori Morimoto 
186553e947a0SKuninori Morimoto 	/* remove and free each DAI */
18667ce6088fSKuninori Morimoto 	soc_remove_link_dais(card);
18670ced7b05SKuninori Morimoto 	soc_remove_link_components(card);
18687ce6088fSKuninori Morimoto 
1869cc733900SKuninori Morimoto 	for_each_card_rtds_safe(card, rtd, n)
187050cd9b53SKuninori Morimoto 		snd_soc_remove_pcm_runtime(card, rtd);
18717ce6088fSKuninori Morimoto 
187253e947a0SKuninori Morimoto 	/* remove auxiliary devices */
187353e947a0SKuninori Morimoto 	soc_remove_aux_devices(card);
1874e8fbd250SKuninori Morimoto 	soc_unbind_aux_dev(card);
187553e947a0SKuninori Morimoto 
187653e947a0SKuninori Morimoto 	snd_soc_dapm_free(&card->dapm);
187753e947a0SKuninori Morimoto 	soc_cleanup_card_debugfs(card);
187853e947a0SKuninori Morimoto 
187953e947a0SKuninori Morimoto 	/* remove the card */
1880ce21401cSKuninori Morimoto 	if (card_probed && card->remove)
188153e947a0SKuninori Morimoto 		card->remove(card);
18820ced7b05SKuninori Morimoto 
18830ced7b05SKuninori Morimoto 	if (card->snd_card) {
18840ced7b05SKuninori Morimoto 		snd_card_free(card->snd_card);
18850ced7b05SKuninori Morimoto 		card->snd_card = NULL;
18860ced7b05SKuninori Morimoto 	}
188753e947a0SKuninori Morimoto }
188853e947a0SKuninori Morimoto 
18892cc1afcfSKuninori Morimoto static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister)
18902cc1afcfSKuninori Morimoto {
18912cc1afcfSKuninori Morimoto 	if (card->instantiated) {
1892ce21401cSKuninori Morimoto 		int card_probed = 1;
1893ce21401cSKuninori Morimoto 
18942cc1afcfSKuninori Morimoto 		card->instantiated = false;
18952cc1afcfSKuninori Morimoto 		snd_soc_flush_all_delayed_work(card);
18962cc1afcfSKuninori Morimoto 
1897ce21401cSKuninori Morimoto 		soc_cleanup_card_resources(card, card_probed);
18982cc1afcfSKuninori Morimoto 		if (!unregister)
18992cc1afcfSKuninori Morimoto 			list_add(&card->list, &unbind_card_list);
19002cc1afcfSKuninori Morimoto 	} else {
19012cc1afcfSKuninori Morimoto 		if (unregister)
19022cc1afcfSKuninori Morimoto 			list_del(&card->list);
19032cc1afcfSKuninori Morimoto 	}
19042cc1afcfSKuninori Morimoto }
19052cc1afcfSKuninori Morimoto 
1906ed90c013SKuninori Morimoto static int snd_soc_bind_card(struct snd_soc_card *card)
1907f0fba2adSLiam Girdwood {
19081a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
190961b0088bSMengdong Lin 	struct snd_soc_dai_link *dai_link;
1910ce21401cSKuninori Morimoto 	int ret, i, card_probed = 0;
191196dd3622SMark Brown 
191234e81ab4SLars-Peter Clausen 	mutex_lock(&client_mutex);
191301b9d99aSLiam Girdwood 	mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
1914f0fba2adSLiam Girdwood 
191595c267ddSKuninori Morimoto 	snd_soc_dapm_init(&card->dapm, card, NULL);
191653e947a0SKuninori Morimoto 
1917a655de80SLiam Girdwood 	/* check whether any platform is ignore machine FE and using topology */
1918a655de80SLiam Girdwood 	soc_check_tplg_fes(card);
1919a655de80SLiam Girdwood 
192044c69bb1SLars-Peter Clausen 	/* bind aux_devs too */
1921bee886f1SKuninori Morimoto 	ret = soc_bind_aux_dev(card);
1922bee886f1SKuninori Morimoto 	if (ret < 0)
192353e947a0SKuninori Morimoto 		goto probe_end;
1924db2a4165SFrank Mandarino 
1925f8f80361SMengdong Lin 	/* add predefined DAI links to the list */
1926d8145989SKuninori Morimoto 	card->num_rtd = 0;
19275b99a0aaSKuninori Morimoto 	for_each_card_prelinks(card, i, dai_link) {
19280c048004SKuninori Morimoto 		ret = snd_soc_add_pcm_runtime(card, dai_link);
19295b99a0aaSKuninori Morimoto 		if (ret < 0)
19305b99a0aaSKuninori Morimoto 			goto probe_end;
19315b99a0aaSKuninori Morimoto 	}
1932f8f80361SMengdong Lin 
1933f0fba2adSLiam Girdwood 	/* card bind complete so register a sound card */
1934102b5a8dSTakashi Iwai 	ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
1935f0fba2adSLiam Girdwood 			card->owner, 0, &card->snd_card);
1936f0fba2adSLiam Girdwood 	if (ret < 0) {
193710e8aa9aSMichał Mirosław 		dev_err(card->dev,
193810e8aa9aSMichał Mirosław 			"ASoC: can't create sound card for card %s: %d\n",
193910e8aa9aSMichał Mirosław 			card->name, ret);
194053e947a0SKuninori Morimoto 		goto probe_end;
1941db2a4165SFrank Mandarino 	}
1942db2a4165SFrank Mandarino 
19430757d834SLars-Peter Clausen 	soc_init_card_debugfs(card);
19440757d834SLars-Peter Clausen 
1945b3da4251SKuninori Morimoto 	soc_resume_init(card);
19466ed25978SAndy Green 
1947b8ba3b57SKuninori Morimoto 	ret = snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
19489a841ebbSMark Brown 					card->num_dapm_widgets);
1949b8ba3b57SKuninori Morimoto 	if (ret < 0)
1950b8ba3b57SKuninori Morimoto 		goto probe_end;
19519a841ebbSMark Brown 
1952b8ba3b57SKuninori Morimoto 	ret = snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets,
1953f23e860eSNicolin Chen 					card->num_of_dapm_widgets);
1954b8ba3b57SKuninori Morimoto 	if (ret < 0)
1955b8ba3b57SKuninori Morimoto 		goto probe_end;
1956f23e860eSNicolin Chen 
1957f0fba2adSLiam Girdwood 	/* initialise the sound card only once */
1958f0fba2adSLiam Girdwood 	if (card->probe) {
1959e7361ec4SMark Brown 		ret = card->probe(card);
1960f0fba2adSLiam Girdwood 		if (ret < 0)
196153e947a0SKuninori Morimoto 			goto probe_end;
1962ce21401cSKuninori Morimoto 		card_probed = 1;
1963f0fba2adSLiam Girdwood 	}
1964f0fba2adSLiam Girdwood 
196562ae68faSStephen Warren 	/* probe all components used by DAI links on this card */
196662f07a6bSKuninori Morimoto 	ret = soc_probe_link_components(card);
196762ae68faSStephen Warren 	if (ret < 0) {
1968f110bfc7SLiam Girdwood 		dev_err(card->dev,
196962f07a6bSKuninori Morimoto 			"ASoC: failed to instantiate card %d\n", ret);
197053e947a0SKuninori Morimoto 		goto probe_end;
197162ae68faSStephen Warren 	}
197262ae68faSStephen Warren 
1973f2ed6b07SMengdong Lin 	/* probe auxiliary components */
1974f2ed6b07SMengdong Lin 	ret = soc_probe_aux_devices(card);
197574bd3f92SKuninori Morimoto 	if (ret < 0) {
197674bd3f92SKuninori Morimoto 		dev_err(card->dev,
197774bd3f92SKuninori Morimoto 			"ASoC: failed to probe aux component %d\n", ret);
197853e947a0SKuninori Morimoto 		goto probe_end;
197974bd3f92SKuninori Morimoto 	}
1980f2ed6b07SMengdong Lin 
198162ae68faSStephen Warren 	/* probe all DAI links on this card */
1982c7e73774SKuninori Morimoto 	ret = soc_probe_link_dais(card);
1983fe3e78e0SMark Brown 	if (ret < 0) {
1984f110bfc7SLiam Girdwood 		dev_err(card->dev,
1985c7e73774SKuninori Morimoto 			"ASoC: failed to instantiate card %d\n", ret);
198653e947a0SKuninori Morimoto 		goto probe_end;
1987fe3e78e0SMark Brown 	}
1988fe3e78e0SMark Brown 
1989626c2e57SKuninori Morimoto 	for_each_card_rtds(card, rtd) {
1990eaffeefbSKuninori Morimoto 		ret = soc_init_pcm_runtime(card, rtd);
1991626c2e57SKuninori Morimoto 		if (ret < 0)
1992626c2e57SKuninori Morimoto 			goto probe_end;
1993626c2e57SKuninori Morimoto 	}
1994c4b46982SKuninori Morimoto 
1995888df395SMark Brown 	snd_soc_dapm_link_dai_widgets(card);
1996b893ea5fSLiam Girdwood 	snd_soc_dapm_connect_dai_link_widgets(card);
1997888df395SMark Brown 
19989b98c7c2SKuninori Morimoto 	ret = snd_soc_add_card_controls(card, card->controls,
19992c7b696aSMarcel Ziswiler 					card->num_controls);
20009b98c7c2SKuninori Morimoto 	if (ret < 0)
20019b98c7c2SKuninori Morimoto 		goto probe_end;
2002b7af1dafSMark Brown 
2003daa480bdSKuninori Morimoto 	ret = snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
2004b8ad29deSMark Brown 				      card->num_dapm_routes);
2005daa480bdSKuninori Morimoto 	if (ret < 0)
2006daa480bdSKuninori Morimoto 		goto probe_end;
2007b8ad29deSMark Brown 
2008daa480bdSKuninori Morimoto 	ret = snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes,
2009f23e860eSNicolin Chen 				      card->num_of_dapm_routes);
2010daa480bdSKuninori Morimoto 	if (ret < 0)
2011daa480bdSKuninori Morimoto 		goto probe_end;
201275d9ac46SMark Brown 
2013861886d3STakashi Iwai 	/* try to set some sane longname if DMI is available */
2014861886d3STakashi Iwai 	snd_soc_set_dmi_name(card, NULL);
2015861886d3STakashi Iwai 
20160f23f718SKuninori Morimoto 	soc_setup_card_name(card->snd_card->shortname,
20170f23f718SKuninori Morimoto 			    card->name, NULL, 0);
20180f23f718SKuninori Morimoto 	soc_setup_card_name(card->snd_card->longname,
20190f23f718SKuninori Morimoto 			    card->long_name, card->name, 0);
20200f23f718SKuninori Morimoto 	soc_setup_card_name(card->snd_card->driver,
20210f23f718SKuninori Morimoto 			    card->driver_name, card->name, 1);
2022fe3e78e0SMark Brown 
2023dc73d73aSJaroslav Kysela 	if (card->components) {
2024dc73d73aSJaroslav Kysela 		/* the current implementation of snd_component_add() accepts */
2025dc73d73aSJaroslav Kysela 		/* multiple components in the string separated by space, */
2026dc73d73aSJaroslav Kysela 		/* but the string collision (identical string) check might */
2027dc73d73aSJaroslav Kysela 		/* not work correctly */
2028dc73d73aSJaroslav Kysela 		ret = snd_component_add(card->snd_card, card->components);
2029dc73d73aSJaroslav Kysela 		if (ret < 0) {
2030dc73d73aSJaroslav Kysela 			dev_err(card->dev, "ASoC: %s snd_component_add() failed: %d\n",
2031dc73d73aSJaroslav Kysela 				card->name, ret);
2032dc73d73aSJaroslav Kysela 			goto probe_end;
2033dc73d73aSJaroslav Kysela 		}
2034dc73d73aSJaroslav Kysela 	}
2035dc73d73aSJaroslav Kysela 
203628e9ad92SMark Brown 	if (card->late_probe) {
203728e9ad92SMark Brown 		ret = card->late_probe(card);
203828e9ad92SMark Brown 		if (ret < 0) {
2039f110bfc7SLiam Girdwood 			dev_err(card->dev, "ASoC: %s late_probe() failed: %d\n",
204028e9ad92SMark Brown 				card->name, ret);
204153e947a0SKuninori Morimoto 			goto probe_end;
204228e9ad92SMark Brown 		}
204328e9ad92SMark Brown 	}
2044ce21401cSKuninori Morimoto 	card_probed = 1;
204528e9ad92SMark Brown 
2046824ef826SLars-Peter Clausen 	snd_soc_dapm_new_widgets(card);
20478c193b8dSLars-Peter Clausen 
2048f0fba2adSLiam Girdwood 	ret = snd_card_register(card->snd_card);
2049fe3e78e0SMark Brown 	if (ret < 0) {
2050f110bfc7SLiam Girdwood 		dev_err(card->dev, "ASoC: failed to register soundcard %d\n",
2051f110bfc7SLiam Girdwood 				ret);
205253e947a0SKuninori Morimoto 		goto probe_end;
2053fe3e78e0SMark Brown 	}
2054fe3e78e0SMark Brown 
2055435c5e25SMark Brown 	card->instantiated = 1;
2056882eab6cSTzung-Bi Shih 	dapm_mark_endpoints_dirty(card);
20574f4c0072SMark Brown 	snd_soc_dapm_sync(&card->dapm);
2058b19e6e7bSMark Brown 
2059ed90c013SKuninori Morimoto 	/* deactivate pins to sleep state */
2060ed90c013SKuninori Morimoto 	for_each_card_rtds(card, rtd) {
2061ed90c013SKuninori Morimoto 		struct snd_soc_dai *dai;
2062ed90c013SKuninori Morimoto 
2063ed90c013SKuninori Morimoto 		for_each_rtd_codec_dai(rtd, i, dai) {
2064ed90c013SKuninori Morimoto 			if (!dai->active)
2065ed90c013SKuninori Morimoto 				pinctrl_pm_select_sleep_state(dai->dev);
2066ed90c013SKuninori Morimoto 		}
2067ed90c013SKuninori Morimoto 
2068ed90c013SKuninori Morimoto 		if (!rtd->cpu_dai->active)
2069ed90c013SKuninori Morimoto 			pinctrl_pm_select_sleep_state(rtd->cpu_dai->dev);
2070ed90c013SKuninori Morimoto 	}
2071ed90c013SKuninori Morimoto 
207253e947a0SKuninori Morimoto probe_end:
207353e947a0SKuninori Morimoto 	if (ret < 0)
2074ce21401cSKuninori Morimoto 		soc_cleanup_card_resources(card, card_probed);
2075db2a4165SFrank Mandarino 
2076f0fba2adSLiam Girdwood 	mutex_unlock(&card->mutex);
207734e81ab4SLars-Peter Clausen 	mutex_unlock(&client_mutex);
2078db2a4165SFrank Mandarino 
2079b19e6e7bSMark Brown 	return ret;
2080435c5e25SMark Brown }
2081435c5e25SMark Brown 
2082435c5e25SMark Brown /* probes a new socdev */
2083435c5e25SMark Brown static int soc_probe(struct platform_device *pdev)
2084435c5e25SMark Brown {
2085f0fba2adSLiam Girdwood 	struct snd_soc_card *card = platform_get_drvdata(pdev);
2086435c5e25SMark Brown 
208770a7ca34SVinod Koul 	/*
208870a7ca34SVinod Koul 	 * no card, so machine driver should be registering card
208970a7ca34SVinod Koul 	 * we should not be here in that case so ret error
209070a7ca34SVinod Koul 	 */
209170a7ca34SVinod Koul 	if (!card)
209270a7ca34SVinod Koul 		return -EINVAL;
209370a7ca34SVinod Koul 
2094fe4085e8SMark Brown 	dev_warn(&pdev->dev,
2095f110bfc7SLiam Girdwood 		 "ASoC: machine %s should use snd_soc_register_card()\n",
2096fe4085e8SMark Brown 		 card->name);
2097fe4085e8SMark Brown 
2098435c5e25SMark Brown 	/* Bodge while we unpick instantiation */
2099435c5e25SMark Brown 	card->dev = &pdev->dev;
2100f0fba2adSLiam Girdwood 
210128d528c8SMark Brown 	return snd_soc_register_card(card);
2102435c5e25SMark Brown }
2103435c5e25SMark Brown 
2104b0e26485SVinod Koul /* removes a socdev */
2105b0e26485SVinod Koul static int soc_remove(struct platform_device *pdev)
2106b0e26485SVinod Koul {
2107b0e26485SVinod Koul 	struct snd_soc_card *card = platform_get_drvdata(pdev);
2108b0e26485SVinod Koul 
2109c5af3a2eSMark Brown 	snd_soc_unregister_card(card);
2110db2a4165SFrank Mandarino 	return 0;
2111db2a4165SFrank Mandarino }
2112db2a4165SFrank Mandarino 
21136f8ab4acSMark Brown int snd_soc_poweroff(struct device *dev)
211451737470SMark Brown {
21156f8ab4acSMark Brown 	struct snd_soc_card *card = dev_get_drvdata(dev);
21161a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
211751737470SMark Brown 
211851737470SMark Brown 	if (!card->instantiated)
2119416356fcSMark Brown 		return 0;
212051737470SMark Brown 
21212c7b696aSMarcel Ziswiler 	/*
21222c7b696aSMarcel Ziswiler 	 * Flush out pmdown_time work - we actually do want to run it
21232c7b696aSMarcel Ziswiler 	 * now, we're shutting down so no imminent restart.
21242c7b696aSMarcel Ziswiler 	 */
212565462e44SKuninori Morimoto 	snd_soc_flush_all_delayed_work(card);
212651737470SMark Brown 
2127f0fba2adSLiam Girdwood 	snd_soc_dapm_shutdown(card);
2128416356fcSMark Brown 
2129988e8cc4SNicolin Chen 	/* deactivate pins to sleep state */
2130bcb1fd1fSKuninori Morimoto 	for_each_card_rtds(card, rtd) {
213188bd870fSBenoit Cousson 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
21320b7990e3SKuninori Morimoto 		struct snd_soc_dai *codec_dai;
21331a497983SMengdong Lin 		int i;
213488bd870fSBenoit Cousson 
2135988e8cc4SNicolin Chen 		pinctrl_pm_select_sleep_state(cpu_dai->dev);
21360b7990e3SKuninori Morimoto 		for_each_rtd_codec_dai(rtd, i, codec_dai) {
213788bd870fSBenoit Cousson 			pinctrl_pm_select_sleep_state(codec_dai->dev);
213888bd870fSBenoit Cousson 		}
2139988e8cc4SNicolin Chen 	}
2140988e8cc4SNicolin Chen 
2141416356fcSMark Brown 	return 0;
214251737470SMark Brown }
21436f8ab4acSMark Brown EXPORT_SYMBOL_GPL(snd_soc_poweroff);
214451737470SMark Brown 
21456f8ab4acSMark Brown const struct dev_pm_ops snd_soc_pm_ops = {
2146b1dd5897SViresh Kumar 	.suspend = snd_soc_suspend,
2147b1dd5897SViresh Kumar 	.resume = snd_soc_resume,
2148b1dd5897SViresh Kumar 	.freeze = snd_soc_suspend,
2149b1dd5897SViresh Kumar 	.thaw = snd_soc_resume,
21506f8ab4acSMark Brown 	.poweroff = snd_soc_poweroff,
2151b1dd5897SViresh Kumar 	.restore = snd_soc_resume,
2152416356fcSMark Brown };
2153deb2607eSStephen Warren EXPORT_SYMBOL_GPL(snd_soc_pm_ops);
2154416356fcSMark Brown 
2155db2a4165SFrank Mandarino /* ASoC platform driver */
2156db2a4165SFrank Mandarino static struct platform_driver soc_driver = {
2157db2a4165SFrank Mandarino 	.driver		= {
2158db2a4165SFrank Mandarino 		.name		= "soc-audio",
21596f8ab4acSMark Brown 		.pm		= &snd_soc_pm_ops,
2160db2a4165SFrank Mandarino 	},
2161db2a4165SFrank Mandarino 	.probe		= soc_probe,
2162db2a4165SFrank Mandarino 	.remove		= soc_remove,
2163db2a4165SFrank Mandarino };
2164db2a4165SFrank Mandarino 
2165096e49d5SMark Brown /**
2166db2a4165SFrank Mandarino  * snd_soc_cnew - create new control
2167db2a4165SFrank Mandarino  * @_template: control template
2168db2a4165SFrank Mandarino  * @data: control private data
2169ac11a2b3SMark Brown  * @long_name: control long name
2170efb7ac3fSMark Brown  * @prefix: control name prefix
2171db2a4165SFrank Mandarino  *
2172db2a4165SFrank Mandarino  * Create a new mixer control from a template control.
2173db2a4165SFrank Mandarino  *
2174db2a4165SFrank Mandarino  * Returns 0 for success, else error.
2175db2a4165SFrank Mandarino  */
2176db2a4165SFrank Mandarino struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
21773056557fSMark Brown 				  void *data, const char *long_name,
2178efb7ac3fSMark Brown 				  const char *prefix)
2179db2a4165SFrank Mandarino {
2180db2a4165SFrank Mandarino 	struct snd_kcontrol_new template;
2181efb7ac3fSMark Brown 	struct snd_kcontrol *kcontrol;
2182efb7ac3fSMark Brown 	char *name = NULL;
2183db2a4165SFrank Mandarino 
2184db2a4165SFrank Mandarino 	memcpy(&template, _template, sizeof(template));
2185db2a4165SFrank Mandarino 	template.index = 0;
2186db2a4165SFrank Mandarino 
2187efb7ac3fSMark Brown 	if (!long_name)
2188efb7ac3fSMark Brown 		long_name = template.name;
2189efb7ac3fSMark Brown 
2190efb7ac3fSMark Brown 	if (prefix) {
21912b581074SLars-Peter Clausen 		name = kasprintf(GFP_KERNEL, "%s %s", prefix, long_name);
2192efb7ac3fSMark Brown 		if (!name)
2193efb7ac3fSMark Brown 			return NULL;
2194efb7ac3fSMark Brown 
2195efb7ac3fSMark Brown 		template.name = name;
2196efb7ac3fSMark Brown 	} else {
2197efb7ac3fSMark Brown 		template.name = long_name;
2198efb7ac3fSMark Brown 	}
2199efb7ac3fSMark Brown 
2200efb7ac3fSMark Brown 	kcontrol = snd_ctl_new1(&template, data);
2201efb7ac3fSMark Brown 
2202efb7ac3fSMark Brown 	kfree(name);
2203efb7ac3fSMark Brown 
2204efb7ac3fSMark Brown 	return kcontrol;
2205db2a4165SFrank Mandarino }
2206db2a4165SFrank Mandarino EXPORT_SYMBOL_GPL(snd_soc_cnew);
2207db2a4165SFrank Mandarino 
2208022658beSLiam Girdwood static int snd_soc_add_controls(struct snd_card *card, struct device *dev,
2209022658beSLiam Girdwood 	const struct snd_kcontrol_new *controls, int num_controls,
2210022658beSLiam Girdwood 	const char *prefix, void *data)
2211022658beSLiam Girdwood {
2212022658beSLiam Girdwood 	int err, i;
2213022658beSLiam Girdwood 
2214022658beSLiam Girdwood 	for (i = 0; i < num_controls; i++) {
2215022658beSLiam Girdwood 		const struct snd_kcontrol_new *control = &controls[i];
22162c7b696aSMarcel Ziswiler 
2217022658beSLiam Girdwood 		err = snd_ctl_add(card, snd_soc_cnew(control, data,
2218022658beSLiam Girdwood 						     control->name, prefix));
2219022658beSLiam Girdwood 		if (err < 0) {
2220f110bfc7SLiam Girdwood 			dev_err(dev, "ASoC: Failed to add %s: %d\n",
2221f110bfc7SLiam Girdwood 				control->name, err);
2222022658beSLiam Girdwood 			return err;
2223022658beSLiam Girdwood 		}
2224022658beSLiam Girdwood 	}
2225022658beSLiam Girdwood 
2226022658beSLiam Girdwood 	return 0;
2227022658beSLiam Girdwood }
2228022658beSLiam Girdwood 
22294fefd698SDimitris Papastamos struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
22304fefd698SDimitris Papastamos 					       const char *name)
22314fefd698SDimitris Papastamos {
22324fefd698SDimitris Papastamos 	struct snd_card *card = soc_card->snd_card;
22334fefd698SDimitris Papastamos 	struct snd_kcontrol *kctl;
22344fefd698SDimitris Papastamos 
22354fefd698SDimitris Papastamos 	if (unlikely(!name))
22364fefd698SDimitris Papastamos 		return NULL;
22374fefd698SDimitris Papastamos 
22384fefd698SDimitris Papastamos 	list_for_each_entry(kctl, &card->controls, list)
22394fefd698SDimitris Papastamos 		if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name)))
22404fefd698SDimitris Papastamos 			return kctl;
22414fefd698SDimitris Papastamos 	return NULL;
22424fefd698SDimitris Papastamos }
22434fefd698SDimitris Papastamos EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol);
22444fefd698SDimitris Papastamos 
2245db2a4165SFrank Mandarino /**
22460f2780adSLars-Peter Clausen  * snd_soc_add_component_controls - Add an array of controls to a component.
22470f2780adSLars-Peter Clausen  *
22480f2780adSLars-Peter Clausen  * @component: Component to add controls to
22490f2780adSLars-Peter Clausen  * @controls: Array of controls to add
22500f2780adSLars-Peter Clausen  * @num_controls: Number of elements in the array
22510f2780adSLars-Peter Clausen  *
22520f2780adSLars-Peter Clausen  * Return: 0 for success, else error.
22530f2780adSLars-Peter Clausen  */
22540f2780adSLars-Peter Clausen int snd_soc_add_component_controls(struct snd_soc_component *component,
22550f2780adSLars-Peter Clausen 	const struct snd_kcontrol_new *controls, unsigned int num_controls)
22560f2780adSLars-Peter Clausen {
22570f2780adSLars-Peter Clausen 	struct snd_card *card = component->card->snd_card;
22580f2780adSLars-Peter Clausen 
22590f2780adSLars-Peter Clausen 	return snd_soc_add_controls(card, component->dev, controls,
22600f2780adSLars-Peter Clausen 			num_controls, component->name_prefix, component);
22610f2780adSLars-Peter Clausen }
22620f2780adSLars-Peter Clausen EXPORT_SYMBOL_GPL(snd_soc_add_component_controls);
22630f2780adSLars-Peter Clausen 
22640f2780adSLars-Peter Clausen /**
2265022658beSLiam Girdwood  * snd_soc_add_card_controls - add an array of controls to a SoC card.
2266022658beSLiam Girdwood  * Convenience function to add a list of controls.
2267022658beSLiam Girdwood  *
2268022658beSLiam Girdwood  * @soc_card: SoC card to add controls to
2269022658beSLiam Girdwood  * @controls: array of controls to add
2270022658beSLiam Girdwood  * @num_controls: number of elements in the array
2271022658beSLiam Girdwood  *
2272022658beSLiam Girdwood  * Return 0 for success, else error.
2273022658beSLiam Girdwood  */
2274022658beSLiam Girdwood int snd_soc_add_card_controls(struct snd_soc_card *soc_card,
2275022658beSLiam Girdwood 	const struct snd_kcontrol_new *controls, int num_controls)
2276022658beSLiam Girdwood {
2277022658beSLiam Girdwood 	struct snd_card *card = soc_card->snd_card;
2278022658beSLiam Girdwood 
2279022658beSLiam Girdwood 	return snd_soc_add_controls(card, soc_card->dev, controls, num_controls,
2280022658beSLiam Girdwood 			NULL, soc_card);
2281022658beSLiam Girdwood }
2282022658beSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_add_card_controls);
2283022658beSLiam Girdwood 
2284022658beSLiam Girdwood /**
2285022658beSLiam Girdwood  * snd_soc_add_dai_controls - add an array of controls to a DAI.
2286022658beSLiam Girdwood  * Convienience function to add a list of controls.
2287022658beSLiam Girdwood  *
2288022658beSLiam Girdwood  * @dai: DAI to add controls to
2289022658beSLiam Girdwood  * @controls: array of controls to add
2290022658beSLiam Girdwood  * @num_controls: number of elements in the array
2291022658beSLiam Girdwood  *
2292022658beSLiam Girdwood  * Return 0 for success, else error.
2293022658beSLiam Girdwood  */
2294022658beSLiam Girdwood int snd_soc_add_dai_controls(struct snd_soc_dai *dai,
2295022658beSLiam Girdwood 	const struct snd_kcontrol_new *controls, int num_controls)
2296022658beSLiam Girdwood {
2297313665b9SLars-Peter Clausen 	struct snd_card *card = dai->component->card->snd_card;
2298022658beSLiam Girdwood 
2299022658beSLiam Girdwood 	return snd_soc_add_controls(card, dai->dev, controls, num_controls,
2300022658beSLiam Girdwood 			NULL, dai);
2301022658beSLiam Girdwood }
2302022658beSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls);
2303022658beSLiam Girdwood 
2304c5af3a2eSMark Brown /**
2305c5af3a2eSMark Brown  * snd_soc_register_card - Register a card with the ASoC core
2306c5af3a2eSMark Brown  *
2307ac11a2b3SMark Brown  * @card: Card to register
2308c5af3a2eSMark Brown  *
2309c5af3a2eSMark Brown  */
231070a7ca34SVinod Koul int snd_soc_register_card(struct snd_soc_card *card)
2311c5af3a2eSMark Brown {
2312c5af3a2eSMark Brown 	if (!card->name || !card->dev)
2313c5af3a2eSMark Brown 		return -EINVAL;
2314c5af3a2eSMark Brown 
2315ed77cc12SMark Brown 	dev_set_drvdata(card->dev, card);
2316ed77cc12SMark Brown 
2317b03bfaecSKuninori Morimoto 	INIT_LIST_HEAD(&card->widgets);
2318b03bfaecSKuninori Morimoto 	INIT_LIST_HEAD(&card->paths);
2319b03bfaecSKuninori Morimoto 	INIT_LIST_HEAD(&card->dapm_list);
2320b03bfaecSKuninori Morimoto 	INIT_LIST_HEAD(&card->aux_comp_list);
2321b03bfaecSKuninori Morimoto 	INIT_LIST_HEAD(&card->component_dev_list);
2322b03bfaecSKuninori Morimoto 	INIT_LIST_HEAD(&card->list);
23231a497983SMengdong Lin 	INIT_LIST_HEAD(&card->rtd_list);
2324db432b41SMark Brown 	INIT_LIST_HEAD(&card->dapm_dirty);
23258a978234SLiam Girdwood 	INIT_LIST_HEAD(&card->dobj_list);
2326b03bfaecSKuninori Morimoto 
2327c5af3a2eSMark Brown 	card->instantiated = 0;
2328f0fba2adSLiam Girdwood 	mutex_init(&card->mutex);
2329a73fb2dfSLiam Girdwood 	mutex_init(&card->dapm_mutex);
233072b745e3SPeter Ujfalusi 	mutex_init(&card->pcm_mutex);
2331a9764869SKaiChieh Chuang 	spin_lock_init(&card->dpcm_lock);
2332c5af3a2eSMark Brown 
2333e894efefSSrinivas Kandagatla 	return snd_soc_bind_card(card);
2334c5af3a2eSMark Brown }
233570a7ca34SVinod Koul EXPORT_SYMBOL_GPL(snd_soc_register_card);
2336c5af3a2eSMark Brown 
2337c5af3a2eSMark Brown /**
2338c5af3a2eSMark Brown  * snd_soc_unregister_card - Unregister a card with the ASoC core
2339c5af3a2eSMark Brown  *
2340ac11a2b3SMark Brown  * @card: Card to unregister
2341c5af3a2eSMark Brown  *
2342c5af3a2eSMark Brown  */
234370a7ca34SVinod Koul int snd_soc_unregister_card(struct snd_soc_card *card)
2344c5af3a2eSMark Brown {
2345b545542aSKuninori Morimoto 	mutex_lock(&client_mutex);
2346e894efefSSrinivas Kandagatla 	snd_soc_unbind_card(card, true);
2347b545542aSKuninori Morimoto 	mutex_unlock(&client_mutex);
2348f110bfc7SLiam Girdwood 	dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name);
2349c5af3a2eSMark Brown 
2350c5af3a2eSMark Brown 	return 0;
2351c5af3a2eSMark Brown }
235270a7ca34SVinod Koul EXPORT_SYMBOL_GPL(snd_soc_unregister_card);
2353c5af3a2eSMark Brown 
2354f0fba2adSLiam Girdwood /*
2355f0fba2adSLiam Girdwood  * Simplify DAI link configuration by removing ".-1" from device names
2356f0fba2adSLiam Girdwood  * and sanitizing names.
2357f0fba2adSLiam Girdwood  */
23580b9a214aSDimitris Papastamos static char *fmt_single_name(struct device *dev, int *id)
2359f0fba2adSLiam Girdwood {
2360f0fba2adSLiam Girdwood 	char *found, name[NAME_SIZE];
2361f0fba2adSLiam Girdwood 	int id1, id2;
2362f0fba2adSLiam Girdwood 
2363f0fba2adSLiam Girdwood 	if (dev_name(dev) == NULL)
2364f0fba2adSLiam Girdwood 		return NULL;
2365f0fba2adSLiam Girdwood 
236658818a77SDimitris Papastamos 	strlcpy(name, dev_name(dev), NAME_SIZE);
2367f0fba2adSLiam Girdwood 
2368f0fba2adSLiam Girdwood 	/* are we a "%s.%d" name (platform and SPI components) */
2369f0fba2adSLiam Girdwood 	found = strstr(name, dev->driver->name);
2370f0fba2adSLiam Girdwood 	if (found) {
2371f0fba2adSLiam Girdwood 		/* get ID */
2372f0fba2adSLiam Girdwood 		if (sscanf(&found[strlen(dev->driver->name)], ".%d", id) == 1) {
2373f0fba2adSLiam Girdwood 
2374f0fba2adSLiam Girdwood 			/* discard ID from name if ID == -1 */
2375f0fba2adSLiam Girdwood 			if (*id == -1)
2376f0fba2adSLiam Girdwood 				found[strlen(dev->driver->name)] = '\0';
2377f0fba2adSLiam Girdwood 		}
2378f0fba2adSLiam Girdwood 
2379f0fba2adSLiam Girdwood 	} else {
2380f0fba2adSLiam Girdwood 		/* I2C component devices are named "bus-addr" */
2381f0fba2adSLiam Girdwood 		if (sscanf(name, "%x-%x", &id1, &id2) == 2) {
2382f0fba2adSLiam Girdwood 			char tmp[NAME_SIZE];
2383f0fba2adSLiam Girdwood 
2384f0fba2adSLiam Girdwood 			/* create unique ID number from I2C addr and bus */
238505899446SJarkko Nikula 			*id = ((id1 & 0xffff) << 16) + id2;
2386f0fba2adSLiam Girdwood 
2387f0fba2adSLiam Girdwood 			/* sanitize component name for DAI link creation */
23882c7b696aSMarcel Ziswiler 			snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name,
23892c7b696aSMarcel Ziswiler 				 name);
239058818a77SDimitris Papastamos 			strlcpy(name, tmp, NAME_SIZE);
2391f0fba2adSLiam Girdwood 		} else
2392f0fba2adSLiam Girdwood 			*id = 0;
2393f0fba2adSLiam Girdwood 	}
2394f0fba2adSLiam Girdwood 
239550014499SKuninori Morimoto 	return devm_kstrdup(dev, name, GFP_KERNEL);
2396f0fba2adSLiam Girdwood }
2397f0fba2adSLiam Girdwood 
2398f0fba2adSLiam Girdwood /*
2399f0fba2adSLiam Girdwood  * Simplify DAI link naming for single devices with multiple DAIs by removing
2400f0fba2adSLiam Girdwood  * any ".-1" and using the DAI name (instead of device name).
2401f0fba2adSLiam Girdwood  */
2402f0fba2adSLiam Girdwood static inline char *fmt_multiple_name(struct device *dev,
2403f0fba2adSLiam Girdwood 		struct snd_soc_dai_driver *dai_drv)
2404f0fba2adSLiam Girdwood {
2405f0fba2adSLiam Girdwood 	if (dai_drv->name == NULL) {
240610e8aa9aSMichał Mirosław 		dev_err(dev,
240710e8aa9aSMichał Mirosław 			"ASoC: error - multiple DAI %s registered with no name\n",
240810e8aa9aSMichał Mirosław 			dev_name(dev));
2409f0fba2adSLiam Girdwood 		return NULL;
2410f0fba2adSLiam Girdwood 	}
2411f0fba2adSLiam Girdwood 
241250014499SKuninori Morimoto 	return devm_kstrdup(dev, dai_drv->name, GFP_KERNEL);
2413f0fba2adSLiam Girdwood }
2414f0fba2adSLiam Girdwood 
2415ffdbca0bSKuninori Morimoto void snd_soc_unregister_dai(struct snd_soc_dai *dai)
2416e11381f3SKuninori Morimoto {
2417e11381f3SKuninori Morimoto 	dev_dbg(dai->dev, "ASoC: Unregistered DAI '%s'\n", dai->name);
2418e11381f3SKuninori Morimoto 	list_del(&dai->list);
2419e11381f3SKuninori Morimoto }
2420ffdbca0bSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
2421e11381f3SKuninori Morimoto 
24227ca24386SKuninori Morimoto /**
24237ca24386SKuninori Morimoto  * snd_soc_register_dai - Register a DAI dynamically & create its widgets
24247ca24386SKuninori Morimoto  *
24257ca24386SKuninori Morimoto  * @component: The component the DAIs are registered for
24267ca24386SKuninori Morimoto  * @dai_drv: DAI driver to use for the DAI
2427bc9a6655SRandy Dunlap  * @legacy_dai_naming: if %true, use legacy single-name format;
2428bc9a6655SRandy Dunlap  * 	if %false, use multiple-name format;
24297ca24386SKuninori Morimoto  *
24307ca24386SKuninori Morimoto  * Topology can use this API to register DAIs when probing a component.
24317ca24386SKuninori Morimoto  * These DAIs's widgets will be freed in the card cleanup and the DAIs
24327ca24386SKuninori Morimoto  * will be freed in the component cleanup.
24337ca24386SKuninori Morimoto  */
24347ca24386SKuninori Morimoto struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component,
24355e4fb372SMengdong Lin 					 struct snd_soc_dai_driver *dai_drv,
24365e4fb372SMengdong Lin 					 bool legacy_dai_naming)
24375e4fb372SMengdong Lin {
24385e4fb372SMengdong Lin 	struct device *dev = component->dev;
24395e4fb372SMengdong Lin 	struct snd_soc_dai *dai;
24405e4fb372SMengdong Lin 
24415e4fb372SMengdong Lin 	dev_dbg(dev, "ASoC: dynamically register DAI %s\n", dev_name(dev));
24425e4fb372SMengdong Lin 
24437ca24386SKuninori Morimoto 	lockdep_assert_held(&client_mutex);
24447ca24386SKuninori Morimoto 
244550014499SKuninori Morimoto 	dai = devm_kzalloc(dev, sizeof(*dai), GFP_KERNEL);
24465e4fb372SMengdong Lin 	if (dai == NULL)
24475e4fb372SMengdong Lin 		return NULL;
24485e4fb372SMengdong Lin 
24495e4fb372SMengdong Lin 	/*
24505e4fb372SMengdong Lin 	 * Back in the old days when we still had component-less DAIs,
24515e4fb372SMengdong Lin 	 * instead of having a static name, component-less DAIs would
24525e4fb372SMengdong Lin 	 * inherit the name of the parent device so it is possible to
24535e4fb372SMengdong Lin 	 * register multiple instances of the DAI. We still need to keep
24545e4fb372SMengdong Lin 	 * the same naming style even though those DAIs are not
24555e4fb372SMengdong Lin 	 * component-less anymore.
24565e4fb372SMengdong Lin 	 */
24575e4fb372SMengdong Lin 	if (legacy_dai_naming &&
24585e4fb372SMengdong Lin 	    (dai_drv->id == 0 || dai_drv->name == NULL)) {
24595e4fb372SMengdong Lin 		dai->name = fmt_single_name(dev, &dai->id);
24605e4fb372SMengdong Lin 	} else {
24615e4fb372SMengdong Lin 		dai->name = fmt_multiple_name(dev, dai_drv);
24625e4fb372SMengdong Lin 		if (dai_drv->id)
24635e4fb372SMengdong Lin 			dai->id = dai_drv->id;
24645e4fb372SMengdong Lin 		else
24655e4fb372SMengdong Lin 			dai->id = component->num_dai;
24665e4fb372SMengdong Lin 	}
246750014499SKuninori Morimoto 	if (!dai->name)
24685e4fb372SMengdong Lin 		return NULL;
24695e4fb372SMengdong Lin 
24705e4fb372SMengdong Lin 	dai->component = component;
24715e4fb372SMengdong Lin 	dai->dev = dev;
24725e4fb372SMengdong Lin 	dai->driver = dai_drv;
24735e4fb372SMengdong Lin 	if (!dai->driver->ops)
24745e4fb372SMengdong Lin 		dai->driver->ops = &null_dai_ops;
24755e4fb372SMengdong Lin 
247615a0c645SKuninori Morimoto 	/* see for_each_component_dais */
247758bf4179SKuninori Morimoto 	list_add_tail(&dai->list, &component->dai_list);
24785e4fb372SMengdong Lin 	component->num_dai++;
24795e4fb372SMengdong Lin 
24805e4fb372SMengdong Lin 	dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
24815e4fb372SMengdong Lin 	return dai;
24825e4fb372SMengdong Lin }
2483e11381f3SKuninori Morimoto 
24849115171aSMark Brown /**
24853f6674aeSKuninori Morimoto  * snd_soc_unregister_dai - Unregister DAIs from the ASoC core
24863f6674aeSKuninori Morimoto  *
24873f6674aeSKuninori Morimoto  * @component: The component for which the DAIs should be unregistered
24883f6674aeSKuninori Morimoto  */
24893f6674aeSKuninori Morimoto static void snd_soc_unregister_dais(struct snd_soc_component *component)
24903f6674aeSKuninori Morimoto {
24913f6674aeSKuninori Morimoto 	struct snd_soc_dai *dai, *_dai;
24923f6674aeSKuninori Morimoto 
2493e11381f3SKuninori Morimoto 	for_each_component_dais_safe(component, dai, _dai)
2494e11381f3SKuninori Morimoto 		snd_soc_unregister_dai(dai);
24953f6674aeSKuninori Morimoto }
24963f6674aeSKuninori Morimoto 
24973f6674aeSKuninori Morimoto /**
2498daf77373SKuninori Morimoto  * snd_soc_register_dais - Register a DAI with the ASoC core
2499daf77373SKuninori Morimoto  *
2500daf77373SKuninori Morimoto  * @component: The component the DAIs are registered for
2501daf77373SKuninori Morimoto  * @dai_drv: DAI driver to use for the DAIs
2502daf77373SKuninori Morimoto  * @count: Number of DAIs
2503daf77373SKuninori Morimoto  */
2504daf77373SKuninori Morimoto static int snd_soc_register_dais(struct snd_soc_component *component,
2505daf77373SKuninori Morimoto 				 struct snd_soc_dai_driver *dai_drv,
2506daf77373SKuninori Morimoto 				 size_t count)
2507daf77373SKuninori Morimoto {
2508daf77373SKuninori Morimoto 	struct snd_soc_dai *dai;
2509daf77373SKuninori Morimoto 	unsigned int i;
2510daf77373SKuninori Morimoto 	int ret;
2511daf77373SKuninori Morimoto 
2512daf77373SKuninori Morimoto 	for (i = 0; i < count; i++) {
251371cb85f5SKuninori Morimoto 		dai = snd_soc_register_dai(component, dai_drv + i, count == 1 &&
2514daf77373SKuninori Morimoto 				  !component->driver->non_legacy_dai_naming);
2515daf77373SKuninori Morimoto 		if (dai == NULL) {
2516daf77373SKuninori Morimoto 			ret = -ENOMEM;
2517daf77373SKuninori Morimoto 			goto err;
2518daf77373SKuninori Morimoto 		}
2519daf77373SKuninori Morimoto 	}
2520daf77373SKuninori Morimoto 
2521daf77373SKuninori Morimoto 	return 0;
2522daf77373SKuninori Morimoto 
2523daf77373SKuninori Morimoto err:
2524daf77373SKuninori Morimoto 	snd_soc_unregister_dais(component);
2525daf77373SKuninori Morimoto 
2526daf77373SKuninori Morimoto 	return ret;
2527daf77373SKuninori Morimoto }
2528daf77373SKuninori Morimoto 
2529bb13109dSLars-Peter Clausen static int snd_soc_component_initialize(struct snd_soc_component *component,
2530bb13109dSLars-Peter Clausen 	const struct snd_soc_component_driver *driver, struct device *dev)
2531d191bd8dSKuninori Morimoto {
25328d92bb51SKuninori Morimoto 	INIT_LIST_HEAD(&component->dai_list);
2533495efdb0SKuninori Morimoto 	INIT_LIST_HEAD(&component->dobj_list);
2534495efdb0SKuninori Morimoto 	INIT_LIST_HEAD(&component->card_list);
25358d92bb51SKuninori Morimoto 	mutex_init(&component->io_mutex);
25368d92bb51SKuninori Morimoto 
2537bb13109dSLars-Peter Clausen 	component->name = fmt_single_name(dev, &component->id);
2538bb13109dSLars-Peter Clausen 	if (!component->name) {
2539bb13109dSLars-Peter Clausen 		dev_err(dev, "ASoC: Failed to allocate name\n");
2540d191bd8dSKuninori Morimoto 		return -ENOMEM;
2541d191bd8dSKuninori Morimoto 	}
2542d191bd8dSKuninori Morimoto 
2543bb13109dSLars-Peter Clausen 	component->dev = dev;
2544bb13109dSLars-Peter Clausen 	component->driver = driver;
2545e2c330b9SLars-Peter Clausen 
2546bb13109dSLars-Peter Clausen 	return 0;
2547d191bd8dSKuninori Morimoto }
2548d191bd8dSKuninori Morimoto 
254920feb881SLars-Peter Clausen static void snd_soc_component_setup_regmap(struct snd_soc_component *component)
2550886f5692SLars-Peter Clausen {
2551886f5692SLars-Peter Clausen 	int val_bytes = regmap_get_val_bytes(component->regmap);
255220feb881SLars-Peter Clausen 
2553886f5692SLars-Peter Clausen 	/* Errors are legitimate for non-integer byte multiples */
2554886f5692SLars-Peter Clausen 	if (val_bytes > 0)
2555886f5692SLars-Peter Clausen 		component->val_bytes = val_bytes;
2556886f5692SLars-Peter Clausen }
255720feb881SLars-Peter Clausen 
2558e874bf5fSLars-Peter Clausen #ifdef CONFIG_REGMAP
2559e874bf5fSLars-Peter Clausen 
256020feb881SLars-Peter Clausen /**
25612c7b696aSMarcel Ziswiler  * snd_soc_component_init_regmap() - Initialize regmap instance for the
25622c7b696aSMarcel Ziswiler  *                                   component
256320feb881SLars-Peter Clausen  * @component: The component for which to initialize the regmap instance
256420feb881SLars-Peter Clausen  * @regmap: The regmap instance that should be used by the component
256520feb881SLars-Peter Clausen  *
256620feb881SLars-Peter Clausen  * This function allows deferred assignment of the regmap instance that is
256720feb881SLars-Peter Clausen  * associated with the component. Only use this if the regmap instance is not
256820feb881SLars-Peter Clausen  * yet ready when the component is registered. The function must also be called
256920feb881SLars-Peter Clausen  * before the first IO attempt of the component.
257020feb881SLars-Peter Clausen  */
257120feb881SLars-Peter Clausen void snd_soc_component_init_regmap(struct snd_soc_component *component,
257220feb881SLars-Peter Clausen 	struct regmap *regmap)
257320feb881SLars-Peter Clausen {
257420feb881SLars-Peter Clausen 	component->regmap = regmap;
257520feb881SLars-Peter Clausen 	snd_soc_component_setup_regmap(component);
2576886f5692SLars-Peter Clausen }
257720feb881SLars-Peter Clausen EXPORT_SYMBOL_GPL(snd_soc_component_init_regmap);
257820feb881SLars-Peter Clausen 
257920feb881SLars-Peter Clausen /**
25802c7b696aSMarcel Ziswiler  * snd_soc_component_exit_regmap() - De-initialize regmap instance for the
25812c7b696aSMarcel Ziswiler  *                                   component
258220feb881SLars-Peter Clausen  * @component: The component for which to de-initialize the regmap instance
258320feb881SLars-Peter Clausen  *
258420feb881SLars-Peter Clausen  * Calls regmap_exit() on the regmap instance associated to the component and
258520feb881SLars-Peter Clausen  * removes the regmap instance from the component.
258620feb881SLars-Peter Clausen  *
258720feb881SLars-Peter Clausen  * This function should only be used if snd_soc_component_init_regmap() was used
258820feb881SLars-Peter Clausen  * to initialize the regmap instance.
258920feb881SLars-Peter Clausen  */
259020feb881SLars-Peter Clausen void snd_soc_component_exit_regmap(struct snd_soc_component *component)
259120feb881SLars-Peter Clausen {
259220feb881SLars-Peter Clausen 	regmap_exit(component->regmap);
259320feb881SLars-Peter Clausen 	component->regmap = NULL;
259420feb881SLars-Peter Clausen }
259520feb881SLars-Peter Clausen EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap);
2596886f5692SLars-Peter Clausen 
2597e874bf5fSLars-Peter Clausen #endif
2598d191bd8dSKuninori Morimoto 
2599273d778eSKuninori Morimoto #define ENDIANNESS_MAP(name) \
2600273d778eSKuninori Morimoto 	(SNDRV_PCM_FMTBIT_##name##LE | SNDRV_PCM_FMTBIT_##name##BE)
2601273d778eSKuninori Morimoto static u64 endianness_format_map[] = {
2602273d778eSKuninori Morimoto 	ENDIANNESS_MAP(S16_),
2603273d778eSKuninori Morimoto 	ENDIANNESS_MAP(U16_),
2604273d778eSKuninori Morimoto 	ENDIANNESS_MAP(S24_),
2605273d778eSKuninori Morimoto 	ENDIANNESS_MAP(U24_),
2606273d778eSKuninori Morimoto 	ENDIANNESS_MAP(S32_),
2607273d778eSKuninori Morimoto 	ENDIANNESS_MAP(U32_),
2608273d778eSKuninori Morimoto 	ENDIANNESS_MAP(S24_3),
2609273d778eSKuninori Morimoto 	ENDIANNESS_MAP(U24_3),
2610273d778eSKuninori Morimoto 	ENDIANNESS_MAP(S20_3),
2611273d778eSKuninori Morimoto 	ENDIANNESS_MAP(U20_3),
2612273d778eSKuninori Morimoto 	ENDIANNESS_MAP(S18_3),
2613273d778eSKuninori Morimoto 	ENDIANNESS_MAP(U18_3),
2614273d778eSKuninori Morimoto 	ENDIANNESS_MAP(FLOAT_),
2615273d778eSKuninori Morimoto 	ENDIANNESS_MAP(FLOAT64_),
2616273d778eSKuninori Morimoto 	ENDIANNESS_MAP(IEC958_SUBFRAME_),
2617273d778eSKuninori Morimoto };
2618273d778eSKuninori Morimoto 
2619273d778eSKuninori Morimoto /*
2620273d778eSKuninori Morimoto  * Fix up the DAI formats for endianness: codecs don't actually see
2621273d778eSKuninori Morimoto  * the endianness of the data but we're using the CPU format
2622273d778eSKuninori Morimoto  * definitions which do need to include endianness so we ensure that
2623273d778eSKuninori Morimoto  * codec DAIs always have both big and little endian variants set.
2624273d778eSKuninori Morimoto  */
2625273d778eSKuninori Morimoto static void convert_endianness_formats(struct snd_soc_pcm_stream *stream)
2626273d778eSKuninori Morimoto {
2627273d778eSKuninori Morimoto 	int i;
2628273d778eSKuninori Morimoto 
2629273d778eSKuninori Morimoto 	for (i = 0; i < ARRAY_SIZE(endianness_format_map); i++)
2630273d778eSKuninori Morimoto 		if (stream->formats & endianness_format_map[i])
2631273d778eSKuninori Morimoto 			stream->formats |= endianness_format_map[i];
2632273d778eSKuninori Morimoto }
2633273d778eSKuninori Morimoto 
2634e894efefSSrinivas Kandagatla static void snd_soc_try_rebind_card(void)
2635e894efefSSrinivas Kandagatla {
2636e894efefSSrinivas Kandagatla 	struct snd_soc_card *card, *c;
2637e894efefSSrinivas Kandagatla 
2638b245d273SKuninori Morimoto 	list_for_each_entry_safe(card, c, &unbind_card_list, list)
2639e894efefSSrinivas Kandagatla 		if (!snd_soc_bind_card(card))
2640e894efefSSrinivas Kandagatla 			list_del(&card->list);
2641e894efefSSrinivas Kandagatla }
2642e894efefSSrinivas Kandagatla 
2643486c7978SKuninori Morimoto static void snd_soc_del_component_unlocked(struct snd_soc_component *component)
2644486c7978SKuninori Morimoto {
2645b18768f5SKuninori Morimoto 	struct snd_soc_card *card = component->card;
2646b18768f5SKuninori Morimoto 
2647486c7978SKuninori Morimoto 	snd_soc_unregister_dais(component);
2648b18768f5SKuninori Morimoto 
2649b18768f5SKuninori Morimoto 	if (card)
2650b18768f5SKuninori Morimoto 		snd_soc_unbind_card(card, false);
2651b18768f5SKuninori Morimoto 
2652b18768f5SKuninori Morimoto 	list_del(&component->list);
2653486c7978SKuninori Morimoto }
2654486c7978SKuninori Morimoto 
2655e0dac41bSKuninori Morimoto int snd_soc_add_component(struct device *dev,
2656e0dac41bSKuninori Morimoto 			struct snd_soc_component *component,
2657cf9e829eSKuninori Morimoto 			const struct snd_soc_component_driver *component_driver,
2658d191bd8dSKuninori Morimoto 			struct snd_soc_dai_driver *dai_drv,
2659d191bd8dSKuninori Morimoto 			int num_dai)
2660d191bd8dSKuninori Morimoto {
2661bb13109dSLars-Peter Clausen 	int ret;
2662273d778eSKuninori Morimoto 	int i;
2663d191bd8dSKuninori Morimoto 
2664b18768f5SKuninori Morimoto 	mutex_lock(&client_mutex);
2665b18768f5SKuninori Morimoto 
2666cf9e829eSKuninori Morimoto 	ret = snd_soc_component_initialize(component, component_driver, dev);
2667bb13109dSLars-Peter Clausen 	if (ret)
2668bb13109dSLars-Peter Clausen 		goto err_free;
2669bb13109dSLars-Peter Clausen 
2670273d778eSKuninori Morimoto 	if (component_driver->endianness) {
2671273d778eSKuninori Morimoto 		for (i = 0; i < num_dai; i++) {
2672273d778eSKuninori Morimoto 			convert_endianness_formats(&dai_drv[i].playback);
2673273d778eSKuninori Morimoto 			convert_endianness_formats(&dai_drv[i].capture);
2674273d778eSKuninori Morimoto 		}
2675273d778eSKuninori Morimoto 	}
2676273d778eSKuninori Morimoto 
26770e7b25c6SKuninori Morimoto 	ret = snd_soc_register_dais(component, dai_drv, num_dai);
2678bb13109dSLars-Peter Clausen 	if (ret < 0) {
2679f42cf8d6SMasanari Iida 		dev_err(dev, "ASoC: Failed to register DAIs: %d\n", ret);
2680bb13109dSLars-Peter Clausen 		goto err_cleanup;
2681bb13109dSLars-Peter Clausen 	}
2682bb13109dSLars-Peter Clausen 
2683b18768f5SKuninori Morimoto 	if (!component->driver->write && !component->driver->read) {
2684b18768f5SKuninori Morimoto 		if (!component->regmap)
2685b18768f5SKuninori Morimoto 			component->regmap = dev_get_regmap(component->dev,
2686b18768f5SKuninori Morimoto 							   NULL);
2687b18768f5SKuninori Morimoto 		if (component->regmap)
2688b18768f5SKuninori Morimoto 			snd_soc_component_setup_regmap(component);
2689b18768f5SKuninori Morimoto 	}
2690bb13109dSLars-Peter Clausen 
2691b18768f5SKuninori Morimoto 	/* see for_each_component */
2692b18768f5SKuninori Morimoto 	list_add(&component->list, &component_list);
2693bb13109dSLars-Peter Clausen 
2694bb13109dSLars-Peter Clausen err_cleanup:
2695b18768f5SKuninori Morimoto 	if (ret < 0)
2696486c7978SKuninori Morimoto 		snd_soc_del_component_unlocked(component);
2697bb13109dSLars-Peter Clausen err_free:
2698b18768f5SKuninori Morimoto 	mutex_unlock(&client_mutex);
2699b18768f5SKuninori Morimoto 
2700b18768f5SKuninori Morimoto 	if (ret == 0)
2701b18768f5SKuninori Morimoto 		snd_soc_try_rebind_card();
2702b18768f5SKuninori Morimoto 
2703bb13109dSLars-Peter Clausen 	return ret;
2704d191bd8dSKuninori Morimoto }
2705e0dac41bSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_add_component);
2706e0dac41bSKuninori Morimoto 
2707e0dac41bSKuninori Morimoto int snd_soc_register_component(struct device *dev,
2708e0dac41bSKuninori Morimoto 			const struct snd_soc_component_driver *component_driver,
2709e0dac41bSKuninori Morimoto 			struct snd_soc_dai_driver *dai_drv,
2710e0dac41bSKuninori Morimoto 			int num_dai)
2711e0dac41bSKuninori Morimoto {
2712e0dac41bSKuninori Morimoto 	struct snd_soc_component *component;
2713e0dac41bSKuninori Morimoto 
27147ecbd6a9SKuninori Morimoto 	component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL);
271508e61d03SKuninori Morimoto 	if (!component)
2716e0dac41bSKuninori Morimoto 		return -ENOMEM;
2717e0dac41bSKuninori Morimoto 
2718e0dac41bSKuninori Morimoto 	return snd_soc_add_component(dev, component, component_driver,
2719e0dac41bSKuninori Morimoto 				     dai_drv, num_dai);
2720e0dac41bSKuninori Morimoto }
2721d191bd8dSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_register_component);
2722d191bd8dSKuninori Morimoto 
2723d191bd8dSKuninori Morimoto /**
27242eccea8cSKuninori Morimoto  * snd_soc_unregister_component - Unregister all related component
27252eccea8cSKuninori Morimoto  * from the ASoC core
2726d191bd8dSKuninori Morimoto  *
2727628536eaSJonathan Corbet  * @dev: The device to unregister
2728d191bd8dSKuninori Morimoto  */
27292eccea8cSKuninori Morimoto void snd_soc_unregister_component(struct device *dev)
27302eccea8cSKuninori Morimoto {
2731ac6a4dd3SKuninori Morimoto 	struct snd_soc_component *component;
2732ac6a4dd3SKuninori Morimoto 
2733ac6a4dd3SKuninori Morimoto 	mutex_lock(&client_mutex);
2734ac6a4dd3SKuninori Morimoto 	while (1) {
273518dd66eaSKuninori Morimoto 		component = snd_soc_lookup_component_nolocked(dev, NULL);
2736ac6a4dd3SKuninori Morimoto 		if (!component)
2737ac6a4dd3SKuninori Morimoto 			break;
2738ac6a4dd3SKuninori Morimoto 
2739ac6a4dd3SKuninori Morimoto 		snd_soc_del_component_unlocked(component);
2740ac6a4dd3SKuninori Morimoto 	}
2741ac6a4dd3SKuninori Morimoto 	mutex_unlock(&client_mutex);
2742d191bd8dSKuninori Morimoto }
2743d191bd8dSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
2744d191bd8dSKuninori Morimoto 
2745bec4fa05SStephen Warren /* Retrieve a card's name from device tree */
2746b07609ceSKuninori Morimoto int snd_soc_of_parse_card_name(struct snd_soc_card *card,
2747bec4fa05SStephen Warren 			       const char *propname)
2748bec4fa05SStephen Warren {
2749b07609ceSKuninori Morimoto 	struct device_node *np;
2750bec4fa05SStephen Warren 	int ret;
2751bec4fa05SStephen Warren 
27527e07e7c0STushar Behera 	if (!card->dev) {
27537e07e7c0STushar Behera 		pr_err("card->dev is not set before calling %s\n", __func__);
27547e07e7c0STushar Behera 		return -EINVAL;
27557e07e7c0STushar Behera 	}
27567e07e7c0STushar Behera 
27577e07e7c0STushar Behera 	np = card->dev->of_node;
27587e07e7c0STushar Behera 
2759bec4fa05SStephen Warren 	ret = of_property_read_string_index(np, propname, 0, &card->name);
2760bec4fa05SStephen Warren 	/*
2761bec4fa05SStephen Warren 	 * EINVAL means the property does not exist. This is fine providing
2762bec4fa05SStephen Warren 	 * card->name was previously set, which is checked later in
2763bec4fa05SStephen Warren 	 * snd_soc_register_card.
2764bec4fa05SStephen Warren 	 */
2765bec4fa05SStephen Warren 	if (ret < 0 && ret != -EINVAL) {
2766bec4fa05SStephen Warren 		dev_err(card->dev,
2767f110bfc7SLiam Girdwood 			"ASoC: Property '%s' could not be read: %d\n",
2768bec4fa05SStephen Warren 			propname, ret);
2769bec4fa05SStephen Warren 		return ret;
2770bec4fa05SStephen Warren 	}
2771bec4fa05SStephen Warren 
2772bec4fa05SStephen Warren 	return 0;
2773bec4fa05SStephen Warren }
2774b07609ceSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name);
2775bec4fa05SStephen Warren 
27769a6d4860SXiubo Li static const struct snd_soc_dapm_widget simple_widgets[] = {
27779a6d4860SXiubo Li 	SND_SOC_DAPM_MIC("Microphone", NULL),
27789a6d4860SXiubo Li 	SND_SOC_DAPM_LINE("Line", NULL),
27799a6d4860SXiubo Li 	SND_SOC_DAPM_HP("Headphone", NULL),
27809a6d4860SXiubo Li 	SND_SOC_DAPM_SPK("Speaker", NULL),
27819a6d4860SXiubo Li };
27829a6d4860SXiubo Li 
278321efde50SKuninori Morimoto int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
27849a6d4860SXiubo Li 					  const char *propname)
27859a6d4860SXiubo Li {
278621efde50SKuninori Morimoto 	struct device_node *np = card->dev->of_node;
27879a6d4860SXiubo Li 	struct snd_soc_dapm_widget *widgets;
27889a6d4860SXiubo Li 	const char *template, *wname;
27899a6d4860SXiubo Li 	int i, j, num_widgets, ret;
27909a6d4860SXiubo Li 
27919a6d4860SXiubo Li 	num_widgets = of_property_count_strings(np, propname);
27929a6d4860SXiubo Li 	if (num_widgets < 0) {
27939a6d4860SXiubo Li 		dev_err(card->dev,
27949a6d4860SXiubo Li 			"ASoC: Property '%s' does not exist\n",	propname);
27959a6d4860SXiubo Li 		return -EINVAL;
27969a6d4860SXiubo Li 	}
27979a6d4860SXiubo Li 	if (num_widgets & 1) {
27989a6d4860SXiubo Li 		dev_err(card->dev,
27999a6d4860SXiubo Li 			"ASoC: Property '%s' length is not even\n", propname);
28009a6d4860SXiubo Li 		return -EINVAL;
28019a6d4860SXiubo Li 	}
28029a6d4860SXiubo Li 
28039a6d4860SXiubo Li 	num_widgets /= 2;
28049a6d4860SXiubo Li 	if (!num_widgets) {
28059a6d4860SXiubo Li 		dev_err(card->dev, "ASoC: Property '%s's length is zero\n",
28069a6d4860SXiubo Li 			propname);
28079a6d4860SXiubo Li 		return -EINVAL;
28089a6d4860SXiubo Li 	}
28099a6d4860SXiubo Li 
28109a6d4860SXiubo Li 	widgets = devm_kcalloc(card->dev, num_widgets, sizeof(*widgets),
28119a6d4860SXiubo Li 			       GFP_KERNEL);
28129a6d4860SXiubo Li 	if (!widgets) {
28139a6d4860SXiubo Li 		dev_err(card->dev,
28149a6d4860SXiubo Li 			"ASoC: Could not allocate memory for widgets\n");
28159a6d4860SXiubo Li 		return -ENOMEM;
28169a6d4860SXiubo Li 	}
28179a6d4860SXiubo Li 
28189a6d4860SXiubo Li 	for (i = 0; i < num_widgets; i++) {
28199a6d4860SXiubo Li 		ret = of_property_read_string_index(np, propname,
28209a6d4860SXiubo Li 			2 * i, &template);
28219a6d4860SXiubo Li 		if (ret) {
28229a6d4860SXiubo Li 			dev_err(card->dev,
28239a6d4860SXiubo Li 				"ASoC: Property '%s' index %d read error:%d\n",
28249a6d4860SXiubo Li 				propname, 2 * i, ret);
28259a6d4860SXiubo Li 			return -EINVAL;
28269a6d4860SXiubo Li 		}
28279a6d4860SXiubo Li 
28289a6d4860SXiubo Li 		for (j = 0; j < ARRAY_SIZE(simple_widgets); j++) {
28299a6d4860SXiubo Li 			if (!strncmp(template, simple_widgets[j].name,
28309a6d4860SXiubo Li 				     strlen(simple_widgets[j].name))) {
28319a6d4860SXiubo Li 				widgets[i] = simple_widgets[j];
28329a6d4860SXiubo Li 				break;
28339a6d4860SXiubo Li 			}
28349a6d4860SXiubo Li 		}
28359a6d4860SXiubo Li 
28369a6d4860SXiubo Li 		if (j >= ARRAY_SIZE(simple_widgets)) {
28379a6d4860SXiubo Li 			dev_err(card->dev,
28389a6d4860SXiubo Li 				"ASoC: DAPM widget '%s' is not supported\n",
28399a6d4860SXiubo Li 				template);
28409a6d4860SXiubo Li 			return -EINVAL;
28419a6d4860SXiubo Li 		}
28429a6d4860SXiubo Li 
28439a6d4860SXiubo Li 		ret = of_property_read_string_index(np, propname,
28449a6d4860SXiubo Li 						    (2 * i) + 1,
28459a6d4860SXiubo Li 						    &wname);
28469a6d4860SXiubo Li 		if (ret) {
28479a6d4860SXiubo Li 			dev_err(card->dev,
28489a6d4860SXiubo Li 				"ASoC: Property '%s' index %d read error:%d\n",
28499a6d4860SXiubo Li 				propname, (2 * i) + 1, ret);
28509a6d4860SXiubo Li 			return -EINVAL;
28519a6d4860SXiubo Li 		}
28529a6d4860SXiubo Li 
28539a6d4860SXiubo Li 		widgets[i].name = wname;
28549a6d4860SXiubo Li 	}
28559a6d4860SXiubo Li 
2856f23e860eSNicolin Chen 	card->of_dapm_widgets = widgets;
2857f23e860eSNicolin Chen 	card->num_of_dapm_widgets = num_widgets;
28589a6d4860SXiubo Li 
28599a6d4860SXiubo Li 	return 0;
28609a6d4860SXiubo Li }
286121efde50SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets);
28629a6d4860SXiubo Li 
2863cbdfab3bSJerome Brunet int snd_soc_of_get_slot_mask(struct device_node *np,
28646131084aSJyri Sarha 			     const char *prop_name,
28656131084aSJyri Sarha 			     unsigned int *mask)
28666131084aSJyri Sarha {
28676131084aSJyri Sarha 	u32 val;
28686c84e591SJyri Sarha 	const __be32 *of_slot_mask = of_get_property(np, prop_name, &val);
28696131084aSJyri Sarha 	int i;
28706131084aSJyri Sarha 
28716131084aSJyri Sarha 	if (!of_slot_mask)
28726131084aSJyri Sarha 		return 0;
28736131084aSJyri Sarha 	val /= sizeof(u32);
28746131084aSJyri Sarha 	for (i = 0; i < val; i++)
28756131084aSJyri Sarha 		if (be32_to_cpup(&of_slot_mask[i]))
28766131084aSJyri Sarha 			*mask |= (1 << i);
28776131084aSJyri Sarha 
28786131084aSJyri Sarha 	return val;
28796131084aSJyri Sarha }
2880cbdfab3bSJerome Brunet EXPORT_SYMBOL_GPL(snd_soc_of_get_slot_mask);
28816131084aSJyri Sarha 
288289c67857SXiubo Li int snd_soc_of_parse_tdm_slot(struct device_node *np,
28836131084aSJyri Sarha 			      unsigned int *tx_mask,
28846131084aSJyri Sarha 			      unsigned int *rx_mask,
288589c67857SXiubo Li 			      unsigned int *slots,
288689c67857SXiubo Li 			      unsigned int *slot_width)
288789c67857SXiubo Li {
288889c67857SXiubo Li 	u32 val;
288989c67857SXiubo Li 	int ret;
289089c67857SXiubo Li 
28916131084aSJyri Sarha 	if (tx_mask)
28926131084aSJyri Sarha 		snd_soc_of_get_slot_mask(np, "dai-tdm-slot-tx-mask", tx_mask);
28936131084aSJyri Sarha 	if (rx_mask)
28946131084aSJyri Sarha 		snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", rx_mask);
28956131084aSJyri Sarha 
289689c67857SXiubo Li 	if (of_property_read_bool(np, "dai-tdm-slot-num")) {
289789c67857SXiubo Li 		ret = of_property_read_u32(np, "dai-tdm-slot-num", &val);
289889c67857SXiubo Li 		if (ret)
289989c67857SXiubo Li 			return ret;
290089c67857SXiubo Li 
290189c67857SXiubo Li 		if (slots)
290289c67857SXiubo Li 			*slots = val;
290389c67857SXiubo Li 	}
290489c67857SXiubo Li 
290589c67857SXiubo Li 	if (of_property_read_bool(np, "dai-tdm-slot-width")) {
290689c67857SXiubo Li 		ret = of_property_read_u32(np, "dai-tdm-slot-width", &val);
290789c67857SXiubo Li 		if (ret)
290889c67857SXiubo Li 			return ret;
290989c67857SXiubo Li 
291089c67857SXiubo Li 		if (slot_width)
291189c67857SXiubo Li 			*slot_width = val;
291289c67857SXiubo Li 	}
291389c67857SXiubo Li 
291489c67857SXiubo Li 	return 0;
291589c67857SXiubo Li }
291689c67857SXiubo Li EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot);
291789c67857SXiubo Li 
29183b710356SKuninori Morimoto void snd_soc_of_parse_node_prefix(struct device_node *np,
29195e3cdaa2SKuninori Morimoto 				  struct snd_soc_codec_conf *codec_conf,
29205e3cdaa2SKuninori Morimoto 				  struct device_node *of_node,
29215e3cdaa2SKuninori Morimoto 				  const char *propname)
29225e3cdaa2SKuninori Morimoto {
29235e3cdaa2SKuninori Morimoto 	const char *str;
29245e3cdaa2SKuninori Morimoto 	int ret;
29255e3cdaa2SKuninori Morimoto 
29265e3cdaa2SKuninori Morimoto 	ret = of_property_read_string(np, propname, &str);
29275e3cdaa2SKuninori Morimoto 	if (ret < 0) {
29285e3cdaa2SKuninori Morimoto 		/* no prefix is not error */
29295e3cdaa2SKuninori Morimoto 		return;
29305e3cdaa2SKuninori Morimoto 	}
29315e3cdaa2SKuninori Morimoto 
29325e3cdaa2SKuninori Morimoto 	codec_conf->of_node	= of_node;
29335e3cdaa2SKuninori Morimoto 	codec_conf->name_prefix	= str;
29345e3cdaa2SKuninori Morimoto }
29353b710356SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_node_prefix);
29365e3cdaa2SKuninori Morimoto 
29372bc644afSKuninori Morimoto int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
2938a4a54dd5SStephen Warren 				   const char *propname)
2939a4a54dd5SStephen Warren {
29402bc644afSKuninori Morimoto 	struct device_node *np = card->dev->of_node;
2941e3b1e6a1SMark Brown 	int num_routes;
2942a4a54dd5SStephen Warren 	struct snd_soc_dapm_route *routes;
2943a4a54dd5SStephen Warren 	int i, ret;
2944a4a54dd5SStephen Warren 
2945a4a54dd5SStephen Warren 	num_routes = of_property_count_strings(np, propname);
2946c34ce320SRichard Zhao 	if (num_routes < 0 || num_routes & 1) {
294710e8aa9aSMichał Mirosław 		dev_err(card->dev,
294810e8aa9aSMichał Mirosław 			"ASoC: Property '%s' does not exist or its length is not even\n",
294910e8aa9aSMichał Mirosław 			propname);
2950a4a54dd5SStephen Warren 		return -EINVAL;
2951a4a54dd5SStephen Warren 	}
2952a4a54dd5SStephen Warren 	num_routes /= 2;
2953a4a54dd5SStephen Warren 	if (!num_routes) {
2954f110bfc7SLiam Girdwood 		dev_err(card->dev, "ASoC: Property '%s's length is zero\n",
2955a4a54dd5SStephen Warren 			propname);
2956a4a54dd5SStephen Warren 		return -EINVAL;
2957a4a54dd5SStephen Warren 	}
2958a4a54dd5SStephen Warren 
2959a86854d0SKees Cook 	routes = devm_kcalloc(card->dev, num_routes, sizeof(*routes),
2960a4a54dd5SStephen Warren 			      GFP_KERNEL);
2961a4a54dd5SStephen Warren 	if (!routes) {
2962a4a54dd5SStephen Warren 		dev_err(card->dev,
2963f110bfc7SLiam Girdwood 			"ASoC: Could not allocate DAPM route table\n");
2964a4a54dd5SStephen Warren 		return -EINVAL;
2965a4a54dd5SStephen Warren 	}
2966a4a54dd5SStephen Warren 
2967a4a54dd5SStephen Warren 	for (i = 0; i < num_routes; i++) {
2968a4a54dd5SStephen Warren 		ret = of_property_read_string_index(np, propname,
2969e3b1e6a1SMark Brown 			2 * i, &routes[i].sink);
2970a4a54dd5SStephen Warren 		if (ret) {
2971c871bd0bSMark Brown 			dev_err(card->dev,
2972c871bd0bSMark Brown 				"ASoC: Property '%s' index %d could not be read: %d\n",
2973c871bd0bSMark Brown 				propname, 2 * i, ret);
2974a4a54dd5SStephen Warren 			return -EINVAL;
2975a4a54dd5SStephen Warren 		}
2976a4a54dd5SStephen Warren 		ret = of_property_read_string_index(np, propname,
2977e3b1e6a1SMark Brown 			(2 * i) + 1, &routes[i].source);
2978a4a54dd5SStephen Warren 		if (ret) {
2979a4a54dd5SStephen Warren 			dev_err(card->dev,
2980c871bd0bSMark Brown 				"ASoC: Property '%s' index %d could not be read: %d\n",
2981c871bd0bSMark Brown 				propname, (2 * i) + 1, ret);
2982a4a54dd5SStephen Warren 			return -EINVAL;
2983a4a54dd5SStephen Warren 		}
2984a4a54dd5SStephen Warren 	}
2985a4a54dd5SStephen Warren 
2986f23e860eSNicolin Chen 	card->num_of_dapm_routes = num_routes;
2987f23e860eSNicolin Chen 	card->of_dapm_routes = routes;
2988a4a54dd5SStephen Warren 
2989a4a54dd5SStephen Warren 	return 0;
2990a4a54dd5SStephen Warren }
29912bc644afSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing);
2992a4a54dd5SStephen Warren 
2993a7930ed4SKuninori Morimoto unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
2994389cb834SJyri Sarha 				     const char *prefix,
2995389cb834SJyri Sarha 				     struct device_node **bitclkmaster,
2996389cb834SJyri Sarha 				     struct device_node **framemaster)
2997a7930ed4SKuninori Morimoto {
2998a7930ed4SKuninori Morimoto 	int ret, i;
2999a7930ed4SKuninori Morimoto 	char prop[128];
3000a7930ed4SKuninori Morimoto 	unsigned int format = 0;
3001a7930ed4SKuninori Morimoto 	int bit, frame;
3002a7930ed4SKuninori Morimoto 	const char *str;
3003a7930ed4SKuninori Morimoto 	struct {
3004a7930ed4SKuninori Morimoto 		char *name;
3005a7930ed4SKuninori Morimoto 		unsigned int val;
3006a7930ed4SKuninori Morimoto 	} of_fmt_table[] = {
3007a7930ed4SKuninori Morimoto 		{ "i2s",	SND_SOC_DAIFMT_I2S },
3008a7930ed4SKuninori Morimoto 		{ "right_j",	SND_SOC_DAIFMT_RIGHT_J },
3009a7930ed4SKuninori Morimoto 		{ "left_j",	SND_SOC_DAIFMT_LEFT_J },
3010a7930ed4SKuninori Morimoto 		{ "dsp_a",	SND_SOC_DAIFMT_DSP_A },
3011a7930ed4SKuninori Morimoto 		{ "dsp_b",	SND_SOC_DAIFMT_DSP_B },
3012a7930ed4SKuninori Morimoto 		{ "ac97",	SND_SOC_DAIFMT_AC97 },
3013a7930ed4SKuninori Morimoto 		{ "pdm",	SND_SOC_DAIFMT_PDM},
3014a7930ed4SKuninori Morimoto 		{ "msb",	SND_SOC_DAIFMT_MSB },
3015a7930ed4SKuninori Morimoto 		{ "lsb",	SND_SOC_DAIFMT_LSB },
3016a7930ed4SKuninori Morimoto 	};
3017a7930ed4SKuninori Morimoto 
3018a7930ed4SKuninori Morimoto 	if (!prefix)
3019a7930ed4SKuninori Morimoto 		prefix = "";
3020a7930ed4SKuninori Morimoto 
3021a7930ed4SKuninori Morimoto 	/*
30225711c979SKuninori Morimoto 	 * check "dai-format = xxx"
30235711c979SKuninori Morimoto 	 * or    "[prefix]format = xxx"
3024a7930ed4SKuninori Morimoto 	 * SND_SOC_DAIFMT_FORMAT_MASK area
3025a7930ed4SKuninori Morimoto 	 */
30265711c979SKuninori Morimoto 	ret = of_property_read_string(np, "dai-format", &str);
30275711c979SKuninori Morimoto 	if (ret < 0) {
3028a7930ed4SKuninori Morimoto 		snprintf(prop, sizeof(prop), "%sformat", prefix);
3029a7930ed4SKuninori Morimoto 		ret = of_property_read_string(np, prop, &str);
30305711c979SKuninori Morimoto 	}
3031a7930ed4SKuninori Morimoto 	if (ret == 0) {
3032a7930ed4SKuninori Morimoto 		for (i = 0; i < ARRAY_SIZE(of_fmt_table); i++) {
3033a7930ed4SKuninori Morimoto 			if (strcmp(str, of_fmt_table[i].name) == 0) {
3034a7930ed4SKuninori Morimoto 				format |= of_fmt_table[i].val;
3035a7930ed4SKuninori Morimoto 				break;
3036a7930ed4SKuninori Morimoto 			}
3037a7930ed4SKuninori Morimoto 		}
3038a7930ed4SKuninori Morimoto 	}
3039a7930ed4SKuninori Morimoto 
3040a7930ed4SKuninori Morimoto 	/*
30418c2d6a9fSKuninori Morimoto 	 * check "[prefix]continuous-clock"
3042a7930ed4SKuninori Morimoto 	 * SND_SOC_DAIFMT_CLOCK_MASK area
3043a7930ed4SKuninori Morimoto 	 */
30448c2d6a9fSKuninori Morimoto 	snprintf(prop, sizeof(prop), "%scontinuous-clock", prefix);
304551930295SJulia Lawall 	if (of_property_read_bool(np, prop))
30468c2d6a9fSKuninori Morimoto 		format |= SND_SOC_DAIFMT_CONT;
30478c2d6a9fSKuninori Morimoto 	else
30488c2d6a9fSKuninori Morimoto 		format |= SND_SOC_DAIFMT_GATED;
3049a7930ed4SKuninori Morimoto 
3050a7930ed4SKuninori Morimoto 	/*
3051a7930ed4SKuninori Morimoto 	 * check "[prefix]bitclock-inversion"
3052a7930ed4SKuninori Morimoto 	 * check "[prefix]frame-inversion"
3053a7930ed4SKuninori Morimoto 	 * SND_SOC_DAIFMT_INV_MASK area
3054a7930ed4SKuninori Morimoto 	 */
3055a7930ed4SKuninori Morimoto 	snprintf(prop, sizeof(prop), "%sbitclock-inversion", prefix);
3056a7930ed4SKuninori Morimoto 	bit = !!of_get_property(np, prop, NULL);
3057a7930ed4SKuninori Morimoto 
3058a7930ed4SKuninori Morimoto 	snprintf(prop, sizeof(prop), "%sframe-inversion", prefix);
3059a7930ed4SKuninori Morimoto 	frame = !!of_get_property(np, prop, NULL);
3060a7930ed4SKuninori Morimoto 
3061a7930ed4SKuninori Morimoto 	switch ((bit << 4) + frame) {
3062a7930ed4SKuninori Morimoto 	case 0x11:
3063a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_IB_IF;
3064a7930ed4SKuninori Morimoto 		break;
3065a7930ed4SKuninori Morimoto 	case 0x10:
3066a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_IB_NF;
3067a7930ed4SKuninori Morimoto 		break;
3068a7930ed4SKuninori Morimoto 	case 0x01:
3069a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_NB_IF;
3070a7930ed4SKuninori Morimoto 		break;
3071a7930ed4SKuninori Morimoto 	default:
3072a7930ed4SKuninori Morimoto 		/* SND_SOC_DAIFMT_NB_NF is default */
3073a7930ed4SKuninori Morimoto 		break;
3074a7930ed4SKuninori Morimoto 	}
3075a7930ed4SKuninori Morimoto 
3076a7930ed4SKuninori Morimoto 	/*
3077a7930ed4SKuninori Morimoto 	 * check "[prefix]bitclock-master"
3078a7930ed4SKuninori Morimoto 	 * check "[prefix]frame-master"
3079a7930ed4SKuninori Morimoto 	 * SND_SOC_DAIFMT_MASTER_MASK area
3080a7930ed4SKuninori Morimoto 	 */
3081a7930ed4SKuninori Morimoto 	snprintf(prop, sizeof(prop), "%sbitclock-master", prefix);
3082a7930ed4SKuninori Morimoto 	bit = !!of_get_property(np, prop, NULL);
3083389cb834SJyri Sarha 	if (bit && bitclkmaster)
3084389cb834SJyri Sarha 		*bitclkmaster = of_parse_phandle(np, prop, 0);
3085a7930ed4SKuninori Morimoto 
3086a7930ed4SKuninori Morimoto 	snprintf(prop, sizeof(prop), "%sframe-master", prefix);
3087a7930ed4SKuninori Morimoto 	frame = !!of_get_property(np, prop, NULL);
3088389cb834SJyri Sarha 	if (frame && framemaster)
3089389cb834SJyri Sarha 		*framemaster = of_parse_phandle(np, prop, 0);
3090a7930ed4SKuninori Morimoto 
3091a7930ed4SKuninori Morimoto 	switch ((bit << 4) + frame) {
3092a7930ed4SKuninori Morimoto 	case 0x11:
3093a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_CBM_CFM;
3094a7930ed4SKuninori Morimoto 		break;
3095a7930ed4SKuninori Morimoto 	case 0x10:
3096a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_CBM_CFS;
3097a7930ed4SKuninori Morimoto 		break;
3098a7930ed4SKuninori Morimoto 	case 0x01:
3099a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_CBS_CFM;
3100a7930ed4SKuninori Morimoto 		break;
3101a7930ed4SKuninori Morimoto 	default:
3102a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_CBS_CFS;
3103a7930ed4SKuninori Morimoto 		break;
3104a7930ed4SKuninori Morimoto 	}
3105a7930ed4SKuninori Morimoto 
3106a7930ed4SKuninori Morimoto 	return format;
3107a7930ed4SKuninori Morimoto }
3108a7930ed4SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt);
3109a7930ed4SKuninori Morimoto 
3110a180e8b9SKuninori Morimoto int snd_soc_get_dai_id(struct device_node *ep)
3111a180e8b9SKuninori Morimoto {
311209d4cc03SKuninori Morimoto 	struct snd_soc_component *component;
3113c1e230f0SKuninori Morimoto 	struct snd_soc_dai_link_component dlc;
3114a180e8b9SKuninori Morimoto 	int ret;
3115a180e8b9SKuninori Morimoto 
3116c1e230f0SKuninori Morimoto 	dlc.of_node	= of_graph_get_port_parent(ep);
3117c1e230f0SKuninori Morimoto 	dlc.name	= NULL;
3118a180e8b9SKuninori Morimoto 	/*
3119a180e8b9SKuninori Morimoto 	 * For example HDMI case, HDMI has video/sound port,
3120a180e8b9SKuninori Morimoto 	 * but ALSA SoC needs sound port number only.
3121a180e8b9SKuninori Morimoto 	 * Thus counting HDMI DT port/endpoint doesn't work.
3122a180e8b9SKuninori Morimoto 	 * Then, it should have .of_xlate_dai_id
3123a180e8b9SKuninori Morimoto 	 */
3124a180e8b9SKuninori Morimoto 	ret = -ENOTSUPP;
3125a180e8b9SKuninori Morimoto 	mutex_lock(&client_mutex);
3126c1e230f0SKuninori Morimoto 	component = soc_find_component(&dlc);
31272c7b1704SKuninori Morimoto 	if (component)
31282c7b1704SKuninori Morimoto 		ret = snd_soc_component_of_xlate_dai_id(component, ep);
3129a180e8b9SKuninori Morimoto 	mutex_unlock(&client_mutex);
3130a180e8b9SKuninori Morimoto 
3131c1e230f0SKuninori Morimoto 	of_node_put(dlc.of_node);
3132c0a480d1STony Lindgren 
3133a180e8b9SKuninori Morimoto 	return ret;
3134a180e8b9SKuninori Morimoto }
3135a180e8b9SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_get_dai_id);
3136a180e8b9SKuninori Morimoto 
31371ad8ec53SKuninori Morimoto int snd_soc_get_dai_name(struct of_phandle_args *args,
3138cb470087SKuninori Morimoto 				const char **dai_name)
3139cb470087SKuninori Morimoto {
3140cb470087SKuninori Morimoto 	struct snd_soc_component *pos;
31413e0aa8d8SJyri Sarha 	struct device_node *component_of_node;
314293b0f3eeSJean-Francois Moine 	int ret = -EPROBE_DEFER;
3143cb470087SKuninori Morimoto 
3144cb470087SKuninori Morimoto 	mutex_lock(&client_mutex);
3145368dee94SKuninori Morimoto 	for_each_component(pos) {
3146c0834440SKuninori Morimoto 		component_of_node = soc_component_to_node(pos);
31473e0aa8d8SJyri Sarha 
31483e0aa8d8SJyri Sarha 		if (component_of_node != args->np)
3149cb470087SKuninori Morimoto 			continue;
3150cb470087SKuninori Morimoto 
3151a2a34175SKuninori Morimoto 		ret = snd_soc_component_of_xlate_dai_name(pos, args, dai_name);
3152a2a34175SKuninori Morimoto 		if (ret == -ENOTSUPP) {
315358bf4179SKuninori Morimoto 			struct snd_soc_dai *dai;
31546833c452SKuninori Morimoto 			int id = -1;
31556833c452SKuninori Morimoto 
315693b0f3eeSJean-Francois Moine 			switch (args->args_count) {
31576833c452SKuninori Morimoto 			case 0:
31586833c452SKuninori Morimoto 				id = 0; /* same as dai_drv[0] */
31596833c452SKuninori Morimoto 				break;
31606833c452SKuninori Morimoto 			case 1:
316193b0f3eeSJean-Francois Moine 				id = args->args[0];
31626833c452SKuninori Morimoto 				break;
31636833c452SKuninori Morimoto 			default:
31646833c452SKuninori Morimoto 				/* not supported */
3165cb470087SKuninori Morimoto 				break;
3166cb470087SKuninori Morimoto 			}
3167cb470087SKuninori Morimoto 
31686833c452SKuninori Morimoto 			if (id < 0 || id >= pos->num_dai) {
31696833c452SKuninori Morimoto 				ret = -EINVAL;
31703dcba280SNicolin Chen 				continue;
31716833c452SKuninori Morimoto 			}
3172e41975edSXiubo Li 
3173e41975edSXiubo Li 			ret = 0;
3174e41975edSXiubo Li 
317558bf4179SKuninori Morimoto 			/* find target DAI */
317615a0c645SKuninori Morimoto 			for_each_component_dais(pos, dai) {
317758bf4179SKuninori Morimoto 				if (id == 0)
317858bf4179SKuninori Morimoto 					break;
317958bf4179SKuninori Morimoto 				id--;
318058bf4179SKuninori Morimoto 			}
318158bf4179SKuninori Morimoto 
318258bf4179SKuninori Morimoto 			*dai_name = dai->driver->name;
3183e41975edSXiubo Li 			if (!*dai_name)
3184e41975edSXiubo Li 				*dai_name = pos->name;
31856833c452SKuninori Morimoto 		}
31866833c452SKuninori Morimoto 
3187cb470087SKuninori Morimoto 		break;
3188cb470087SKuninori Morimoto 	}
3189cb470087SKuninori Morimoto 	mutex_unlock(&client_mutex);
319093b0f3eeSJean-Francois Moine 	return ret;
319193b0f3eeSJean-Francois Moine }
31921ad8ec53SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_get_dai_name);
319393b0f3eeSJean-Francois Moine 
319493b0f3eeSJean-Francois Moine int snd_soc_of_get_dai_name(struct device_node *of_node,
319593b0f3eeSJean-Francois Moine 			    const char **dai_name)
319693b0f3eeSJean-Francois Moine {
319793b0f3eeSJean-Francois Moine 	struct of_phandle_args args;
319893b0f3eeSJean-Francois Moine 	int ret;
319993b0f3eeSJean-Francois Moine 
320093b0f3eeSJean-Francois Moine 	ret = of_parse_phandle_with_args(of_node, "sound-dai",
320193b0f3eeSJean-Francois Moine 					 "#sound-dai-cells", 0, &args);
320293b0f3eeSJean-Francois Moine 	if (ret)
320393b0f3eeSJean-Francois Moine 		return ret;
320493b0f3eeSJean-Francois Moine 
320593b0f3eeSJean-Francois Moine 	ret = snd_soc_get_dai_name(&args, dai_name);
3206cb470087SKuninori Morimoto 
3207cb470087SKuninori Morimoto 	of_node_put(args.np);
3208cb470087SKuninori Morimoto 
3209cb470087SKuninori Morimoto 	return ret;
3210cb470087SKuninori Morimoto }
3211cb470087SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name);
3212cb470087SKuninori Morimoto 
321393b0f3eeSJean-Francois Moine /*
321494685763SSylwester Nawrocki  * snd_soc_of_put_dai_link_codecs - Dereference device nodes in the codecs array
321594685763SSylwester Nawrocki  * @dai_link: DAI link
321694685763SSylwester Nawrocki  *
321794685763SSylwester Nawrocki  * Dereference device nodes acquired by snd_soc_of_get_dai_link_codecs().
321894685763SSylwester Nawrocki  */
321994685763SSylwester Nawrocki void snd_soc_of_put_dai_link_codecs(struct snd_soc_dai_link *dai_link)
322094685763SSylwester Nawrocki {
32213db769f1SKuninori Morimoto 	struct snd_soc_dai_link_component *component;
322294685763SSylwester Nawrocki 	int index;
322394685763SSylwester Nawrocki 
32243db769f1SKuninori Morimoto 	for_each_link_codecs(dai_link, index, component) {
322594685763SSylwester Nawrocki 		if (!component->of_node)
322694685763SSylwester Nawrocki 			break;
322794685763SSylwester Nawrocki 		of_node_put(component->of_node);
322894685763SSylwester Nawrocki 		component->of_node = NULL;
322994685763SSylwester Nawrocki 	}
323094685763SSylwester Nawrocki }
323194685763SSylwester Nawrocki EXPORT_SYMBOL_GPL(snd_soc_of_put_dai_link_codecs);
323294685763SSylwester Nawrocki 
323394685763SSylwester Nawrocki /*
323493b0f3eeSJean-Francois Moine  * snd_soc_of_get_dai_link_codecs - Parse a list of CODECs in the devicetree
323593b0f3eeSJean-Francois Moine  * @dev: Card device
323693b0f3eeSJean-Francois Moine  * @of_node: Device node
323793b0f3eeSJean-Francois Moine  * @dai_link: DAI link
323893b0f3eeSJean-Francois Moine  *
323993b0f3eeSJean-Francois Moine  * Builds an array of CODEC DAI components from the DAI link property
324093b0f3eeSJean-Francois Moine  * 'sound-dai'.
324193b0f3eeSJean-Francois Moine  * The array is set in the DAI link and the number of DAIs is set accordingly.
324294685763SSylwester Nawrocki  * The device nodes in the array (of_node) must be dereferenced by calling
324394685763SSylwester Nawrocki  * snd_soc_of_put_dai_link_codecs() on @dai_link.
324493b0f3eeSJean-Francois Moine  *
324593b0f3eeSJean-Francois Moine  * Returns 0 for success
324693b0f3eeSJean-Francois Moine  */
324793b0f3eeSJean-Francois Moine int snd_soc_of_get_dai_link_codecs(struct device *dev,
324893b0f3eeSJean-Francois Moine 				   struct device_node *of_node,
324993b0f3eeSJean-Francois Moine 				   struct snd_soc_dai_link *dai_link)
325093b0f3eeSJean-Francois Moine {
325193b0f3eeSJean-Francois Moine 	struct of_phandle_args args;
325293b0f3eeSJean-Francois Moine 	struct snd_soc_dai_link_component *component;
325393b0f3eeSJean-Francois Moine 	char *name;
325493b0f3eeSJean-Francois Moine 	int index, num_codecs, ret;
325593b0f3eeSJean-Francois Moine 
325693b0f3eeSJean-Francois Moine 	/* Count the number of CODECs */
325793b0f3eeSJean-Francois Moine 	name = "sound-dai";
325893b0f3eeSJean-Francois Moine 	num_codecs = of_count_phandle_with_args(of_node, name,
325993b0f3eeSJean-Francois Moine 						"#sound-dai-cells");
326093b0f3eeSJean-Francois Moine 	if (num_codecs <= 0) {
326193b0f3eeSJean-Francois Moine 		if (num_codecs == -ENOENT)
326293b0f3eeSJean-Francois Moine 			dev_err(dev, "No 'sound-dai' property\n");
326393b0f3eeSJean-Francois Moine 		else
326493b0f3eeSJean-Francois Moine 			dev_err(dev, "Bad phandle in 'sound-dai'\n");
326593b0f3eeSJean-Francois Moine 		return num_codecs;
326693b0f3eeSJean-Francois Moine 	}
3267a86854d0SKees Cook 	component = devm_kcalloc(dev,
3268a86854d0SKees Cook 				 num_codecs, sizeof(*component),
326993b0f3eeSJean-Francois Moine 				 GFP_KERNEL);
327093b0f3eeSJean-Francois Moine 	if (!component)
327193b0f3eeSJean-Francois Moine 		return -ENOMEM;
327293b0f3eeSJean-Francois Moine 	dai_link->codecs = component;
327393b0f3eeSJean-Francois Moine 	dai_link->num_codecs = num_codecs;
327493b0f3eeSJean-Francois Moine 
327593b0f3eeSJean-Francois Moine 	/* Parse the list */
32763db769f1SKuninori Morimoto 	for_each_link_codecs(dai_link, index, component) {
327793b0f3eeSJean-Francois Moine 		ret = of_parse_phandle_with_args(of_node, name,
327893b0f3eeSJean-Francois Moine 						 "#sound-dai-cells",
327993b0f3eeSJean-Francois Moine 						 index, &args);
328093b0f3eeSJean-Francois Moine 		if (ret)
328193b0f3eeSJean-Francois Moine 			goto err;
328293b0f3eeSJean-Francois Moine 		component->of_node = args.np;
328393b0f3eeSJean-Francois Moine 		ret = snd_soc_get_dai_name(&args, &component->dai_name);
328493b0f3eeSJean-Francois Moine 		if (ret < 0)
328593b0f3eeSJean-Francois Moine 			goto err;
328693b0f3eeSJean-Francois Moine 	}
328793b0f3eeSJean-Francois Moine 	return 0;
328893b0f3eeSJean-Francois Moine err:
328994685763SSylwester Nawrocki 	snd_soc_of_put_dai_link_codecs(dai_link);
329093b0f3eeSJean-Francois Moine 	dai_link->codecs = NULL;
329193b0f3eeSJean-Francois Moine 	dai_link->num_codecs = 0;
329293b0f3eeSJean-Francois Moine 	return ret;
329393b0f3eeSJean-Francois Moine }
329493b0f3eeSJean-Francois Moine EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_link_codecs);
329593b0f3eeSJean-Francois Moine 
3296c9b3a40fSTakashi Iwai static int __init snd_soc_init(void)
3297db2a4165SFrank Mandarino {
32986553bf06SLars-Peter Clausen 	snd_soc_debugfs_init();
3299fb257897SMark Brown 	snd_soc_util_init();
3300fb257897SMark Brown 
3301db2a4165SFrank Mandarino 	return platform_driver_register(&soc_driver);
3302db2a4165SFrank Mandarino }
33034abe8e16SMark Brown module_init(snd_soc_init);
3304db2a4165SFrank Mandarino 
33057d8c16a6SMark Brown static void __exit snd_soc_exit(void)
3306db2a4165SFrank Mandarino {
3307fb257897SMark Brown 	snd_soc_util_exit();
33086553bf06SLars-Peter Clausen 	snd_soc_debugfs_exit();
3309fb257897SMark Brown 
3310db2a4165SFrank Mandarino 	platform_driver_unregister(&soc_driver);
3311db2a4165SFrank Mandarino }
3312db2a4165SFrank Mandarino module_exit(snd_soc_exit);
3313db2a4165SFrank Mandarino 
3314db2a4165SFrank Mandarino /* Module information */
3315d331124dSLiam Girdwood MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
3316db2a4165SFrank Mandarino MODULE_DESCRIPTION("ALSA SoC Core");
3317db2a4165SFrank Mandarino MODULE_LICENSE("GPL");
33188b45a209SKay Sievers MODULE_ALIAS("platform:soc-audio");
3319