xref: /openbmc/linux/sound/soc/soc-core.c (revision 2eda3cb108b699a6ff78a87e25143c153bc88e41)
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);
55c5af3a2eSMark Brown 
56db2a4165SFrank Mandarino /*
57db2a4165SFrank Mandarino  * This is a timeout to do a DAPM powerdown after a stream is closed().
58db2a4165SFrank Mandarino  * It can be used to eliminate pops between different playback streams, e.g.
59db2a4165SFrank Mandarino  * between two audio tracks.
60db2a4165SFrank Mandarino  */
61db2a4165SFrank Mandarino static int pmdown_time = 5000;
62db2a4165SFrank Mandarino module_param(pmdown_time, int, 0);
63db2a4165SFrank Mandarino MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)");
64db2a4165SFrank Mandarino 
6598faf436SMengdong Lin /* If a DMI filed contain strings in this blacklist (e.g.
6698faf436SMengdong Lin  * "Type2 - Board Manufacturer" or  "Type1 - TBD by OEM"), it will be taken
6798faf436SMengdong Lin  * as invalid and dropped when setting the card long name from DMI info.
6898faf436SMengdong Lin  */
6998faf436SMengdong Lin static const char * const dmi_blacklist[] = {
7098faf436SMengdong Lin 	"To be filled by OEM",
7198faf436SMengdong Lin 	"TBD by OEM",
7298faf436SMengdong Lin 	"Default String",
7398faf436SMengdong Lin 	"Board Manufacturer",
7498faf436SMengdong Lin 	"Board Vendor Name",
7598faf436SMengdong Lin 	"Board Product Name",
7698faf436SMengdong Lin 	NULL,	/* terminator */
7798faf436SMengdong Lin };
7898faf436SMengdong Lin 
79dbe21408SMark Brown static ssize_t pmdown_time_show(struct device *dev,
80dbe21408SMark Brown 				struct device_attribute *attr, char *buf)
81dbe21408SMark Brown {
8236ae1a96SMark Brown 	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
83dbe21408SMark Brown 
84f0fba2adSLiam Girdwood 	return sprintf(buf, "%ld\n", rtd->pmdown_time);
85dbe21408SMark Brown }
86dbe21408SMark Brown 
87dbe21408SMark Brown static ssize_t pmdown_time_set(struct device *dev,
88dbe21408SMark Brown 			       struct device_attribute *attr,
89dbe21408SMark Brown 			       const char *buf, size_t count)
90dbe21408SMark Brown {
9136ae1a96SMark Brown 	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
92c593b520SMark Brown 	int ret;
93dbe21408SMark Brown 
94b785a492SJingoo Han 	ret = kstrtol(buf, 10, &rtd->pmdown_time);
95c593b520SMark Brown 	if (ret)
96c593b520SMark Brown 		return ret;
97dbe21408SMark Brown 
98dbe21408SMark Brown 	return count;
99dbe21408SMark Brown }
100dbe21408SMark Brown 
101dbe21408SMark Brown static DEVICE_ATTR(pmdown_time, 0644, pmdown_time_show, pmdown_time_set);
102dbe21408SMark Brown 
103d29697dcSTakashi Iwai static struct attribute *soc_dev_attrs[] = {
104d29697dcSTakashi Iwai 	&dev_attr_pmdown_time.attr,
105d29697dcSTakashi Iwai 	NULL
106d29697dcSTakashi Iwai };
107d29697dcSTakashi Iwai 
108d29697dcSTakashi Iwai static umode_t soc_dev_attr_is_visible(struct kobject *kobj,
109d29697dcSTakashi Iwai 				       struct attribute *attr, int idx)
110d29697dcSTakashi Iwai {
111d29697dcSTakashi Iwai 	struct device *dev = kobj_to_dev(kobj);
112d29697dcSTakashi Iwai 	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
113d29697dcSTakashi Iwai 
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 	if (!component->debugfs_root) {
15781c7cfd1SLars-Peter Clausen 		dev_warn(component->dev,
15881c7cfd1SLars-Peter Clausen 			"ASoC: Failed to create component debugfs directory\n");
1592624d5faSMark Brown 		return;
1602624d5faSMark Brown 	}
1612624d5faSMark Brown 
16281c7cfd1SLars-Peter Clausen 	snd_soc_dapm_debugfs_init(snd_soc_component_get_dapm(component),
16381c7cfd1SLars-Peter Clausen 		component->debugfs_root);
16481c7cfd1SLars-Peter Clausen }
16581c7cfd1SLars-Peter Clausen 
16681c7cfd1SLars-Peter Clausen static void soc_cleanup_component_debugfs(struct snd_soc_component *component)
16781c7cfd1SLars-Peter Clausen {
16881c7cfd1SLars-Peter Clausen 	debugfs_remove_recursive(component->debugfs_root);
16981c7cfd1SLars-Peter Clausen }
17081c7cfd1SLars-Peter Clausen 
171c15b2a1dSPeng Donglin static int dai_list_show(struct seq_file *m, void *v)
172f3208780SMark Brown {
1731438c2f6SLars-Peter Clausen 	struct snd_soc_component *component;
174f3208780SMark Brown 	struct snd_soc_dai *dai;
175f3208780SMark Brown 
17634e81ab4SLars-Peter Clausen 	mutex_lock(&client_mutex);
17734e81ab4SLars-Peter Clausen 
178700c17caSDonglin Peng 	list_for_each_entry(component, &component_list, list)
179700c17caSDonglin Peng 		list_for_each_entry(dai, &component->dai_list, list)
180700c17caSDonglin Peng 			seq_printf(m, "%s\n", dai->name);
181f3208780SMark Brown 
18234e81ab4SLars-Peter Clausen 	mutex_unlock(&client_mutex);
18334e81ab4SLars-Peter Clausen 
184700c17caSDonglin Peng 	return 0;
185700c17caSDonglin Peng }
186c15b2a1dSPeng Donglin DEFINE_SHOW_ATTRIBUTE(dai_list);
187f3208780SMark Brown 
188db795f9bSKuninori Morimoto static int component_list_show(struct seq_file *m, void *v)
189db795f9bSKuninori Morimoto {
190db795f9bSKuninori Morimoto 	struct snd_soc_component *component;
191db795f9bSKuninori Morimoto 
192db795f9bSKuninori Morimoto 	mutex_lock(&client_mutex);
193db795f9bSKuninori Morimoto 
194db795f9bSKuninori Morimoto 	list_for_each_entry(component, &component_list, list)
195db795f9bSKuninori Morimoto 		seq_printf(m, "%s\n", component->name);
196db795f9bSKuninori Morimoto 
197db795f9bSKuninori Morimoto 	mutex_unlock(&client_mutex);
198db795f9bSKuninori Morimoto 
199db795f9bSKuninori Morimoto 	return 0;
200db795f9bSKuninori Morimoto }
201db795f9bSKuninori Morimoto DEFINE_SHOW_ATTRIBUTE(component_list);
202db795f9bSKuninori Morimoto 
203a6052154SJarkko Nikula static void soc_init_card_debugfs(struct snd_soc_card *card)
204a6052154SJarkko Nikula {
2056553bf06SLars-Peter Clausen 	if (!snd_soc_debugfs_root)
2066553bf06SLars-Peter Clausen 		return;
2076553bf06SLars-Peter Clausen 
208a6052154SJarkko Nikula 	card->debugfs_card_root = debugfs_create_dir(card->name,
2098a9dab1aSMark Brown 						     snd_soc_debugfs_root);
2103a45b867SJarkko Nikula 	if (!card->debugfs_card_root) {
211a6052154SJarkko Nikula 		dev_warn(card->dev,
2127c08be84SLothar Waßmann 			 "ASoC: Failed to create card debugfs directory\n");
2133a45b867SJarkko Nikula 		return;
2143a45b867SJarkko Nikula 	}
2153a45b867SJarkko Nikula 
2163a45b867SJarkko Nikula 	card->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0644,
2173a45b867SJarkko Nikula 						    card->debugfs_card_root,
2183a45b867SJarkko Nikula 						    &card->pop_time);
2193a45b867SJarkko Nikula 	if (!card->debugfs_pop_time)
2203a45b867SJarkko Nikula 		dev_warn(card->dev,
221f110bfc7SLiam Girdwood 		       "ASoC: Failed to create pop time debugfs file\n");
222a6052154SJarkko Nikula }
223a6052154SJarkko Nikula 
224a6052154SJarkko Nikula static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
225a6052154SJarkko Nikula {
226a6052154SJarkko Nikula 	debugfs_remove_recursive(card->debugfs_card_root);
227a6052154SJarkko Nikula }
228a6052154SJarkko Nikula 
2296553bf06SLars-Peter Clausen static void snd_soc_debugfs_init(void)
2306553bf06SLars-Peter Clausen {
2316553bf06SLars-Peter Clausen 	snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL);
232d9a02c55SFabio Estevam 	if (IS_ERR_OR_NULL(snd_soc_debugfs_root)) {
2336553bf06SLars-Peter Clausen 		pr_warn("ASoC: Failed to create debugfs directory\n");
2346553bf06SLars-Peter Clausen 		snd_soc_debugfs_root = NULL;
2356553bf06SLars-Peter Clausen 		return;
2366553bf06SLars-Peter Clausen 	}
2376553bf06SLars-Peter Clausen 
2386553bf06SLars-Peter Clausen 	if (!debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL,
2396553bf06SLars-Peter Clausen 				 &dai_list_fops))
2406553bf06SLars-Peter Clausen 		pr_warn("ASoC: Failed to create DAI list debugfs file\n");
241db795f9bSKuninori Morimoto 
242db795f9bSKuninori Morimoto 	if (!debugfs_create_file("components", 0444, snd_soc_debugfs_root, NULL,
243db795f9bSKuninori Morimoto 				 &component_list_fops))
244db795f9bSKuninori Morimoto 		pr_warn("ASoC: Failed to create component list debugfs file\n");
2456553bf06SLars-Peter Clausen }
2466553bf06SLars-Peter Clausen 
2476553bf06SLars-Peter Clausen static void snd_soc_debugfs_exit(void)
2486553bf06SLars-Peter Clausen {
2496553bf06SLars-Peter Clausen 	debugfs_remove_recursive(snd_soc_debugfs_root);
2506553bf06SLars-Peter Clausen }
2516553bf06SLars-Peter Clausen 
2522624d5faSMark Brown #else
2532624d5faSMark Brown 
25481c7cfd1SLars-Peter Clausen static inline void soc_init_component_debugfs(
25581c7cfd1SLars-Peter Clausen 	struct snd_soc_component *component)
2562624d5faSMark Brown {
2572624d5faSMark Brown }
2582624d5faSMark Brown 
25981c7cfd1SLars-Peter Clausen static inline void soc_cleanup_component_debugfs(
26081c7cfd1SLars-Peter Clausen 	struct snd_soc_component *component)
261731f1ab2SSebastien Guiriec {
262731f1ab2SSebastien Guiriec }
263731f1ab2SSebastien Guiriec 
264b95fccbcSAxel Lin static inline void soc_init_card_debugfs(struct snd_soc_card *card)
265b95fccbcSAxel Lin {
266b95fccbcSAxel Lin }
267b95fccbcSAxel Lin 
268b95fccbcSAxel Lin static inline void soc_cleanup_card_debugfs(struct snd_soc_card *card)
269b95fccbcSAxel Lin {
270b95fccbcSAxel Lin }
2716553bf06SLars-Peter Clausen 
2726553bf06SLars-Peter Clausen static inline void snd_soc_debugfs_init(void)
2736553bf06SLars-Peter Clausen {
2746553bf06SLars-Peter Clausen }
2756553bf06SLars-Peter Clausen 
2766553bf06SLars-Peter Clausen static inline void snd_soc_debugfs_exit(void)
2776553bf06SLars-Peter Clausen {
2786553bf06SLars-Peter Clausen }
2796553bf06SLars-Peter Clausen 
2802624d5faSMark Brown #endif
2812624d5faSMark Brown 
282a0ac4411SKuninori Morimoto static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd,
283a0ac4411SKuninori Morimoto 			      struct snd_soc_component *component)
284a0ac4411SKuninori Morimoto {
285a0ac4411SKuninori Morimoto 	struct snd_soc_rtdcom_list *rtdcom;
286a0ac4411SKuninori Morimoto 	struct snd_soc_rtdcom_list *new_rtdcom;
287a0ac4411SKuninori Morimoto 
288a0ac4411SKuninori Morimoto 	for_each_rtdcom(rtd, rtdcom) {
289a0ac4411SKuninori Morimoto 		/* already connected */
290a0ac4411SKuninori Morimoto 		if (rtdcom->component == component)
291a0ac4411SKuninori Morimoto 			return 0;
292a0ac4411SKuninori Morimoto 	}
293a0ac4411SKuninori Morimoto 
294a0ac4411SKuninori Morimoto 	new_rtdcom = kmalloc(sizeof(*new_rtdcom), GFP_KERNEL);
295a0ac4411SKuninori Morimoto 	if (!new_rtdcom)
296a0ac4411SKuninori Morimoto 		return -ENOMEM;
297a0ac4411SKuninori Morimoto 
298a0ac4411SKuninori Morimoto 	new_rtdcom->component = component;
299a0ac4411SKuninori Morimoto 	INIT_LIST_HEAD(&new_rtdcom->list);
300a0ac4411SKuninori Morimoto 
301a0ac4411SKuninori Morimoto 	list_add_tail(&new_rtdcom->list, &rtd->component_list);
302a0ac4411SKuninori Morimoto 
303a0ac4411SKuninori Morimoto 	return 0;
304a0ac4411SKuninori Morimoto }
305a0ac4411SKuninori Morimoto 
306a0ac4411SKuninori Morimoto static void snd_soc_rtdcom_del_all(struct snd_soc_pcm_runtime *rtd)
307a0ac4411SKuninori Morimoto {
308a0ac4411SKuninori Morimoto 	struct snd_soc_rtdcom_list *rtdcom1, *rtdcom2;
309a0ac4411SKuninori Morimoto 
310a0ac4411SKuninori Morimoto 	for_each_rtdcom_safe(rtd, rtdcom1, rtdcom2)
311a0ac4411SKuninori Morimoto 		kfree(rtdcom1);
312a0ac4411SKuninori Morimoto 
313a0ac4411SKuninori Morimoto 	INIT_LIST_HEAD(&rtd->component_list);
314a0ac4411SKuninori Morimoto }
315a0ac4411SKuninori Morimoto 
316a0ac4411SKuninori Morimoto struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd,
317a0ac4411SKuninori Morimoto 						const char *driver_name)
318a0ac4411SKuninori Morimoto {
319a0ac4411SKuninori Morimoto 	struct snd_soc_rtdcom_list *rtdcom;
320a0ac4411SKuninori Morimoto 
321971da24cSKuninori Morimoto 	if (!driver_name)
322971da24cSKuninori Morimoto 		return NULL;
323971da24cSKuninori Morimoto 
324a0ac4411SKuninori Morimoto 	for_each_rtdcom(rtd, rtdcom) {
325971da24cSKuninori Morimoto 		const char *component_name = rtdcom->component->driver->name;
326971da24cSKuninori Morimoto 
327971da24cSKuninori Morimoto 		if (!component_name)
328971da24cSKuninori Morimoto 			continue;
329971da24cSKuninori Morimoto 
330971da24cSKuninori Morimoto 		if ((component_name == driver_name) ||
331971da24cSKuninori Morimoto 		    strcmp(component_name, driver_name) == 0)
332a0ac4411SKuninori Morimoto 			return rtdcom->component;
333a0ac4411SKuninori Morimoto 	}
334a0ac4411SKuninori Morimoto 
335a0ac4411SKuninori Morimoto 	return NULL;
336a0ac4411SKuninori Morimoto }
337031734b7SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_rtdcom_lookup);
338a0ac4411SKuninori Morimoto 
33947c88fffSLiam Girdwood struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
34047c88fffSLiam Girdwood 		const char *dai_link, int stream)
34147c88fffSLiam Girdwood {
3421a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
34347c88fffSLiam Girdwood 
3441a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
3451a497983SMengdong Lin 		if (rtd->dai_link->no_pcm &&
3461a497983SMengdong Lin 			!strcmp(rtd->dai_link->name, dai_link))
3471a497983SMengdong Lin 			return rtd->pcm->streams[stream].substream;
34847c88fffSLiam Girdwood 	}
349f110bfc7SLiam Girdwood 	dev_dbg(card->dev, "ASoC: failed to find dai link %s\n", dai_link);
35047c88fffSLiam Girdwood 	return NULL;
35147c88fffSLiam Girdwood }
35247c88fffSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream);
35347c88fffSLiam Girdwood 
35475ab9eb6SKuninori Morimoto static const struct snd_soc_ops null_snd_soc_ops;
35575ab9eb6SKuninori Morimoto 
3561a497983SMengdong Lin static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
3571a497983SMengdong Lin 	struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
3581a497983SMengdong Lin {
3591a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
3601a497983SMengdong Lin 
3611a497983SMengdong Lin 	rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL);
3621a497983SMengdong Lin 	if (!rtd)
3631a497983SMengdong Lin 		return NULL;
3641a497983SMengdong Lin 
365a0ac4411SKuninori Morimoto 	INIT_LIST_HEAD(&rtd->component_list);
3661a497983SMengdong Lin 	rtd->card = card;
3671a497983SMengdong Lin 	rtd->dai_link = dai_link;
36875ab9eb6SKuninori Morimoto 	if (!rtd->dai_link->ops)
36975ab9eb6SKuninori Morimoto 		rtd->dai_link->ops = &null_snd_soc_ops;
37075ab9eb6SKuninori Morimoto 
3716396bb22SKees Cook 	rtd->codec_dais = kcalloc(dai_link->num_codecs,
3726396bb22SKees Cook 					sizeof(struct snd_soc_dai *),
3731a497983SMengdong Lin 					GFP_KERNEL);
3741a497983SMengdong Lin 	if (!rtd->codec_dais) {
3751a497983SMengdong Lin 		kfree(rtd);
3761a497983SMengdong Lin 		return NULL;
3771a497983SMengdong Lin 	}
3781a497983SMengdong Lin 
3791a497983SMengdong Lin 	return rtd;
3801a497983SMengdong Lin }
3811a497983SMengdong Lin 
3821a497983SMengdong Lin static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd)
3831a497983SMengdong Lin {
3841a497983SMengdong Lin 	kfree(rtd->codec_dais);
385a0ac4411SKuninori Morimoto 	snd_soc_rtdcom_del_all(rtd);
3861a497983SMengdong Lin 	kfree(rtd);
3871a497983SMengdong Lin }
3881a497983SMengdong Lin 
3891a497983SMengdong Lin static void soc_add_pcm_runtime(struct snd_soc_card *card,
3901a497983SMengdong Lin 		struct snd_soc_pcm_runtime *rtd)
3911a497983SMengdong Lin {
3921a497983SMengdong Lin 	list_add_tail(&rtd->list, &card->rtd_list);
3931a497983SMengdong Lin 	rtd->num = card->num_rtd;
3941a497983SMengdong Lin 	card->num_rtd++;
3951a497983SMengdong Lin }
3961a497983SMengdong Lin 
3971a497983SMengdong Lin static void soc_remove_pcm_runtimes(struct snd_soc_card *card)
3981a497983SMengdong Lin {
3991a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd, *_rtd;
4001a497983SMengdong Lin 
4011a497983SMengdong Lin 	list_for_each_entry_safe(rtd, _rtd, &card->rtd_list, list) {
4021a497983SMengdong Lin 		list_del(&rtd->list);
4031a497983SMengdong Lin 		soc_free_pcm_runtime(rtd);
4041a497983SMengdong Lin 	}
4051a497983SMengdong Lin 
4061a497983SMengdong Lin 	card->num_rtd = 0;
4071a497983SMengdong Lin }
4081a497983SMengdong Lin 
40947c88fffSLiam Girdwood struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
41047c88fffSLiam Girdwood 		const char *dai_link)
41147c88fffSLiam Girdwood {
4121a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
41347c88fffSLiam Girdwood 
4141a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
4151a497983SMengdong Lin 		if (!strcmp(rtd->dai_link->name, dai_link))
4161a497983SMengdong Lin 			return rtd;
41747c88fffSLiam Girdwood 	}
418f110bfc7SLiam Girdwood 	dev_dbg(card->dev, "ASoC: failed to find rtd %s\n", dai_link);
41947c88fffSLiam Girdwood 	return NULL;
42047c88fffSLiam Girdwood }
42147c88fffSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime);
42247c88fffSLiam Girdwood 
4239d58a077SRichard Fitzgerald static void codec2codec_close_delayed_work(struct work_struct *work)
4249d58a077SRichard Fitzgerald {
4259d58a077SRichard Fitzgerald 	/* Currently nothing to do for c2c links
4269d58a077SRichard Fitzgerald 	 * Since c2c links are internal nodes in the DAPM graph and
4279d58a077SRichard Fitzgerald 	 * don't interface with the outside world or application layer
4289d58a077SRichard Fitzgerald 	 * we don't have to do any special handling on close.
4299d58a077SRichard Fitzgerald 	 */
4309d58a077SRichard Fitzgerald }
4319d58a077SRichard Fitzgerald 
4326f8ab4acSMark Brown #ifdef CONFIG_PM_SLEEP
433db2a4165SFrank Mandarino /* powers down audio subsystem for suspend */
4346f8ab4acSMark Brown int snd_soc_suspend(struct device *dev)
435db2a4165SFrank Mandarino {
4366f8ab4acSMark Brown 	struct snd_soc_card *card = dev_get_drvdata(dev);
437d9fc4063SKuninori Morimoto 	struct snd_soc_component *component;
4381a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
4391a497983SMengdong Lin 	int i;
440db2a4165SFrank Mandarino 
441c5599b87SLars-Peter Clausen 	/* If the card is not initialized yet there is nothing to do */
442c5599b87SLars-Peter Clausen 	if (!card->instantiated)
443e3509ff0SDaniel Mack 		return 0;
444e3509ff0SDaniel Mack 
4456ed25978SAndy Green 	/* Due to the resume being scheduled into a workqueue we could
4466ed25978SAndy Green 	* suspend before that's finished - wait for it to complete.
4476ed25978SAndy Green 	 */
448f0fba2adSLiam Girdwood 	snd_power_wait(card->snd_card, SNDRV_CTL_POWER_D0);
4496ed25978SAndy Green 
4506ed25978SAndy Green 	/* we're going to block userspace touching us until resume completes */
451f0fba2adSLiam Girdwood 	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
4526ed25978SAndy Green 
453a00f90f9SMark Brown 	/* mute any active DACs */
4541a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
4550b7990e3SKuninori Morimoto 		struct snd_soc_dai *dai;
4563efab7dcSMark Brown 
4571a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
4583efab7dcSMark Brown 			continue;
4593efab7dcSMark Brown 
4600b7990e3SKuninori Morimoto 		for_each_rtd_codec_dai(rtd, i, dai) {
46188bd870fSBenoit Cousson 			struct snd_soc_dai_driver *drv = dai->driver;
46288bd870fSBenoit Cousson 
463f0fba2adSLiam Girdwood 			if (drv->ops->digital_mute && dai->playback_active)
464f0fba2adSLiam Girdwood 				drv->ops->digital_mute(dai, 1);
465db2a4165SFrank Mandarino 		}
46688bd870fSBenoit Cousson 	}
467db2a4165SFrank Mandarino 
4684ccab3e7SLiam Girdwood 	/* suspend all pcms */
4691a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
4701a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
4713efab7dcSMark Brown 			continue;
4723efab7dcSMark Brown 
4731a497983SMengdong Lin 		snd_pcm_suspend_all(rtd->pcm);
4743efab7dcSMark Brown 	}
4754ccab3e7SLiam Girdwood 
47687506549SMark Brown 	if (card->suspend_pre)
47770b2ac12SMark Brown 		card->suspend_pre(card);
478db2a4165SFrank Mandarino 
4791a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
4801a497983SMengdong Lin 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
4813efab7dcSMark Brown 
4821a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
4833efab7dcSMark Brown 			continue;
4843efab7dcSMark Brown 
485bc263214SLars-Peter Clausen 		if (cpu_dai->driver->suspend && !cpu_dai->driver->bus_control)
486f0fba2adSLiam Girdwood 			cpu_dai->driver->suspend(cpu_dai);
487db2a4165SFrank Mandarino 	}
488db2a4165SFrank Mandarino 
48937660b6dSLars-Peter Clausen 	/* close any waiting streams */
4901a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list)
4911a497983SMengdong Lin 		flush_delayed_work(&rtd->delayed_work);
492db2a4165SFrank Mandarino 
4931a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
4943efab7dcSMark Brown 
4951a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
4963efab7dcSMark Brown 			continue;
4973efab7dcSMark Brown 
4981a497983SMengdong Lin 		snd_soc_dapm_stream_event(rtd,
4997bd3a6f3SMark Brown 					  SNDRV_PCM_STREAM_PLAYBACK,
500db2a4165SFrank Mandarino 					  SND_SOC_DAPM_STREAM_SUSPEND);
501f0fba2adSLiam Girdwood 
5021a497983SMengdong Lin 		snd_soc_dapm_stream_event(rtd,
5037bd3a6f3SMark Brown 					  SNDRV_PCM_STREAM_CAPTURE,
504db2a4165SFrank Mandarino 					  SND_SOC_DAPM_STREAM_SUSPEND);
505db2a4165SFrank Mandarino 	}
506db2a4165SFrank Mandarino 
5078be4da29SLars-Peter Clausen 	/* Recheck all endpoints too, their state is affected by suspend */
5088be4da29SLars-Peter Clausen 	dapm_mark_endpoints_dirty(card);
509e2d32ff6SMark Brown 	snd_soc_dapm_sync(&card->dapm);
510e2d32ff6SMark Brown 
5119178feb4SKuninori Morimoto 	/* suspend all COMPONENTs */
512d9fc4063SKuninori Morimoto 	list_for_each_entry(component, &card->component_dev_list, card_list) {
513d9fc4063SKuninori Morimoto 		struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
514d9fc4063SKuninori Morimoto 
5159178feb4SKuninori Morimoto 		/* If there are paths active then the COMPONENT will be held with
5161547aba9SMark Brown 		 * bias _ON and should not be suspended. */
5179178feb4SKuninori Morimoto 		if (!component->suspended) {
5184890140fSLars-Peter Clausen 			switch (snd_soc_dapm_get_bias_level(dapm)) {
5191547aba9SMark Brown 			case SND_SOC_BIAS_STANDBY:
520125a25daSMark Brown 				/*
5219178feb4SKuninori Morimoto 				 * If the COMPONENT is capable of idle
522125a25daSMark Brown 				 * bias off then being in STANDBY
523125a25daSMark Brown 				 * means it's doing something,
524125a25daSMark Brown 				 * otherwise fall through.
525125a25daSMark Brown 				 */
5264890140fSLars-Peter Clausen 				if (dapm->idle_bias_off) {
5279178feb4SKuninori Morimoto 					dev_dbg(component->dev,
52810e8aa9aSMichał Mirosław 						"ASoC: idle_bias_off CODEC on over suspend\n");
529125a25daSMark Brown 					break;
530125a25daSMark Brown 				}
5311a12d5dcSGustavo A. R. Silva 				/* fall through */
532a8093297SLars-Peter Clausen 
5331547aba9SMark Brown 			case SND_SOC_BIAS_OFF:
534999f7f5aSKuninori Morimoto 				if (component->driver->suspend)
535999f7f5aSKuninori Morimoto 					component->driver->suspend(component);
5369178feb4SKuninori Morimoto 				component->suspended = 1;
5379178feb4SKuninori Morimoto 				if (component->regmap)
5389178feb4SKuninori Morimoto 					regcache_mark_dirty(component->regmap);
539988e8cc4SNicolin Chen 				/* deactivate pins to sleep state */
5409178feb4SKuninori Morimoto 				pinctrl_pm_select_sleep_state(component->dev);
5411547aba9SMark Brown 				break;
5421547aba9SMark Brown 			default:
5439178feb4SKuninori Morimoto 				dev_dbg(component->dev,
5449178feb4SKuninori Morimoto 					"ASoC: COMPONENT is on over suspend\n");
5451547aba9SMark Brown 				break;
5461547aba9SMark Brown 			}
5471547aba9SMark Brown 		}
548f0fba2adSLiam Girdwood 	}
549db2a4165SFrank Mandarino 
5501a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
5511a497983SMengdong Lin 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
5523efab7dcSMark Brown 
5531a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
5543efab7dcSMark Brown 			continue;
5553efab7dcSMark Brown 
556bc263214SLars-Peter Clausen 		if (cpu_dai->driver->suspend && cpu_dai->driver->bus_control)
557f0fba2adSLiam Girdwood 			cpu_dai->driver->suspend(cpu_dai);
558988e8cc4SNicolin Chen 
559988e8cc4SNicolin Chen 		/* deactivate pins to sleep state */
560988e8cc4SNicolin Chen 		pinctrl_pm_select_sleep_state(cpu_dai->dev);
561db2a4165SFrank Mandarino 	}
562db2a4165SFrank Mandarino 
56387506549SMark Brown 	if (card->suspend_post)
56470b2ac12SMark Brown 		card->suspend_post(card);
565db2a4165SFrank Mandarino 
566db2a4165SFrank Mandarino 	return 0;
567db2a4165SFrank Mandarino }
5686f8ab4acSMark Brown EXPORT_SYMBOL_GPL(snd_soc_suspend);
569db2a4165SFrank Mandarino 
5706ed25978SAndy Green /* deferred resume work, so resume can complete before we finished
5716ed25978SAndy Green  * setting our codec back up, which can be very slow on I2C
5726ed25978SAndy Green  */
5736ed25978SAndy Green static void soc_resume_deferred(struct work_struct *work)
574db2a4165SFrank Mandarino {
575f0fba2adSLiam Girdwood 	struct snd_soc_card *card =
576f0fba2adSLiam Girdwood 			container_of(work, struct snd_soc_card, deferred_resume_work);
5771a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
578d9fc4063SKuninori Morimoto 	struct snd_soc_component *component;
5791a497983SMengdong Lin 	int i;
580db2a4165SFrank Mandarino 
5816ed25978SAndy Green 	/* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
5826ed25978SAndy Green 	 * so userspace apps are blocked from touching us
5836ed25978SAndy Green 	 */
5846ed25978SAndy Green 
585f110bfc7SLiam Girdwood 	dev_dbg(card->dev, "ASoC: starting resume work\n");
5866ed25978SAndy Green 
5879949788bSMark Brown 	/* Bring us up into D2 so that DAPM starts enabling things */
588f0fba2adSLiam Girdwood 	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D2);
5899949788bSMark Brown 
59087506549SMark Brown 	if (card->resume_pre)
59170b2ac12SMark Brown 		card->resume_pre(card);
592db2a4165SFrank Mandarino 
593bc263214SLars-Peter Clausen 	/* resume control bus DAIs */
5941a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
5951a497983SMengdong Lin 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
5963efab7dcSMark Brown 
5971a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
5983efab7dcSMark Brown 			continue;
5993efab7dcSMark Brown 
600bc263214SLars-Peter Clausen 		if (cpu_dai->driver->resume && cpu_dai->driver->bus_control)
601f0fba2adSLiam Girdwood 			cpu_dai->driver->resume(cpu_dai);
602db2a4165SFrank Mandarino 	}
603db2a4165SFrank Mandarino 
604d9fc4063SKuninori Morimoto 	list_for_each_entry(component, &card->component_dev_list, card_list) {
6059178feb4SKuninori Morimoto 		if (component->suspended) {
606999f7f5aSKuninori Morimoto 			if (component->driver->resume)
607999f7f5aSKuninori Morimoto 				component->driver->resume(component);
6089178feb4SKuninori Morimoto 			component->suspended = 0;
6091547aba9SMark Brown 		}
610f0fba2adSLiam Girdwood 	}
611db2a4165SFrank Mandarino 
6121a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
6133efab7dcSMark Brown 
6141a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
6153efab7dcSMark Brown 			continue;
6163efab7dcSMark Brown 
6171a497983SMengdong Lin 		snd_soc_dapm_stream_event(rtd,
618d9b0951bSLiam Girdwood 					  SNDRV_PCM_STREAM_PLAYBACK,
619db2a4165SFrank Mandarino 					  SND_SOC_DAPM_STREAM_RESUME);
620f0fba2adSLiam Girdwood 
6211a497983SMengdong Lin 		snd_soc_dapm_stream_event(rtd,
622d9b0951bSLiam Girdwood 					  SNDRV_PCM_STREAM_CAPTURE,
623db2a4165SFrank Mandarino 					  SND_SOC_DAPM_STREAM_RESUME);
624db2a4165SFrank Mandarino 	}
625db2a4165SFrank Mandarino 
6263ff3f64bSMark Brown 	/* unmute any active DACs */
6271a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
6280b7990e3SKuninori Morimoto 		struct snd_soc_dai *dai;
6293efab7dcSMark Brown 
6301a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
6313efab7dcSMark Brown 			continue;
6323efab7dcSMark Brown 
6330b7990e3SKuninori Morimoto 		for_each_rtd_codec_dai(rtd, i, dai) {
63488bd870fSBenoit Cousson 			struct snd_soc_dai_driver *drv = dai->driver;
63588bd870fSBenoit Cousson 
636f0fba2adSLiam Girdwood 			if (drv->ops->digital_mute && dai->playback_active)
637f0fba2adSLiam Girdwood 				drv->ops->digital_mute(dai, 0);
638db2a4165SFrank Mandarino 		}
63988bd870fSBenoit Cousson 	}
640db2a4165SFrank Mandarino 
6411a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
6421a497983SMengdong Lin 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
6433efab7dcSMark Brown 
6441a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
6453efab7dcSMark Brown 			continue;
6463efab7dcSMark Brown 
647bc263214SLars-Peter Clausen 		if (cpu_dai->driver->resume && !cpu_dai->driver->bus_control)
648f0fba2adSLiam Girdwood 			cpu_dai->driver->resume(cpu_dai);
649db2a4165SFrank Mandarino 	}
650db2a4165SFrank Mandarino 
65187506549SMark Brown 	if (card->resume_post)
65270b2ac12SMark Brown 		card->resume_post(card);
653db2a4165SFrank Mandarino 
654f110bfc7SLiam Girdwood 	dev_dbg(card->dev, "ASoC: resume work completed\n");
6556ed25978SAndy Green 
6568be4da29SLars-Peter Clausen 	/* Recheck all endpoints too, their state is affected by suspend */
6578be4da29SLars-Peter Clausen 	dapm_mark_endpoints_dirty(card);
658e2d32ff6SMark Brown 	snd_soc_dapm_sync(&card->dapm);
6591a7aaa58SJeeja KP 
6601a7aaa58SJeeja KP 	/* userspace can access us now we are back as we were before */
6611a7aaa58SJeeja KP 	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0);
6626ed25978SAndy Green }
6636ed25978SAndy Green 
6646ed25978SAndy Green /* powers up audio subsystem after a suspend */
6656f8ab4acSMark Brown int snd_soc_resume(struct device *dev)
6666ed25978SAndy Green {
6676f8ab4acSMark Brown 	struct snd_soc_card *card = dev_get_drvdata(dev);
668bc263214SLars-Peter Clausen 	bool bus_control = false;
6691a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
670b9dd94a8SPeter Ujfalusi 
671c5599b87SLars-Peter Clausen 	/* If the card is not initialized yet there is nothing to do */
672c5599b87SLars-Peter Clausen 	if (!card->instantiated)
6735ff1ddf2SEric Miao 		return 0;
6745ff1ddf2SEric Miao 
675988e8cc4SNicolin Chen 	/* activate pins from sleep state */
6761a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
6770b7990e3SKuninori Morimoto 		struct snd_soc_dai *codec_dai;
67888bd870fSBenoit Cousson 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
67988bd870fSBenoit Cousson 		int j;
68088bd870fSBenoit Cousson 
681988e8cc4SNicolin Chen 		if (cpu_dai->active)
682988e8cc4SNicolin Chen 			pinctrl_pm_select_default_state(cpu_dai->dev);
68388bd870fSBenoit Cousson 
6840b7990e3SKuninori Morimoto 		for_each_rtd_codec_dai(rtd, j, codec_dai) {
685988e8cc4SNicolin Chen 			if (codec_dai->active)
686988e8cc4SNicolin Chen 				pinctrl_pm_select_default_state(codec_dai->dev);
687988e8cc4SNicolin Chen 		}
68888bd870fSBenoit Cousson 	}
689988e8cc4SNicolin Chen 
690bc263214SLars-Peter Clausen 	/*
691bc263214SLars-Peter Clausen 	 * DAIs that also act as the control bus master might have other drivers
692bc263214SLars-Peter Clausen 	 * hanging off them so need to resume immediately. Other drivers don't
693bc263214SLars-Peter Clausen 	 * have that problem and may take a substantial amount of time to resume
69464ab9baaSMark Brown 	 * due to I/O costs and anti-pop so handle them out of line.
69564ab9baaSMark Brown 	 */
6961a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
6971a497983SMengdong Lin 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
698bc263214SLars-Peter Clausen 		bus_control |= cpu_dai->driver->bus_control;
69982e14e8bSStephen Warren 	}
700bc263214SLars-Peter Clausen 	if (bus_control) {
701bc263214SLars-Peter Clausen 		dev_dbg(dev, "ASoC: Resuming control bus master immediately\n");
70264ab9baaSMark Brown 		soc_resume_deferred(&card->deferred_resume_work);
70364ab9baaSMark Brown 	} else {
704f110bfc7SLiam Girdwood 		dev_dbg(dev, "ASoC: Scheduling resume work\n");
7056308419aSMark Brown 		if (!schedule_work(&card->deferred_resume_work))
706f110bfc7SLiam Girdwood 			dev_err(dev, "ASoC: resume work item may be lost\n");
707f0fba2adSLiam Girdwood 	}
7086ed25978SAndy Green 
709db2a4165SFrank Mandarino 	return 0;
710db2a4165SFrank Mandarino }
7116f8ab4acSMark Brown EXPORT_SYMBOL_GPL(snd_soc_resume);
712db2a4165SFrank Mandarino #else
7136f8ab4acSMark Brown #define snd_soc_suspend NULL
7146f8ab4acSMark Brown #define snd_soc_resume NULL
715db2a4165SFrank Mandarino #endif
716db2a4165SFrank Mandarino 
71785e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops null_dai_ops = {
71802a06d30SBarry Song };
71902a06d30SBarry Song 
72065d9361fSLars-Peter Clausen static struct snd_soc_component *soc_find_component(
72165d9361fSLars-Peter Clausen 	const struct device_node *of_node, const char *name)
72212023a9aSMisael Lopez Cruz {
72365d9361fSLars-Peter Clausen 	struct snd_soc_component *component;
72412023a9aSMisael Lopez Cruz 
72534e81ab4SLars-Peter Clausen 	lockdep_assert_held(&client_mutex);
72634e81ab4SLars-Peter Clausen 
72765d9361fSLars-Peter Clausen 	list_for_each_entry(component, &component_list, list) {
72865d9361fSLars-Peter Clausen 		if (of_node) {
72965d9361fSLars-Peter Clausen 			if (component->dev->of_node == of_node)
73065d9361fSLars-Peter Clausen 				return component;
73165d9361fSLars-Peter Clausen 		} else if (strcmp(component->name, name) == 0) {
73265d9361fSLars-Peter Clausen 			return component;
73312023a9aSMisael Lopez Cruz 		}
73412023a9aSMisael Lopez Cruz 	}
73512023a9aSMisael Lopez Cruz 
73612023a9aSMisael Lopez Cruz 	return NULL;
73712023a9aSMisael Lopez Cruz }
73812023a9aSMisael Lopez Cruz 
739fbb88b5cSMengdong Lin /**
740fbb88b5cSMengdong Lin  * snd_soc_find_dai - Find a registered DAI
741fbb88b5cSMengdong Lin  *
7424958471bSJeffy Chen  * @dlc: name of the DAI or the DAI driver and optional component info to match
743fbb88b5cSMengdong Lin  *
744ad61dd30SStephen Boyd  * This function will search all registered components and their DAIs to
745fbb88b5cSMengdong Lin  * find the DAI of the same name. The component's of_node and name
746fbb88b5cSMengdong Lin  * should also match if being specified.
747fbb88b5cSMengdong Lin  *
748fbb88b5cSMengdong Lin  * Return: pointer of DAI, or NULL if not found.
749fbb88b5cSMengdong Lin  */
750305e9020SMengdong Lin struct snd_soc_dai *snd_soc_find_dai(
75114621c7eSLars-Peter Clausen 	const struct snd_soc_dai_link_component *dlc)
75212023a9aSMisael Lopez Cruz {
75314621c7eSLars-Peter Clausen 	struct snd_soc_component *component;
75414621c7eSLars-Peter Clausen 	struct snd_soc_dai *dai;
7553e0aa8d8SJyri Sarha 	struct device_node *component_of_node;
75612023a9aSMisael Lopez Cruz 
75734e81ab4SLars-Peter Clausen 	lockdep_assert_held(&client_mutex);
75834e81ab4SLars-Peter Clausen 
75914621c7eSLars-Peter Clausen 	/* Find CPU DAI from registered DAIs*/
76014621c7eSLars-Peter Clausen 	list_for_each_entry(component, &component_list, list) {
7613e0aa8d8SJyri Sarha 		component_of_node = component->dev->of_node;
7623e0aa8d8SJyri Sarha 		if (!component_of_node && component->dev->parent)
7633e0aa8d8SJyri Sarha 			component_of_node = component->dev->parent->of_node;
7643e0aa8d8SJyri Sarha 
7653e0aa8d8SJyri Sarha 		if (dlc->of_node && component_of_node != dlc->of_node)
76612023a9aSMisael Lopez Cruz 			continue;
7671ffae361SLars-Peter Clausen 		if (dlc->name && strcmp(component->name, dlc->name))
76812023a9aSMisael Lopez Cruz 			continue;
76914621c7eSLars-Peter Clausen 		list_for_each_entry(dai, &component->dai_list, list) {
7704958471bSJeffy Chen 			if (dlc->dai_name && strcmp(dai->name, dlc->dai_name)
7716a6dafdaSJeffy Chen 			    && (!dai->driver->name
7726a6dafdaSJeffy Chen 				|| strcmp(dai->driver->name, dlc->dai_name)))
77314621c7eSLars-Peter Clausen 				continue;
77412023a9aSMisael Lopez Cruz 
77514621c7eSLars-Peter Clausen 			return dai;
77612023a9aSMisael Lopez Cruz 		}
77712023a9aSMisael Lopez Cruz 	}
77812023a9aSMisael Lopez Cruz 
77912023a9aSMisael Lopez Cruz 	return NULL;
78012023a9aSMisael Lopez Cruz }
781305e9020SMengdong Lin EXPORT_SYMBOL_GPL(snd_soc_find_dai);
78212023a9aSMisael Lopez Cruz 
78317fb1755SMengdong Lin 
78417fb1755SMengdong Lin /**
78517fb1755SMengdong Lin  * snd_soc_find_dai_link - Find a DAI link
78617fb1755SMengdong Lin  *
78717fb1755SMengdong Lin  * @card: soc card
78817fb1755SMengdong Lin  * @id: DAI link ID to match
78917fb1755SMengdong Lin  * @name: DAI link name to match, optional
7908abab35fSCharles Keepax  * @stream_name: DAI link stream name to match, optional
79117fb1755SMengdong Lin  *
79217fb1755SMengdong Lin  * This function will search all existing DAI links of the soc card to
79317fb1755SMengdong Lin  * find the link of the same ID. Since DAI links may not have their
79417fb1755SMengdong Lin  * unique ID, so name and stream name should also match if being
79517fb1755SMengdong Lin  * specified.
79617fb1755SMengdong Lin  *
79717fb1755SMengdong Lin  * Return: pointer of DAI link, or NULL if not found.
79817fb1755SMengdong Lin  */
79917fb1755SMengdong Lin struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card,
80017fb1755SMengdong Lin 					       int id, const char *name,
80117fb1755SMengdong Lin 					       const char *stream_name)
80217fb1755SMengdong Lin {
80317fb1755SMengdong Lin 	struct snd_soc_dai_link *link, *_link;
80417fb1755SMengdong Lin 
80517fb1755SMengdong Lin 	lockdep_assert_held(&client_mutex);
80617fb1755SMengdong Lin 
80717fb1755SMengdong Lin 	list_for_each_entry_safe(link, _link, &card->dai_link_list, list) {
80817fb1755SMengdong Lin 		if (link->id != id)
80917fb1755SMengdong Lin 			continue;
81017fb1755SMengdong Lin 
81117fb1755SMengdong Lin 		if (name && (!link->name || strcmp(name, link->name)))
81217fb1755SMengdong Lin 			continue;
81317fb1755SMengdong Lin 
81417fb1755SMengdong Lin 		if (stream_name && (!link->stream_name
81517fb1755SMengdong Lin 			|| strcmp(stream_name, link->stream_name)))
81617fb1755SMengdong Lin 			continue;
81717fb1755SMengdong Lin 
81817fb1755SMengdong Lin 		return link;
81917fb1755SMengdong Lin 	}
82017fb1755SMengdong Lin 
82117fb1755SMengdong Lin 	return NULL;
82217fb1755SMengdong Lin }
82317fb1755SMengdong Lin EXPORT_SYMBOL_GPL(snd_soc_find_dai_link);
82417fb1755SMengdong Lin 
82549a5ba1cSMengdong Lin static bool soc_is_dai_link_bound(struct snd_soc_card *card,
82649a5ba1cSMengdong Lin 		struct snd_soc_dai_link *dai_link)
827db2a4165SFrank Mandarino {
82849a5ba1cSMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
82949a5ba1cSMengdong Lin 
83049a5ba1cSMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
83149a5ba1cSMengdong Lin 		if (rtd->dai_link == dai_link)
83249a5ba1cSMengdong Lin 			return true;
83349a5ba1cSMengdong Lin 	}
83449a5ba1cSMengdong Lin 
83549a5ba1cSMengdong Lin 	return false;
83649a5ba1cSMengdong Lin }
83749a5ba1cSMengdong Lin 
8386f2f1ff0SMengdong Lin static int soc_bind_dai_link(struct snd_soc_card *card,
8396f2f1ff0SMengdong Lin 	struct snd_soc_dai_link *dai_link)
840db2a4165SFrank Mandarino {
8411a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
84288bd870fSBenoit Cousson 	struct snd_soc_dai_link_component *codecs = dai_link->codecs;
84314621c7eSLars-Peter Clausen 	struct snd_soc_dai_link_component cpu_dai_component;
84490be711eSKuninori Morimoto 	struct snd_soc_component *component;
8451a497983SMengdong Lin 	struct snd_soc_dai **codec_dais;
84606859fcaSCharles Keepax 	struct device_node *platform_of_node;
847848dd8beSMark Brown 	const char *platform_name;
84888bd870fSBenoit Cousson 	int i;
849db2a4165SFrank Mandarino 
850a655de80SLiam Girdwood 	if (dai_link->ignore)
851a655de80SLiam Girdwood 		return 0;
852a655de80SLiam Girdwood 
8536f2f1ff0SMengdong Lin 	dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name);
8546308419aSMark Brown 
85549a5ba1cSMengdong Lin 	if (soc_is_dai_link_bound(card, dai_link)) {
85649a5ba1cSMengdong Lin 		dev_dbg(card->dev, "ASoC: dai link %s already bound\n",
85749a5ba1cSMengdong Lin 			dai_link->name);
85849a5ba1cSMengdong Lin 		return 0;
85949a5ba1cSMengdong Lin 	}
860db2a4165SFrank Mandarino 
861513cb311SSudip Mukherjee 	rtd = soc_new_pcm_runtime(card, dai_link);
862513cb311SSudip Mukherjee 	if (!rtd)
863513cb311SSudip Mukherjee 		return -ENOMEM;
864513cb311SSudip Mukherjee 
86514621c7eSLars-Peter Clausen 	cpu_dai_component.name = dai_link->cpu_name;
86614621c7eSLars-Peter Clausen 	cpu_dai_component.of_node = dai_link->cpu_of_node;
86714621c7eSLars-Peter Clausen 	cpu_dai_component.dai_name = dai_link->cpu_dai_name;
86814621c7eSLars-Peter Clausen 	rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component);
869b19e6e7bSMark Brown 	if (!rtd->cpu_dai) {
8706b490879SMartin Hundebøll 		dev_info(card->dev, "ASoC: CPU DAI %s not registered\n",
871f0fba2adSLiam Girdwood 			 dai_link->cpu_dai_name);
8721a497983SMengdong Lin 		goto _err_defer;
873c5af3a2eSMark Brown 	}
87490be711eSKuninori Morimoto 	snd_soc_rtdcom_add(rtd, rtd->cpu_dai->component);
875c5af3a2eSMark Brown 
87688bd870fSBenoit Cousson 	rtd->num_codecs = dai_link->num_codecs;
87788bd870fSBenoit Cousson 
87888bd870fSBenoit Cousson 	/* Find CODEC from registered CODECs */
8790b7990e3SKuninori Morimoto 	/* we can use for_each_rtd_codec_dai() after this */
8801a497983SMengdong Lin 	codec_dais = rtd->codec_dais;
88188bd870fSBenoit Cousson 	for (i = 0; i < rtd->num_codecs; i++) {
88214621c7eSLars-Peter Clausen 		codec_dais[i] = snd_soc_find_dai(&codecs[i]);
88388bd870fSBenoit Cousson 		if (!codec_dais[i]) {
88412023a9aSMisael Lopez Cruz 			dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n",
88588bd870fSBenoit Cousson 				codecs[i].dai_name);
8861a497983SMengdong Lin 			goto _err_defer;
88712023a9aSMisael Lopez Cruz 		}
88890be711eSKuninori Morimoto 		snd_soc_rtdcom_add(rtd, codec_dais[i]->component);
88988bd870fSBenoit Cousson 	}
89088bd870fSBenoit Cousson 
89188bd870fSBenoit Cousson 	/* Single codec links expect codec and codec_dai in runtime data */
89288bd870fSBenoit Cousson 	rtd->codec_dai = codec_dais[0];
89312023a9aSMisael Lopez Cruz 
894848dd8beSMark Brown 	/* if there's no platform we match on the empty platform */
895daecf46eSKuninori Morimoto 	platform_name = dai_link->platform->name;
896daecf46eSKuninori Morimoto 	if (!platform_name && !dai_link->platform->of_node)
897848dd8beSMark Brown 		platform_name = "snd-soc-dummy";
898848dd8beSMark Brown 
899b19e6e7bSMark Brown 	/* find one from the set of registered platforms */
90090be711eSKuninori Morimoto 	list_for_each_entry(component, &component_list, list) {
90190be711eSKuninori Morimoto 		platform_of_node = component->dev->of_node;
90290be711eSKuninori Morimoto 		if (!platform_of_node && component->dev->parent->of_node)
90390be711eSKuninori Morimoto 			platform_of_node = component->dev->parent->of_node;
90490be711eSKuninori Morimoto 
905daecf46eSKuninori Morimoto 		if (dai_link->platform->of_node) {
906daecf46eSKuninori Morimoto 			if (platform_of_node != dai_link->platform->of_node)
90790be711eSKuninori Morimoto 				continue;
90890be711eSKuninori Morimoto 		} else {
90990be711eSKuninori Morimoto 			if (strcmp(component->name, platform_name))
91090be711eSKuninori Morimoto 				continue;
91190be711eSKuninori Morimoto 		}
91290be711eSKuninori Morimoto 
91390be711eSKuninori Morimoto 		snd_soc_rtdcom_add(rtd, component);
91490be711eSKuninori Morimoto 	}
91590be711eSKuninori Morimoto 
9161a497983SMengdong Lin 	soc_add_pcm_runtime(card, rtd);
917b19e6e7bSMark Brown 	return 0;
9181a497983SMengdong Lin 
9191a497983SMengdong Lin _err_defer:
9201a497983SMengdong Lin 	soc_free_pcm_runtime(rtd);
9211a497983SMengdong Lin 	return  -EPROBE_DEFER;
9226b05eda6SMark Brown }
9236b05eda6SMark Brown 
924f1d45cc3SLars-Peter Clausen static void soc_remove_component(struct snd_soc_component *component)
925d12cd198SStephen Warren {
926abd31b32SLars-Peter Clausen 	if (!component->card)
92770090bbbSLars-Peter Clausen 		return;
928d12cd198SStephen Warren 
929d9fc4063SKuninori Morimoto 	list_del(&component->card_list);
930d12cd198SStephen Warren 
931999f7f5aSKuninori Morimoto 	if (component->driver->remove)
932999f7f5aSKuninori Morimoto 		component->driver->remove(component);
933d12cd198SStephen Warren 
934f1d45cc3SLars-Peter Clausen 	snd_soc_dapm_free(snd_soc_component_get_dapm(component));
935d12cd198SStephen Warren 
936f1d45cc3SLars-Peter Clausen 	soc_cleanup_component_debugfs(component);
937abd31b32SLars-Peter Clausen 	component->card = NULL;
938f1d45cc3SLars-Peter Clausen 	module_put(component->dev->driver->owner);
939d12cd198SStephen Warren }
940d12cd198SStephen Warren 
941e60cd14fSLars-Peter Clausen static void soc_remove_dai(struct snd_soc_dai *dai, int order)
942589c3563SJarkko Nikula {
943589c3563SJarkko Nikula 	int err;
944589c3563SJarkko Nikula 
945*2eda3cb1SKuninori Morimoto 	if (!dai || !dai->probed ||
946*2eda3cb1SKuninori Morimoto 	    dai->driver->remove_order != order)
947*2eda3cb1SKuninori Morimoto 		return;
948*2eda3cb1SKuninori Morimoto 
949e60cd14fSLars-Peter Clausen 	if (dai->driver->remove) {
950e60cd14fSLars-Peter Clausen 		err = dai->driver->remove(dai);
951589c3563SJarkko Nikula 		if (err < 0)
952e60cd14fSLars-Peter Clausen 			dev_err(dai->dev,
953b0aa88afSMisael Lopez Cruz 				"ASoC: failed to remove %s: %d\n",
954e60cd14fSLars-Peter Clausen 				dai->name, err);
955b0aa88afSMisael Lopez Cruz 	}
956e60cd14fSLars-Peter Clausen 	dai->probed = 0;
957b0aa88afSMisael Lopez Cruz }
958b0aa88afSMisael Lopez Cruz 
9591a497983SMengdong Lin static void soc_remove_link_dais(struct snd_soc_card *card,
9601a497983SMengdong Lin 		struct snd_soc_pcm_runtime *rtd, int order)
961f0fba2adSLiam Girdwood {
962e60cd14fSLars-Peter Clausen 	int i;
9630b7990e3SKuninori Morimoto 	struct snd_soc_dai *codec_dai;
964f0fba2adSLiam Girdwood 
965f0fba2adSLiam Girdwood 	/* unregister the rtd device */
966f0fba2adSLiam Girdwood 	if (rtd->dev_registered) {
96736ae1a96SMark Brown 		device_unregister(rtd->dev);
968f0fba2adSLiam Girdwood 		rtd->dev_registered = 0;
96902a06d30SBarry Song 	}
97002a06d30SBarry Song 
971f0fba2adSLiam Girdwood 	/* remove the CODEC DAI */
9720b7990e3SKuninori Morimoto 	for_each_rtd_codec_dai(rtd, i, codec_dai)
9730b7990e3SKuninori Morimoto 		soc_remove_dai(codec_dai, order);
974f0fba2adSLiam Girdwood 
975e60cd14fSLars-Peter Clausen 	soc_remove_dai(rtd->cpu_dai, order);
976f0fba2adSLiam Girdwood }
977f0fba2adSLiam Girdwood 
9781a497983SMengdong Lin static void soc_remove_link_components(struct snd_soc_card *card,
9791a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd, int order)
98062ae68faSStephen Warren {
98161aca564SLars-Peter Clausen 	struct snd_soc_component *component;
98290be711eSKuninori Morimoto 	struct snd_soc_rtdcom_list *rtdcom;
98362ae68faSStephen Warren 
98490be711eSKuninori Morimoto 	for_each_rtdcom(rtd, rtdcom) {
98590be711eSKuninori Morimoto 		component = rtdcom->component;
98662ae68faSStephen Warren 
98770090bbbSLars-Peter Clausen 		if (component->driver->remove_order == order)
98861aca564SLars-Peter Clausen 			soc_remove_component(component);
98962ae68faSStephen Warren 	}
99062ae68faSStephen Warren }
99162ae68faSStephen Warren 
9920671fd8eSKuninori Morimoto static void soc_remove_dai_links(struct snd_soc_card *card)
9930671fd8eSKuninori Morimoto {
9941a497983SMengdong Lin 	int order;
9951a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
996f8f80361SMengdong Lin 	struct snd_soc_dai_link *link, *_link;
9970671fd8eSKuninori Morimoto 
9980168bf0dSLiam Girdwood 	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
9990168bf0dSLiam Girdwood 			order++) {
10001a497983SMengdong Lin 		list_for_each_entry(rtd, &card->rtd_list, list)
10011a497983SMengdong Lin 			soc_remove_link_dais(card, rtd, order);
10020168bf0dSLiam Girdwood 	}
100362ae68faSStephen Warren 
100462ae68faSStephen Warren 	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
100562ae68faSStephen Warren 			order++) {
10061a497983SMengdong Lin 		list_for_each_entry(rtd, &card->rtd_list, list)
10071a497983SMengdong Lin 			soc_remove_link_components(card, rtd, order);
100862ae68faSStephen Warren 	}
100962ae68faSStephen Warren 
1010f8f80361SMengdong Lin 	list_for_each_entry_safe(link, _link, &card->dai_link_list, list) {
1011f8f80361SMengdong Lin 		if (link->dobj.type == SND_SOC_DOBJ_DAI_LINK)
1012f8f80361SMengdong Lin 			dev_warn(card->dev, "Topology forgot to remove link %s?\n",
1013f8f80361SMengdong Lin 				link->name);
1014f8f80361SMengdong Lin 
1015f8f80361SMengdong Lin 		list_del(&link->list);
1016f8f80361SMengdong Lin 		card->num_dai_links--;
10170671fd8eSKuninori Morimoto 	}
10180671fd8eSKuninori Morimoto }
10190671fd8eSKuninori Morimoto 
1020daecf46eSKuninori Morimoto static int snd_soc_init_platform(struct snd_soc_card *card,
1021daecf46eSKuninori Morimoto 				 struct snd_soc_dai_link *dai_link)
1022daecf46eSKuninori Morimoto {
1023daecf46eSKuninori Morimoto 	/*
1024daecf46eSKuninori Morimoto 	 * FIXME
1025daecf46eSKuninori Morimoto 	 *
1026daecf46eSKuninori Morimoto 	 * this function should be removed in the future
1027daecf46eSKuninori Morimoto 	 */
1028daecf46eSKuninori Morimoto 	/* convert Legacy platform link */
1029daecf46eSKuninori Morimoto 	if (dai_link->platform)
1030daecf46eSKuninori Morimoto 		return 0;
1031daecf46eSKuninori Morimoto 
1032daecf46eSKuninori Morimoto 	dai_link->platform = devm_kzalloc(card->dev,
1033daecf46eSKuninori Morimoto 				sizeof(struct snd_soc_dai_link_component),
1034daecf46eSKuninori Morimoto 				GFP_KERNEL);
1035daecf46eSKuninori Morimoto 	if (!dai_link->platform)
1036daecf46eSKuninori Morimoto 		return -ENOMEM;
1037daecf46eSKuninori Morimoto 
1038daecf46eSKuninori Morimoto 	dai_link->platform->name	= dai_link->platform_name;
1039daecf46eSKuninori Morimoto 	dai_link->platform->of_node	= dai_link->platform_of_node;
1040daecf46eSKuninori Morimoto 	dai_link->platform->dai_name	= NULL;
1041daecf46eSKuninori Morimoto 
1042daecf46eSKuninori Morimoto 	return 0;
1043daecf46eSKuninori Morimoto }
1044daecf46eSKuninori Morimoto 
1045923c5e61SMengdong Lin static int snd_soc_init_multicodec(struct snd_soc_card *card,
1046923c5e61SMengdong Lin 				   struct snd_soc_dai_link *dai_link)
1047923c5e61SMengdong Lin {
1048923c5e61SMengdong Lin 	/* Legacy codec/codec_dai link is a single entry in multicodec */
1049923c5e61SMengdong Lin 	if (dai_link->codec_name || dai_link->codec_of_node ||
1050923c5e61SMengdong Lin 	    dai_link->codec_dai_name) {
1051923c5e61SMengdong Lin 		dai_link->num_codecs = 1;
1052923c5e61SMengdong Lin 
1053923c5e61SMengdong Lin 		dai_link->codecs = devm_kzalloc(card->dev,
1054923c5e61SMengdong Lin 				sizeof(struct snd_soc_dai_link_component),
1055923c5e61SMengdong Lin 				GFP_KERNEL);
1056923c5e61SMengdong Lin 		if (!dai_link->codecs)
1057923c5e61SMengdong Lin 			return -ENOMEM;
1058923c5e61SMengdong Lin 
1059923c5e61SMengdong Lin 		dai_link->codecs[0].name = dai_link->codec_name;
1060923c5e61SMengdong Lin 		dai_link->codecs[0].of_node = dai_link->codec_of_node;
1061923c5e61SMengdong Lin 		dai_link->codecs[0].dai_name = dai_link->codec_dai_name;
1062923c5e61SMengdong Lin 	}
1063923c5e61SMengdong Lin 
1064923c5e61SMengdong Lin 	if (!dai_link->codecs) {
1065923c5e61SMengdong Lin 		dev_err(card->dev, "ASoC: DAI link has no CODECs\n");
1066923c5e61SMengdong Lin 		return -EINVAL;
1067923c5e61SMengdong Lin 	}
1068923c5e61SMengdong Lin 
1069923c5e61SMengdong Lin 	return 0;
1070923c5e61SMengdong Lin }
1071923c5e61SMengdong Lin 
1072923c5e61SMengdong Lin static int soc_init_dai_link(struct snd_soc_card *card,
1073923c5e61SMengdong Lin 				   struct snd_soc_dai_link *link)
1074923c5e61SMengdong Lin {
1075923c5e61SMengdong Lin 	int i, ret;
10763db769f1SKuninori Morimoto 	struct snd_soc_dai_link_component *codec;
1077923c5e61SMengdong Lin 
1078daecf46eSKuninori Morimoto 	ret = snd_soc_init_platform(card, link);
1079daecf46eSKuninori Morimoto 	if (ret) {
1080daecf46eSKuninori Morimoto 		dev_err(card->dev, "ASoC: failed to init multiplatform\n");
1081daecf46eSKuninori Morimoto 		return ret;
1082daecf46eSKuninori Morimoto 	}
1083daecf46eSKuninori Morimoto 
1084923c5e61SMengdong Lin 	ret = snd_soc_init_multicodec(card, link);
1085923c5e61SMengdong Lin 	if (ret) {
1086923c5e61SMengdong Lin 		dev_err(card->dev, "ASoC: failed to init multicodec\n");
1087923c5e61SMengdong Lin 		return ret;
1088923c5e61SMengdong Lin 	}
1089923c5e61SMengdong Lin 
10903db769f1SKuninori Morimoto 	for_each_link_codecs(link, i, codec) {
1091923c5e61SMengdong Lin 		/*
1092923c5e61SMengdong Lin 		 * Codec must be specified by 1 of name or OF node,
1093923c5e61SMengdong Lin 		 * not both or neither.
1094923c5e61SMengdong Lin 		 */
10953db769f1SKuninori Morimoto 		if (!!codec->name ==
10963db769f1SKuninori Morimoto 		    !!codec->of_node) {
1097923c5e61SMengdong Lin 			dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n",
1098923c5e61SMengdong Lin 				link->name);
1099923c5e61SMengdong Lin 			return -EINVAL;
1100923c5e61SMengdong Lin 		}
1101923c5e61SMengdong Lin 		/* Codec DAI name must be specified */
11023db769f1SKuninori Morimoto 		if (!codec->dai_name) {
1103923c5e61SMengdong Lin 			dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n",
1104923c5e61SMengdong Lin 				link->name);
1105923c5e61SMengdong Lin 			return -EINVAL;
1106923c5e61SMengdong Lin 		}
1107923c5e61SMengdong Lin 	}
1108923c5e61SMengdong Lin 
1109923c5e61SMengdong Lin 	/*
1110923c5e61SMengdong Lin 	 * Platform may be specified by either name or OF node, but
1111923c5e61SMengdong Lin 	 * can be left unspecified, and a dummy platform will be used.
1112923c5e61SMengdong Lin 	 */
1113daecf46eSKuninori Morimoto 	if (link->platform->name && link->platform->of_node) {
1114923c5e61SMengdong Lin 		dev_err(card->dev,
1115923c5e61SMengdong Lin 			"ASoC: Both platform name/of_node are set for %s\n",
1116923c5e61SMengdong Lin 			link->name);
1117923c5e61SMengdong Lin 		return -EINVAL;
1118923c5e61SMengdong Lin 	}
1119923c5e61SMengdong Lin 	/*
1120923c5e61SMengdong Lin 	 * CPU device may be specified by either name or OF node, but
1121923c5e61SMengdong Lin 	 * can be left unspecified, and will be matched based on DAI
1122923c5e61SMengdong Lin 	 * name alone..
1123923c5e61SMengdong Lin 	 */
1124923c5e61SMengdong Lin 	if (link->cpu_name && link->cpu_of_node) {
1125923c5e61SMengdong Lin 		dev_err(card->dev,
1126923c5e61SMengdong Lin 			"ASoC: Neither/both cpu name/of_node are set for %s\n",
1127923c5e61SMengdong Lin 			link->name);
1128923c5e61SMengdong Lin 		return -EINVAL;
1129923c5e61SMengdong Lin 	}
1130923c5e61SMengdong Lin 	/*
1131923c5e61SMengdong Lin 	 * At least one of CPU DAI name or CPU device name/node must be
1132923c5e61SMengdong Lin 	 * specified
1133923c5e61SMengdong Lin 	 */
1134923c5e61SMengdong Lin 	if (!link->cpu_dai_name &&
1135923c5e61SMengdong Lin 	    !(link->cpu_name || link->cpu_of_node)) {
1136923c5e61SMengdong Lin 		dev_err(card->dev,
1137923c5e61SMengdong Lin 			"ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n",
1138923c5e61SMengdong Lin 			link->name);
1139923c5e61SMengdong Lin 		return -EINVAL;
1140923c5e61SMengdong Lin 	}
1141923c5e61SMengdong Lin 
1142923c5e61SMengdong Lin 	return 0;
1143923c5e61SMengdong Lin }
1144923c5e61SMengdong Lin 
1145ef2e8175SKuninori Morimoto void snd_soc_disconnect_sync(struct device *dev)
1146ef2e8175SKuninori Morimoto {
1147ef2e8175SKuninori Morimoto 	struct snd_soc_component *component = snd_soc_lookup_component(dev, NULL);
1148ef2e8175SKuninori Morimoto 
1149ef2e8175SKuninori Morimoto 	if (!component || !component->card)
1150ef2e8175SKuninori Morimoto 		return;
1151ef2e8175SKuninori Morimoto 
1152ef2e8175SKuninori Morimoto 	snd_card_disconnect_sync(component->card->snd_card);
1153ef2e8175SKuninori Morimoto }
1154df532185SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_disconnect_sync);
1155ef2e8175SKuninori Morimoto 
1156f8f80361SMengdong Lin /**
1157f8f80361SMengdong Lin  * snd_soc_add_dai_link - Add a DAI link dynamically
1158f8f80361SMengdong Lin  * @card: The ASoC card to which the DAI link is added
1159f8f80361SMengdong Lin  * @dai_link: The new DAI link to add
1160f8f80361SMengdong Lin  *
1161f8f80361SMengdong Lin  * This function adds a DAI link to the ASoC card's link list.
1162f8f80361SMengdong Lin  *
1163f8f80361SMengdong Lin  * Note: Topology can use this API to add DAI links when probing the
1164f8f80361SMengdong Lin  * topology component. And machine drivers can still define static
1165f8f80361SMengdong Lin  * DAI links in dai_link array.
1166f8f80361SMengdong Lin  */
1167f8f80361SMengdong Lin int snd_soc_add_dai_link(struct snd_soc_card *card,
1168f8f80361SMengdong Lin 		struct snd_soc_dai_link *dai_link)
1169f8f80361SMengdong Lin {
1170f8f80361SMengdong Lin 	if (dai_link->dobj.type
1171f8f80361SMengdong Lin 	    && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) {
1172f8f80361SMengdong Lin 		dev_err(card->dev, "Invalid dai link type %d\n",
1173f8f80361SMengdong Lin 			dai_link->dobj.type);
1174f8f80361SMengdong Lin 		return -EINVAL;
1175f8f80361SMengdong Lin 	}
1176f8f80361SMengdong Lin 
1177f8f80361SMengdong Lin 	lockdep_assert_held(&client_mutex);
1178d6f220eaSMengdong Lin 	/* Notify the machine driver for extra initialization
1179d6f220eaSMengdong Lin 	 * on the link created by topology.
1180d6f220eaSMengdong Lin 	 */
1181d6f220eaSMengdong Lin 	if (dai_link->dobj.type && card->add_dai_link)
1182d6f220eaSMengdong Lin 		card->add_dai_link(card, dai_link);
1183d6f220eaSMengdong Lin 
1184f8f80361SMengdong Lin 	list_add_tail(&dai_link->list, &card->dai_link_list);
1185f8f80361SMengdong Lin 	card->num_dai_links++;
1186f8f80361SMengdong Lin 
1187f8f80361SMengdong Lin 	return 0;
1188f8f80361SMengdong Lin }
1189f8f80361SMengdong Lin EXPORT_SYMBOL_GPL(snd_soc_add_dai_link);
1190f8f80361SMengdong Lin 
1191f8f80361SMengdong Lin /**
1192f8f80361SMengdong Lin  * snd_soc_remove_dai_link - Remove a DAI link from the list
1193f8f80361SMengdong Lin  * @card: The ASoC card that owns the link
1194f8f80361SMengdong Lin  * @dai_link: The DAI link to remove
1195f8f80361SMengdong Lin  *
1196f8f80361SMengdong Lin  * This function removes a DAI link from the ASoC card's link list.
1197f8f80361SMengdong Lin  *
1198f8f80361SMengdong Lin  * For DAI links previously added by topology, topology should
1199f8f80361SMengdong Lin  * remove them by using the dobj embedded in the link.
1200f8f80361SMengdong Lin  */
1201f8f80361SMengdong Lin void snd_soc_remove_dai_link(struct snd_soc_card *card,
1202f8f80361SMengdong Lin 			     struct snd_soc_dai_link *dai_link)
1203f8f80361SMengdong Lin {
1204f8f80361SMengdong Lin 	struct snd_soc_dai_link *link, *_link;
1205f8f80361SMengdong Lin 
1206f8f80361SMengdong Lin 	if (dai_link->dobj.type
1207f8f80361SMengdong Lin 	    && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) {
1208f8f80361SMengdong Lin 		dev_err(card->dev, "Invalid dai link type %d\n",
1209f8f80361SMengdong Lin 			dai_link->dobj.type);
1210f8f80361SMengdong Lin 		return;
1211f8f80361SMengdong Lin 	}
1212f8f80361SMengdong Lin 
1213f8f80361SMengdong Lin 	lockdep_assert_held(&client_mutex);
1214d6f220eaSMengdong Lin 	/* Notify the machine driver for extra destruction
1215d6f220eaSMengdong Lin 	 * on the link created by topology.
1216d6f220eaSMengdong Lin 	 */
1217d6f220eaSMengdong Lin 	if (dai_link->dobj.type && card->remove_dai_link)
1218d6f220eaSMengdong Lin 		card->remove_dai_link(card, dai_link);
1219d6f220eaSMengdong Lin 
1220f8f80361SMengdong Lin 	list_for_each_entry_safe(link, _link, &card->dai_link_list, list) {
1221f8f80361SMengdong Lin 		if (link == dai_link) {
1222f8f80361SMengdong Lin 			list_del(&link->list);
1223f8f80361SMengdong Lin 			card->num_dai_links--;
1224f8f80361SMengdong Lin 			return;
1225f8f80361SMengdong Lin 		}
1226f8f80361SMengdong Lin 	}
1227f8f80361SMengdong Lin }
1228f8f80361SMengdong Lin EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link);
1229f0fba2adSLiam Girdwood 
1230aefba455SJerome Brunet static void soc_set_of_name_prefix(struct snd_soc_component *component)
1231aefba455SJerome Brunet {
1232aefba455SJerome Brunet 	struct device_node *component_of_node = component->dev->of_node;
1233aefba455SJerome Brunet 	const char *str;
1234aefba455SJerome Brunet 	int ret;
1235aefba455SJerome Brunet 
1236aefba455SJerome Brunet 	if (!component_of_node && component->dev->parent)
1237aefba455SJerome Brunet 		component_of_node = component->dev->parent->of_node;
1238aefba455SJerome Brunet 
1239aefba455SJerome Brunet 	ret = of_property_read_string(component_of_node, "sound-name-prefix",
1240aefba455SJerome Brunet 				      &str);
1241aefba455SJerome Brunet 	if (!ret)
1242aefba455SJerome Brunet 		component->name_prefix = str;
1243aefba455SJerome Brunet }
1244aefba455SJerome Brunet 
1245ead9b919SJarkko Nikula static void soc_set_name_prefix(struct snd_soc_card *card,
124694f99c87SLars-Peter Clausen 				struct snd_soc_component *component)
1247ead9b919SJarkko Nikula {
1248ead9b919SJarkko Nikula 	int i;
1249ead9b919SJarkko Nikula 
1250aefba455SJerome Brunet 	for (i = 0; i < card->num_configs && card->codec_conf; i++) {
1251ff819b83SDimitris Papastamos 		struct snd_soc_codec_conf *map = &card->codec_conf[i];
1252b24c539bSCharles Keepax 		struct device_node *component_of_node = component->dev->of_node;
1253b24c539bSCharles Keepax 
1254b24c539bSCharles Keepax 		if (!component_of_node && component->dev->parent)
1255b24c539bSCharles Keepax 			component_of_node = component->dev->parent->of_node;
1256b24c539bSCharles Keepax 
1257b24c539bSCharles Keepax 		if (map->of_node && component_of_node != map->of_node)
12583ca041edSSebastian Reichel 			continue;
125994f99c87SLars-Peter Clausen 		if (map->dev_name && strcmp(component->name, map->dev_name))
12603ca041edSSebastian Reichel 			continue;
126194f99c87SLars-Peter Clausen 		component->name_prefix = map->name_prefix;
1262aefba455SJerome Brunet 		return;
1263ead9b919SJarkko Nikula 	}
1264aefba455SJerome Brunet 
1265aefba455SJerome Brunet 	/*
1266aefba455SJerome Brunet 	 * If there is no configuration table or no match in the table,
1267aefba455SJerome Brunet 	 * check if a prefix is provided in the node
1268aefba455SJerome Brunet 	 */
1269aefba455SJerome Brunet 	soc_set_of_name_prefix(component);
1270ead9b919SJarkko Nikula }
1271ead9b919SJarkko Nikula 
1272f1d45cc3SLars-Peter Clausen static int soc_probe_component(struct snd_soc_card *card,
1273f1d45cc3SLars-Peter Clausen 	struct snd_soc_component *component)
1274589c3563SJarkko Nikula {
1275f1d45cc3SLars-Peter Clausen 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
1276888df395SMark Brown 	struct snd_soc_dai *dai;
1277f1d45cc3SLars-Peter Clausen 	int ret;
1278589c3563SJarkko Nikula 
12791b7c1231SLars-Peter Clausen 	if (!strcmp(component->name, "snd-soc-dummy"))
128070090bbbSLars-Peter Clausen 		return 0;
1281589c3563SJarkko Nikula 
1282abd31b32SLars-Peter Clausen 	if (component->card) {
12831b7c1231SLars-Peter Clausen 		if (component->card != card) {
12841b7c1231SLars-Peter Clausen 			dev_err(component->dev,
12851b7c1231SLars-Peter Clausen 				"Trying to bind component to card \"%s\" but is already bound to card \"%s\"\n",
12861b7c1231SLars-Peter Clausen 				card->name, component->card->name);
12871b7c1231SLars-Peter Clausen 			return -ENODEV;
12881b7c1231SLars-Peter Clausen 		}
12891b7c1231SLars-Peter Clausen 		return 0;
12901b7c1231SLars-Peter Clausen 	}
12911b7c1231SLars-Peter Clausen 
1292abd31b32SLars-Peter Clausen 	if (!try_module_get(component->dev->driver->owner))
1293abd31b32SLars-Peter Clausen 		return -ENODEV;
1294abd31b32SLars-Peter Clausen 
1295f1d45cc3SLars-Peter Clausen 	component->card = card;
1296f1d45cc3SLars-Peter Clausen 	dapm->card = card;
1297f1d45cc3SLars-Peter Clausen 	soc_set_name_prefix(card, component);
1298589c3563SJarkko Nikula 
1299f1d45cc3SLars-Peter Clausen 	soc_init_component_debugfs(component);
1300d5d1e0beSLars-Peter Clausen 
1301688d0ebfSKuninori Morimoto 	if (component->driver->dapm_widgets) {
1302688d0ebfSKuninori Morimoto 		ret = snd_soc_dapm_new_controls(dapm,
1303688d0ebfSKuninori Morimoto 					component->driver->dapm_widgets,
1304688d0ebfSKuninori Morimoto 					component->driver->num_dapm_widgets);
130577530150SLars-Peter Clausen 
1306b318ad50SNariman Poushin 		if (ret != 0) {
1307f1d45cc3SLars-Peter Clausen 			dev_err(component->dev,
1308b318ad50SNariman Poushin 				"Failed to create new controls %d\n", ret);
1309b318ad50SNariman Poushin 			goto err_probe;
1310b318ad50SNariman Poushin 		}
1311b318ad50SNariman Poushin 	}
1312b318ad50SNariman Poushin 
13130634814fSLars-Peter Clausen 	list_for_each_entry(dai, &component->dai_list, list) {
13140634814fSLars-Peter Clausen 		ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
1315261edc70SNariman Poushin 		if (ret != 0) {
1316f1d45cc3SLars-Peter Clausen 			dev_err(component->dev,
1317261edc70SNariman Poushin 				"Failed to create DAI widgets %d\n", ret);
1318261edc70SNariman Poushin 			goto err_probe;
1319261edc70SNariman Poushin 		}
1320261edc70SNariman Poushin 	}
1321888df395SMark Brown 
1322999f7f5aSKuninori Morimoto 	if (component->driver->probe) {
1323999f7f5aSKuninori Morimoto 		ret = component->driver->probe(component);
1324589c3563SJarkko Nikula 		if (ret < 0) {
1325f1d45cc3SLars-Peter Clausen 			dev_err(component->dev,
1326f1d45cc3SLars-Peter Clausen 				"ASoC: failed to probe component %d\n", ret);
132770d29331SJarkko Nikula 			goto err_probe;
1328589c3563SJarkko Nikula 		}
1329cb2cf612SLiam Girdwood 
1330f1d45cc3SLars-Peter Clausen 		WARN(dapm->idle_bias_off &&
1331f1d45cc3SLars-Peter Clausen 			dapm->bias_level != SND_SOC_BIAS_OFF,
1332956245e9SLiam Girdwood 			"codec %s can not start from non-off bias with idle_bias_off==1\n",
1333f1d45cc3SLars-Peter Clausen 			component->name);
1334956245e9SLiam Girdwood 	}
1335956245e9SLiam Girdwood 
1336f2ed6b07SMengdong Lin 	/* machine specific init */
1337f2ed6b07SMengdong Lin 	if (component->init) {
1338f2ed6b07SMengdong Lin 		ret = component->init(component);
1339f2ed6b07SMengdong Lin 		if (ret < 0) {
1340f2ed6b07SMengdong Lin 			dev_err(component->dev,
1341f2ed6b07SMengdong Lin 				"Failed to do machine specific init %d\n", ret);
1342f2ed6b07SMengdong Lin 			goto err_probe;
1343f2ed6b07SMengdong Lin 		}
1344f2ed6b07SMengdong Lin 	}
1345f2ed6b07SMengdong Lin 
1346b8972bf0SKuninori Morimoto 	if (component->driver->controls)
1347b8972bf0SKuninori Morimoto 		snd_soc_add_component_controls(component,
1348b8972bf0SKuninori Morimoto 					       component->driver->controls,
1349b8972bf0SKuninori Morimoto 					       component->driver->num_controls);
13506969b2baSKuninori Morimoto 	if (component->driver->dapm_routes)
13516969b2baSKuninori Morimoto 		snd_soc_dapm_add_routes(dapm,
13526969b2baSKuninori Morimoto 					component->driver->dapm_routes,
13536969b2baSKuninori Morimoto 					component->driver->num_dapm_routes);
1354956245e9SLiam Girdwood 
1355f1d45cc3SLars-Peter Clausen 	list_add(&dapm->list, &card->dapm_list);
1356d9fc4063SKuninori Morimoto 	list_add(&component->card_list, &card->component_dev_list);
1357956245e9SLiam Girdwood 
1358956245e9SLiam Girdwood 	return 0;
1359956245e9SLiam Girdwood 
1360956245e9SLiam Girdwood err_probe:
1361f1d45cc3SLars-Peter Clausen 	soc_cleanup_component_debugfs(component);
1362abd31b32SLars-Peter Clausen 	component->card = NULL;
1363f1d45cc3SLars-Peter Clausen 	module_put(component->dev->driver->owner);
1364956245e9SLiam Girdwood 
1365956245e9SLiam Girdwood 	return ret;
1366956245e9SLiam Girdwood }
1367956245e9SLiam Girdwood 
136836ae1a96SMark Brown static void rtd_release(struct device *dev)
136936ae1a96SMark Brown {
137036ae1a96SMark Brown 	kfree(dev);
137136ae1a96SMark Brown }
1372f0fba2adSLiam Girdwood 
13735f3484acSLars-Peter Clausen static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd,
13745f3484acSLars-Peter Clausen 	const char *name)
1375503ae5e0SMisael Lopez Cruz {
1376589c3563SJarkko Nikula 	int ret = 0;
1377589c3563SJarkko Nikula 
1378589c3563SJarkko Nikula 	/* register the rtd device */
137936ae1a96SMark Brown 	rtd->dev = kzalloc(sizeof(struct device), GFP_KERNEL);
138036ae1a96SMark Brown 	if (!rtd->dev)
138136ae1a96SMark Brown 		return -ENOMEM;
138236ae1a96SMark Brown 	device_initialize(rtd->dev);
13835f3484acSLars-Peter Clausen 	rtd->dev->parent = rtd->card->dev;
138436ae1a96SMark Brown 	rtd->dev->release = rtd_release;
1385d29697dcSTakashi Iwai 	rtd->dev->groups = soc_dev_attr_groups;
1386f294afedSLars-Peter Clausen 	dev_set_name(rtd->dev, "%s", name);
138736ae1a96SMark Brown 	dev_set_drvdata(rtd->dev, rtd);
1388b8c0dab9SLiam Girdwood 	mutex_init(&rtd->pcm_mutex);
138901d7584cSLiam Girdwood 	INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients);
139001d7584cSLiam Girdwood 	INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients);
139101d7584cSLiam Girdwood 	INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].fe_clients);
139201d7584cSLiam Girdwood 	INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients);
139336ae1a96SMark Brown 	ret = device_add(rtd->dev);
1394589c3563SJarkko Nikula 	if (ret < 0) {
1395865df9cbSChuansheng Liu 		/* calling put_device() here to free the rtd->dev */
1396865df9cbSChuansheng Liu 		put_device(rtd->dev);
13975f3484acSLars-Peter Clausen 		dev_err(rtd->card->dev,
1398f110bfc7SLiam Girdwood 			"ASoC: failed to register runtime device: %d\n", ret);
1399589c3563SJarkko Nikula 		return ret;
1400589c3563SJarkko Nikula 	}
1401589c3563SJarkko Nikula 	rtd->dev_registered = 1;
1402589c3563SJarkko Nikula 	return 0;
1403589c3563SJarkko Nikula }
1404589c3563SJarkko Nikula 
14051a497983SMengdong Lin static int soc_probe_link_components(struct snd_soc_card *card,
14061a497983SMengdong Lin 			struct snd_soc_pcm_runtime *rtd,
140762ae68faSStephen Warren 				     int order)
140862ae68faSStephen Warren {
1409f1d45cc3SLars-Peter Clausen 	struct snd_soc_component *component;
141090be711eSKuninori Morimoto 	struct snd_soc_rtdcom_list *rtdcom;
141190be711eSKuninori Morimoto 	int ret;
141262ae68faSStephen Warren 
141390be711eSKuninori Morimoto 	for_each_rtdcom(rtd, rtdcom) {
141490be711eSKuninori Morimoto 		component = rtdcom->component;
141590be711eSKuninori Morimoto 
141670090bbbSLars-Peter Clausen 		if (component->driver->probe_order == order) {
1417f1d45cc3SLars-Peter Clausen 			ret = soc_probe_component(card, component);
141862ae68faSStephen Warren 			if (ret < 0)
141962ae68faSStephen Warren 				return ret;
142062ae68faSStephen Warren 		}
142162ae68faSStephen Warren 	}
142262ae68faSStephen Warren 
142362ae68faSStephen Warren 	return 0;
142462ae68faSStephen Warren }
142562ae68faSStephen Warren 
14268e2be562SLars-Peter Clausen static int soc_probe_dai(struct snd_soc_dai *dai, int order)
1427b0aa88afSMisael Lopez Cruz {
14287a2ccad5SKuninori Morimoto 	if (dai->probed ||
14297a2ccad5SKuninori Morimoto 	    dai->driver->probe_order != order)
14307a2ccad5SKuninori Morimoto 		return 0;
1431b0aa88afSMisael Lopez Cruz 
14328e2be562SLars-Peter Clausen 	if (dai->driver->probe) {
14337a2ccad5SKuninori Morimoto 		int ret = dai->driver->probe(dai);
1434b0aa88afSMisael Lopez Cruz 		if (ret < 0) {
14357a2ccad5SKuninori Morimoto 			dev_err(dai->dev, "ASoC: failed to probe DAI %s: %d\n",
14368e2be562SLars-Peter Clausen 				dai->name, ret);
1437b0aa88afSMisael Lopez Cruz 			return ret;
1438b0aa88afSMisael Lopez Cruz 		}
1439b0aa88afSMisael Lopez Cruz 	}
1440b0aa88afSMisael Lopez Cruz 
14418e2be562SLars-Peter Clausen 	dai->probed = 1;
1442b0aa88afSMisael Lopez Cruz 
1443b0aa88afSMisael Lopez Cruz 	return 0;
1444b0aa88afSMisael Lopez Cruz }
1445b0aa88afSMisael Lopez Cruz 
144625f7b701SArnaud Pouliquen static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais,
144725f7b701SArnaud Pouliquen 				struct snd_soc_pcm_runtime *rtd)
144825f7b701SArnaud Pouliquen {
144925f7b701SArnaud Pouliquen 	int i, ret = 0;
145025f7b701SArnaud Pouliquen 
145125f7b701SArnaud Pouliquen 	for (i = 0; i < num_dais; ++i) {
145225f7b701SArnaud Pouliquen 		struct snd_soc_dai_driver *drv = dais[i]->driver;
145325f7b701SArnaud Pouliquen 
145425f7b701SArnaud Pouliquen 		if (!rtd->dai_link->no_pcm && drv->pcm_new)
145525f7b701SArnaud Pouliquen 			ret = drv->pcm_new(rtd, dais[i]);
145625f7b701SArnaud Pouliquen 		if (ret < 0) {
145725f7b701SArnaud Pouliquen 			dev_err(dais[i]->dev,
145825f7b701SArnaud Pouliquen 				"ASoC: Failed to bind %s with pcm device\n",
145925f7b701SArnaud Pouliquen 				dais[i]->name);
146025f7b701SArnaud Pouliquen 			return ret;
146125f7b701SArnaud Pouliquen 		}
146225f7b701SArnaud Pouliquen 	}
146325f7b701SArnaud Pouliquen 
146425f7b701SArnaud Pouliquen 	return 0;
146525f7b701SArnaud Pouliquen }
146625f7b701SArnaud Pouliquen 
14671a497983SMengdong Lin static int soc_probe_link_dais(struct snd_soc_card *card,
14681a497983SMengdong Lin 		struct snd_soc_pcm_runtime *rtd, int order)
1469f0fba2adSLiam Girdwood {
14701a497983SMengdong Lin 	struct snd_soc_dai_link *dai_link = rtd->dai_link;
1471c74184edSMark Brown 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1472a655de80SLiam Girdwood 	struct snd_soc_rtdcom_list *rtdcom;
1473a655de80SLiam Girdwood 	struct snd_soc_component *component;
14740b7990e3SKuninori Morimoto 	struct snd_soc_dai *codec_dai;
1475a655de80SLiam Girdwood 	int i, ret, num;
1476f0fba2adSLiam Girdwood 
1477f110bfc7SLiam Girdwood 	dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n",
14781a497983SMengdong Lin 			card->name, rtd->num, order);
1479f0fba2adSLiam Girdwood 
1480f0fba2adSLiam Girdwood 	/* set default power off timeout */
1481f0fba2adSLiam Girdwood 	rtd->pmdown_time = pmdown_time;
1482f0fba2adSLiam Girdwood 
14838e2be562SLars-Peter Clausen 	ret = soc_probe_dai(cpu_dai, order);
14848e2be562SLars-Peter Clausen 	if (ret)
1485f0fba2adSLiam Girdwood 		return ret;
1486f0fba2adSLiam Girdwood 
1487f0fba2adSLiam Girdwood 	/* probe the CODEC DAI */
14880b7990e3SKuninori Morimoto 	for_each_rtd_codec_dai(rtd, i, codec_dai) {
14890b7990e3SKuninori Morimoto 		ret = soc_probe_dai(codec_dai, order);
1490b0aa88afSMisael Lopez Cruz 		if (ret)
1491f0fba2adSLiam Girdwood 			return ret;
149288bd870fSBenoit Cousson 	}
1493f0fba2adSLiam Girdwood 
14940168bf0dSLiam Girdwood 	/* complete DAI probe during last probe */
14950168bf0dSLiam Girdwood 	if (order != SND_SOC_COMP_ORDER_LAST)
14960168bf0dSLiam Girdwood 		return 0;
14970168bf0dSLiam Girdwood 
14985f3484acSLars-Peter Clausen 	/* do machine specific initialization */
14995f3484acSLars-Peter Clausen 	if (dai_link->init) {
15005f3484acSLars-Peter Clausen 		ret = dai_link->init(rtd);
15015f3484acSLars-Peter Clausen 		if (ret < 0) {
15025f3484acSLars-Peter Clausen 			dev_err(card->dev, "ASoC: failed to init %s: %d\n",
15035f3484acSLars-Peter Clausen 				dai_link->name, ret);
15045f3484acSLars-Peter Clausen 			return ret;
15055f3484acSLars-Peter Clausen 		}
15065f3484acSLars-Peter Clausen 	}
15075f3484acSLars-Peter Clausen 
1508a5053a8eSKuninori Morimoto 	if (dai_link->dai_fmt)
1509a5053a8eSKuninori Morimoto 		snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt);
1510a5053a8eSKuninori Morimoto 
15115f3484acSLars-Peter Clausen 	ret = soc_post_component_init(rtd, dai_link->name);
1512589c3563SJarkko Nikula 	if (ret)
1513f0fba2adSLiam Girdwood 		return ret;
1514f0fba2adSLiam Girdwood 
15155f3484acSLars-Peter Clausen #ifdef CONFIG_DEBUG_FS
15165f3484acSLars-Peter Clausen 	/* add DPCM sysfs entries */
15172e55b90aSLars-Peter Clausen 	if (dai_link->dynamic)
15182e55b90aSLars-Peter Clausen 		soc_dpcm_debugfs_add(rtd);
15195f3484acSLars-Peter Clausen #endif
15205f3484acSLars-Peter Clausen 
1521a655de80SLiam Girdwood 	num = rtd->num;
1522a655de80SLiam Girdwood 
1523a655de80SLiam Girdwood 	/*
1524a655de80SLiam Girdwood 	 * most drivers will register their PCMs using DAI link ordering but
1525a655de80SLiam Girdwood 	 * topology based drivers can use the DAI link id field to set PCM
1526a655de80SLiam Girdwood 	 * device number and then use rtd + a base offset of the BEs.
1527a655de80SLiam Girdwood 	 */
1528a655de80SLiam Girdwood 	for_each_rtdcom(rtd, rtdcom) {
1529a655de80SLiam Girdwood 		component = rtdcom->component;
1530a655de80SLiam Girdwood 
1531a655de80SLiam Girdwood 		if (!component->driver->use_dai_pcm_id)
1532a655de80SLiam Girdwood 			continue;
1533a655de80SLiam Girdwood 
1534a655de80SLiam Girdwood 		if (rtd->dai_link->no_pcm)
1535a655de80SLiam Girdwood 			num += component->driver->be_pcm_base;
1536a655de80SLiam Girdwood 		else
1537a655de80SLiam Girdwood 			num = rtd->dai_link->id;
1538a655de80SLiam Girdwood 	}
1539a655de80SLiam Girdwood 
15406f0c4226SJie Yang 	if (cpu_dai->driver->compress_new) {
15411245b700SNamarta Kohli 		/*create compress_device"*/
1542a655de80SLiam Girdwood 		ret = cpu_dai->driver->compress_new(rtd, num);
15431245b700SNamarta Kohli 		if (ret < 0) {
1544f110bfc7SLiam Girdwood 			dev_err(card->dev, "ASoC: can't create compress %s\n",
15451245b700SNamarta Kohli 					 dai_link->stream_name);
15461245b700SNamarta Kohli 			return ret;
15471245b700SNamarta Kohli 		}
15481245b700SNamarta Kohli 	} else {
15491245b700SNamarta Kohli 
1550c74184edSMark Brown 		if (!dai_link->params) {
1551f0fba2adSLiam Girdwood 			/* create the pcm */
1552a655de80SLiam Girdwood 			ret = soc_new_pcm(rtd, num);
1553f0fba2adSLiam Girdwood 			if (ret < 0) {
1554f110bfc7SLiam Girdwood 				dev_err(card->dev, "ASoC: can't create pcm %s :%d\n",
15550837fc62SFabio Estevam 				       dai_link->stream_name, ret);
1556f0fba2adSLiam Girdwood 				return ret;
1557f0fba2adSLiam Girdwood 			}
155825f7b701SArnaud Pouliquen 			ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd);
155925f7b701SArnaud Pouliquen 			if (ret < 0)
156025f7b701SArnaud Pouliquen 				return ret;
156125f7b701SArnaud Pouliquen 			ret = soc_link_dai_pcm_new(rtd->codec_dais,
156225f7b701SArnaud Pouliquen 						   rtd->num_codecs, rtd);
156325f7b701SArnaud Pouliquen 			if (ret < 0)
156425f7b701SArnaud Pouliquen 				return ret;
1565c74184edSMark Brown 		} else {
15669d58a077SRichard Fitzgerald 			INIT_DELAYED_WORK(&rtd->delayed_work,
15679d58a077SRichard Fitzgerald 						codec2codec_close_delayed_work);
1568c74184edSMark Brown 		}
1569c74184edSMark Brown 	}
1570c74184edSMark Brown 
1571f0fba2adSLiam Girdwood 	return 0;
1572f0fba2adSLiam Girdwood }
1573f0fba2adSLiam Girdwood 
157444c69bb1SLars-Peter Clausen static int soc_bind_aux_dev(struct snd_soc_card *card, int num)
1575b19e6e7bSMark Brown {
15763ca041edSSebastian Reichel 	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
1577f2ed6b07SMengdong Lin 	struct snd_soc_component *component;
1578f2ed6b07SMengdong Lin 	const char *name;
1579f2ed6b07SMengdong Lin 	struct device_node *codec_of_node;
15803ca041edSSebastian Reichel 
1581f2ed6b07SMengdong Lin 	if (aux_dev->codec_of_node || aux_dev->codec_name) {
1582f2ed6b07SMengdong Lin 		/* codecs, usually analog devices */
1583f2ed6b07SMengdong Lin 		name = aux_dev->codec_name;
1584f2ed6b07SMengdong Lin 		codec_of_node = aux_dev->codec_of_node;
1585f2ed6b07SMengdong Lin 		component = soc_find_component(codec_of_node, name);
1586f2ed6b07SMengdong Lin 		if (!component) {
1587f2ed6b07SMengdong Lin 			if (codec_of_node)
1588f2ed6b07SMengdong Lin 				name = of_node_full_name(codec_of_node);
1589f2ed6b07SMengdong Lin 			goto err_defer;
1590f2ed6b07SMengdong Lin 		}
1591f2ed6b07SMengdong Lin 	} else if (aux_dev->name) {
1592f2ed6b07SMengdong Lin 		/* generic components */
1593f2ed6b07SMengdong Lin 		name = aux_dev->name;
1594f2ed6b07SMengdong Lin 		component = soc_find_component(NULL, name);
1595f2ed6b07SMengdong Lin 		if (!component)
1596f2ed6b07SMengdong Lin 			goto err_defer;
1597f2ed6b07SMengdong Lin 	} else {
1598f2ed6b07SMengdong Lin 		dev_err(card->dev, "ASoC: Invalid auxiliary device\n");
1599f2ed6b07SMengdong Lin 		return -EINVAL;
1600f2ed6b07SMengdong Lin 	}
16013ca041edSSebastian Reichel 
1602f2ed6b07SMengdong Lin 	component->init = aux_dev->init;
1603d2e3a135SSylwester Nawrocki 	list_add(&component->card_aux_list, &card->aux_comp_list);
16041a653aa4SKuninori Morimoto 
1605f2ed6b07SMengdong Lin 	return 0;
1606f2ed6b07SMengdong Lin 
1607f2ed6b07SMengdong Lin err_defer:
160865d9361fSLars-Peter Clausen 	dev_err(card->dev, "ASoC: %s not registered\n", name);
1609b19e6e7bSMark Brown 	return -EPROBE_DEFER;
1610b19e6e7bSMark Brown }
1611b19e6e7bSMark Brown 
1612f2ed6b07SMengdong Lin static int soc_probe_aux_devices(struct snd_soc_card *card)
1613f2ed6b07SMengdong Lin {
1614991454e1SKuninori Morimoto 	struct snd_soc_component *comp;
1615f2ed6b07SMengdong Lin 	int order;
1616f2ed6b07SMengdong Lin 	int ret;
1617f2ed6b07SMengdong Lin 
1618f2ed6b07SMengdong Lin 	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
1619f2ed6b07SMengdong Lin 		order++) {
1620991454e1SKuninori Morimoto 		list_for_each_entry(comp, &card->aux_comp_list, card_aux_list) {
1621f2ed6b07SMengdong Lin 			if (comp->driver->probe_order == order) {
1622f2ed6b07SMengdong Lin 				ret = soc_probe_component(card,	comp);
1623f2ed6b07SMengdong Lin 				if (ret < 0) {
1624f2ed6b07SMengdong Lin 					dev_err(card->dev,
1625f2ed6b07SMengdong Lin 						"ASoC: failed to probe aux component %s %d\n",
1626f2ed6b07SMengdong Lin 						comp->name, ret);
1627f2ed6b07SMengdong Lin 					return ret;
1628f2ed6b07SMengdong Lin 				}
1629f2ed6b07SMengdong Lin 			}
1630f2ed6b07SMengdong Lin 		}
1631f2ed6b07SMengdong Lin 	}
163265d9361fSLars-Peter Clausen 
163344c69bb1SLars-Peter Clausen 	return 0;
16343ca041edSSebastian Reichel }
16352eea392dSJarkko Nikula 
1636f2ed6b07SMengdong Lin static void soc_remove_aux_devices(struct snd_soc_card *card)
163744c69bb1SLars-Peter Clausen {
1638f2ed6b07SMengdong Lin 	struct snd_soc_component *comp, *_comp;
1639f2ed6b07SMengdong Lin 	int order;
164044c69bb1SLars-Peter Clausen 
1641f2ed6b07SMengdong Lin 	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
1642f2ed6b07SMengdong Lin 		order++) {
1643f2ed6b07SMengdong Lin 		list_for_each_entry_safe(comp, _comp,
1644991454e1SKuninori Morimoto 			&card->aux_comp_list, card_aux_list) {
16451a653aa4SKuninori Morimoto 
1646f2ed6b07SMengdong Lin 			if (comp->driver->remove_order == order) {
1647f2ed6b07SMengdong Lin 				soc_remove_component(comp);
1648991454e1SKuninori Morimoto 				/* remove it from the card's aux_comp_list */
1649991454e1SKuninori Morimoto 				list_del(&comp->card_aux_list);
16502eea392dSJarkko Nikula 			}
16515f3484acSLars-Peter Clausen 		}
16522eea392dSJarkko Nikula 	}
16532eea392dSJarkko Nikula }
16542eea392dSJarkko Nikula 
1655ce64c8b9SLars-Peter Clausen /**
1656ce64c8b9SLars-Peter Clausen  * snd_soc_runtime_set_dai_fmt() - Change DAI link format for a ASoC runtime
1657ce64c8b9SLars-Peter Clausen  * @rtd: The runtime for which the DAI link format should be changed
1658ce64c8b9SLars-Peter Clausen  * @dai_fmt: The new DAI link format
1659ce64c8b9SLars-Peter Clausen  *
1660ce64c8b9SLars-Peter Clausen  * This function updates the DAI link format for all DAIs connected to the DAI
1661ce64c8b9SLars-Peter Clausen  * link for the specified runtime.
1662ce64c8b9SLars-Peter Clausen  *
1663ce64c8b9SLars-Peter Clausen  * Note: For setups with a static format set the dai_fmt field in the
1664ce64c8b9SLars-Peter Clausen  * corresponding snd_dai_link struct instead of using this function.
1665ce64c8b9SLars-Peter Clausen  *
1666ce64c8b9SLars-Peter Clausen  * Returns 0 on success, otherwise a negative error code.
1667ce64c8b9SLars-Peter Clausen  */
1668ce64c8b9SLars-Peter Clausen int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
1669ce64c8b9SLars-Peter Clausen 	unsigned int dai_fmt)
1670ce64c8b9SLars-Peter Clausen {
1671ce64c8b9SLars-Peter Clausen 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
16720b7990e3SKuninori Morimoto 	struct snd_soc_dai *codec_dai;
1673ce64c8b9SLars-Peter Clausen 	unsigned int i;
1674ce64c8b9SLars-Peter Clausen 	int ret;
1675ce64c8b9SLars-Peter Clausen 
16760b7990e3SKuninori Morimoto 	for_each_rtd_codec_dai(rtd, i, codec_dai) {
1677ce64c8b9SLars-Peter Clausen 		ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
1678ce64c8b9SLars-Peter Clausen 		if (ret != 0 && ret != -ENOTSUPP) {
1679ce64c8b9SLars-Peter Clausen 			dev_warn(codec_dai->dev,
1680ce64c8b9SLars-Peter Clausen 				 "ASoC: Failed to set DAI format: %d\n", ret);
1681ce64c8b9SLars-Peter Clausen 			return ret;
1682ce64c8b9SLars-Peter Clausen 		}
1683ce64c8b9SLars-Peter Clausen 	}
1684ce64c8b9SLars-Peter Clausen 
1685ce64c8b9SLars-Peter Clausen 	/* Flip the polarity for the "CPU" end of a CODEC<->CODEC link */
1686cb2cf0deSKuninori Morimoto 	/* the component which has non_legacy_dai_naming is Codec */
1687999f7f5aSKuninori Morimoto 	if (cpu_dai->component->driver->non_legacy_dai_naming) {
1688ce64c8b9SLars-Peter Clausen 		unsigned int inv_dai_fmt;
1689ce64c8b9SLars-Peter Clausen 
1690ce64c8b9SLars-Peter Clausen 		inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_MASTER_MASK;
1691ce64c8b9SLars-Peter Clausen 		switch (dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1692ce64c8b9SLars-Peter Clausen 		case SND_SOC_DAIFMT_CBM_CFM:
1693ce64c8b9SLars-Peter Clausen 			inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
1694ce64c8b9SLars-Peter Clausen 			break;
1695ce64c8b9SLars-Peter Clausen 		case SND_SOC_DAIFMT_CBM_CFS:
1696ce64c8b9SLars-Peter Clausen 			inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFM;
1697ce64c8b9SLars-Peter Clausen 			break;
1698ce64c8b9SLars-Peter Clausen 		case SND_SOC_DAIFMT_CBS_CFM:
1699ce64c8b9SLars-Peter Clausen 			inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFS;
1700ce64c8b9SLars-Peter Clausen 			break;
1701ce64c8b9SLars-Peter Clausen 		case SND_SOC_DAIFMT_CBS_CFS:
1702ce64c8b9SLars-Peter Clausen 			inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
1703ce64c8b9SLars-Peter Clausen 			break;
1704ce64c8b9SLars-Peter Clausen 		}
1705ce64c8b9SLars-Peter Clausen 
1706ce64c8b9SLars-Peter Clausen 		dai_fmt = inv_dai_fmt;
1707ce64c8b9SLars-Peter Clausen 	}
1708ce64c8b9SLars-Peter Clausen 
1709ce64c8b9SLars-Peter Clausen 	ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
1710ce64c8b9SLars-Peter Clausen 	if (ret != 0 && ret != -ENOTSUPP) {
1711ce64c8b9SLars-Peter Clausen 		dev_warn(cpu_dai->dev,
1712ce64c8b9SLars-Peter Clausen 			 "ASoC: Failed to set DAI format: %d\n", ret);
1713ce64c8b9SLars-Peter Clausen 		return ret;
1714ce64c8b9SLars-Peter Clausen 	}
1715ce64c8b9SLars-Peter Clausen 
1716ce64c8b9SLars-Peter Clausen 	return 0;
1717ce64c8b9SLars-Peter Clausen }
1718ddaca25aSLars-Peter Clausen EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt);
1719ce64c8b9SLars-Peter Clausen 
1720345233d7SLiam Girdwood 
17211f5a4535STakashi Iwai #ifdef CONFIG_DMI
1722345233d7SLiam Girdwood /* Trim special characters, and replace '-' with '_' since '-' is used to
1723345233d7SLiam Girdwood  * separate different DMI fields in the card long name. Only number and
1724345233d7SLiam Girdwood  * alphabet characters and a few separator characters are kept.
1725345233d7SLiam Girdwood  */
1726345233d7SLiam Girdwood static void cleanup_dmi_name(char *name)
1727345233d7SLiam Girdwood {
1728345233d7SLiam Girdwood 	int i, j = 0;
1729345233d7SLiam Girdwood 
1730345233d7SLiam Girdwood 	for (i = 0; name[i]; i++) {
1731345233d7SLiam Girdwood 		if (isalnum(name[i]) || (name[i] == '.')
1732345233d7SLiam Girdwood 		    || (name[i] == '_'))
1733345233d7SLiam Girdwood 			name[j++] = name[i];
1734345233d7SLiam Girdwood 		else if (name[i] == '-')
1735345233d7SLiam Girdwood 			name[j++] = '_';
1736345233d7SLiam Girdwood 	}
1737345233d7SLiam Girdwood 
1738345233d7SLiam Girdwood 	name[j] = '\0';
1739345233d7SLiam Girdwood }
1740345233d7SLiam Girdwood 
174198faf436SMengdong Lin /* Check if a DMI field is valid, i.e. not containing any string
174298faf436SMengdong Lin  * in the black list.
174398faf436SMengdong Lin  */
174498faf436SMengdong Lin static int is_dmi_valid(const char *field)
174598faf436SMengdong Lin {
174698faf436SMengdong Lin 	int i = 0;
174798faf436SMengdong Lin 
174898faf436SMengdong Lin 	while (dmi_blacklist[i]) {
174998faf436SMengdong Lin 		if (strstr(field, dmi_blacklist[i]))
175098faf436SMengdong Lin 			return 0;
175198faf436SMengdong Lin 		i++;
175246b5a4d2SWu Fengguang 	}
175398faf436SMengdong Lin 
175498faf436SMengdong Lin 	return 1;
175598faf436SMengdong Lin }
175698faf436SMengdong Lin 
1757345233d7SLiam Girdwood /**
1758345233d7SLiam Girdwood  * snd_soc_set_dmi_name() - Register DMI names to card
1759345233d7SLiam Girdwood  * @card: The card to register DMI names
1760345233d7SLiam Girdwood  * @flavour: The flavour "differentiator" for the card amongst its peers.
1761345233d7SLiam Girdwood  *
1762345233d7SLiam Girdwood  * An Intel machine driver may be used by many different devices but are
1763345233d7SLiam Girdwood  * difficult for userspace to differentiate, since machine drivers ususally
1764345233d7SLiam Girdwood  * use their own name as the card short name and leave the card long name
1765345233d7SLiam Girdwood  * blank. To differentiate such devices and fix bugs due to lack of
1766345233d7SLiam Girdwood  * device-specific configurations, this function allows DMI info to be used
1767345233d7SLiam Girdwood  * as the sound card long name, in the format of
1768345233d7SLiam Girdwood  * "vendor-product-version-board"
1769345233d7SLiam Girdwood  * (Character '-' is used to separate different DMI fields here).
1770345233d7SLiam Girdwood  * This will help the user space to load the device-specific Use Case Manager
1771345233d7SLiam Girdwood  * (UCM) configurations for the card.
1772345233d7SLiam Girdwood  *
1773345233d7SLiam Girdwood  * Possible card long names may be:
1774345233d7SLiam Girdwood  * DellInc.-XPS139343-01-0310JH
1775345233d7SLiam Girdwood  * ASUSTeKCOMPUTERINC.-T100TA-1.0-T100TA
1776345233d7SLiam Girdwood  * Circuitco-MinnowboardMaxD0PLATFORM-D0-MinnowBoardMAX
1777345233d7SLiam Girdwood  *
1778345233d7SLiam Girdwood  * This function also supports flavoring the card longname to provide
1779345233d7SLiam Girdwood  * the extra differentiation, like "vendor-product-version-board-flavor".
1780345233d7SLiam Girdwood  *
1781345233d7SLiam Girdwood  * We only keep number and alphabet characters and a few separator characters
1782345233d7SLiam Girdwood  * in the card long name since UCM in the user space uses the card long names
1783345233d7SLiam Girdwood  * as card configuration directory names and AudoConf cannot support special
1784345233d7SLiam Girdwood  * charactors like SPACE.
1785345233d7SLiam Girdwood  *
1786345233d7SLiam Girdwood  * Returns 0 on success, otherwise a negative error code.
1787345233d7SLiam Girdwood  */
1788345233d7SLiam Girdwood int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour)
1789345233d7SLiam Girdwood {
1790345233d7SLiam Girdwood 	const char *vendor, *product, *product_version, *board;
1791345233d7SLiam Girdwood 	size_t longname_buf_size = sizeof(card->snd_card->longname);
1792345233d7SLiam Girdwood 	size_t len;
1793345233d7SLiam Girdwood 
1794345233d7SLiam Girdwood 	if (card->long_name)
1795345233d7SLiam Girdwood 		return 0; /* long name already set by driver or from DMI */
1796345233d7SLiam Girdwood 
1797345233d7SLiam Girdwood 	/* make up dmi long name as: vendor.product.version.board */
1798345233d7SLiam Girdwood 	vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
179998faf436SMengdong Lin 	if (!vendor || !is_dmi_valid(vendor)) {
1800345233d7SLiam Girdwood 		dev_warn(card->dev, "ASoC: no DMI vendor name!\n");
1801345233d7SLiam Girdwood 		return 0;
1802345233d7SLiam Girdwood 	}
1803345233d7SLiam Girdwood 
180498faf436SMengdong Lin 
1805345233d7SLiam Girdwood 	snprintf(card->dmi_longname, sizeof(card->snd_card->longname),
1806345233d7SLiam Girdwood 			 "%s", vendor);
1807345233d7SLiam Girdwood 	cleanup_dmi_name(card->dmi_longname);
1808345233d7SLiam Girdwood 
1809345233d7SLiam Girdwood 	product = dmi_get_system_info(DMI_PRODUCT_NAME);
181098faf436SMengdong Lin 	if (product && is_dmi_valid(product)) {
1811345233d7SLiam Girdwood 		len = strlen(card->dmi_longname);
1812345233d7SLiam Girdwood 		snprintf(card->dmi_longname + len,
1813345233d7SLiam Girdwood 			 longname_buf_size - len,
1814345233d7SLiam Girdwood 			 "-%s", product);
1815345233d7SLiam Girdwood 
1816345233d7SLiam Girdwood 		len++;	/* skip the separator "-" */
1817345233d7SLiam Girdwood 		if (len < longname_buf_size)
1818345233d7SLiam Girdwood 			cleanup_dmi_name(card->dmi_longname + len);
1819345233d7SLiam Girdwood 
1820345233d7SLiam Girdwood 		/* some vendors like Lenovo may only put a self-explanatory
1821345233d7SLiam Girdwood 		 * name in the product version field
1822345233d7SLiam Girdwood 		 */
1823345233d7SLiam Girdwood 		product_version = dmi_get_system_info(DMI_PRODUCT_VERSION);
182498faf436SMengdong Lin 		if (product_version && is_dmi_valid(product_version)) {
1825345233d7SLiam Girdwood 			len = strlen(card->dmi_longname);
1826345233d7SLiam Girdwood 			snprintf(card->dmi_longname + len,
1827345233d7SLiam Girdwood 				 longname_buf_size - len,
1828345233d7SLiam Girdwood 				 "-%s", product_version);
1829345233d7SLiam Girdwood 
1830345233d7SLiam Girdwood 			len++;
1831345233d7SLiam Girdwood 			if (len < longname_buf_size)
1832345233d7SLiam Girdwood 				cleanup_dmi_name(card->dmi_longname + len);
1833345233d7SLiam Girdwood 		}
1834345233d7SLiam Girdwood 	}
1835345233d7SLiam Girdwood 
1836345233d7SLiam Girdwood 	board = dmi_get_system_info(DMI_BOARD_NAME);
183798faf436SMengdong Lin 	if (board && is_dmi_valid(board)) {
1838345233d7SLiam Girdwood 		len = strlen(card->dmi_longname);
1839345233d7SLiam Girdwood 		snprintf(card->dmi_longname + len,
1840345233d7SLiam Girdwood 			 longname_buf_size - len,
1841345233d7SLiam Girdwood 			 "-%s", board);
1842345233d7SLiam Girdwood 
1843345233d7SLiam Girdwood 		len++;
1844345233d7SLiam Girdwood 		if (len < longname_buf_size)
1845345233d7SLiam Girdwood 			cleanup_dmi_name(card->dmi_longname + len);
1846345233d7SLiam Girdwood 	} else if (!product) {
1847345233d7SLiam Girdwood 		/* fall back to using legacy name */
1848345233d7SLiam Girdwood 		dev_warn(card->dev, "ASoC: no DMI board/product name!\n");
1849345233d7SLiam Girdwood 		return 0;
1850345233d7SLiam Girdwood 	}
1851345233d7SLiam Girdwood 
1852345233d7SLiam Girdwood 	/* Add flavour to dmi long name */
1853345233d7SLiam Girdwood 	if (flavour) {
1854345233d7SLiam Girdwood 		len = strlen(card->dmi_longname);
1855345233d7SLiam Girdwood 		snprintf(card->dmi_longname + len,
1856345233d7SLiam Girdwood 			 longname_buf_size - len,
1857345233d7SLiam Girdwood 			 "-%s", flavour);
1858345233d7SLiam Girdwood 
1859345233d7SLiam Girdwood 		len++;
1860345233d7SLiam Girdwood 		if (len < longname_buf_size)
1861345233d7SLiam Girdwood 			cleanup_dmi_name(card->dmi_longname + len);
1862345233d7SLiam Girdwood 	}
1863345233d7SLiam Girdwood 
1864345233d7SLiam Girdwood 	/* set the card long name */
1865345233d7SLiam Girdwood 	card->long_name = card->dmi_longname;
1866345233d7SLiam Girdwood 
1867345233d7SLiam Girdwood 	return 0;
1868345233d7SLiam Girdwood }
1869345233d7SLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_set_dmi_name);
18701f5a4535STakashi Iwai #endif /* CONFIG_DMI */
1871345233d7SLiam Girdwood 
1872a655de80SLiam Girdwood static void soc_check_tplg_fes(struct snd_soc_card *card)
1873a655de80SLiam Girdwood {
1874a655de80SLiam Girdwood 	struct snd_soc_component *component;
1875a655de80SLiam Girdwood 	const struct snd_soc_component_driver *comp_drv;
1876a655de80SLiam Girdwood 	struct snd_soc_dai_link *dai_link;
1877a655de80SLiam Girdwood 	int i;
1878a655de80SLiam Girdwood 
1879a655de80SLiam Girdwood 	list_for_each_entry(component, &component_list, list) {
1880a655de80SLiam Girdwood 
1881a655de80SLiam Girdwood 		/* does this component override FEs ? */
1882a655de80SLiam Girdwood 		if (!component->driver->ignore_machine)
1883a655de80SLiam Girdwood 			continue;
1884a655de80SLiam Girdwood 
1885a655de80SLiam Girdwood 		/* for this machine ? */
1886a655de80SLiam Girdwood 		if (strcmp(component->driver->ignore_machine,
1887a655de80SLiam Girdwood 			   card->dev->driver->name))
1888a655de80SLiam Girdwood 			continue;
1889a655de80SLiam Girdwood 
1890a655de80SLiam Girdwood 		/* machine matches, so override the rtd data */
1891a655de80SLiam Girdwood 		for (i = 0; i < card->num_links; i++) {
1892a655de80SLiam Girdwood 
1893a655de80SLiam Girdwood 			dai_link = &card->dai_link[i];
1894a655de80SLiam Girdwood 
1895a655de80SLiam Girdwood 			/* ignore this FE */
1896a655de80SLiam Girdwood 			if (dai_link->dynamic) {
1897a655de80SLiam Girdwood 				dai_link->ignore = true;
1898a655de80SLiam Girdwood 				continue;
1899a655de80SLiam Girdwood 			}
1900a655de80SLiam Girdwood 
1901a655de80SLiam Girdwood 			dev_info(card->dev, "info: override FE DAI link %s\n",
1902a655de80SLiam Girdwood 				 card->dai_link[i].name);
1903a655de80SLiam Girdwood 
1904a655de80SLiam Girdwood 			/* override platform component */
1905daecf46eSKuninori Morimoto 			if (snd_soc_init_platform(card, dai_link) < 0) {
1906daecf46eSKuninori Morimoto 				dev_err(card->dev, "init platform error");
1907daecf46eSKuninori Morimoto 				continue;
1908daecf46eSKuninori Morimoto 			}
1909daecf46eSKuninori Morimoto 			dai_link->platform->name = component->name;
1910a655de80SLiam Girdwood 
1911a655de80SLiam Girdwood 			/* convert non BE into BE */
1912a655de80SLiam Girdwood 			dai_link->no_pcm = 1;
1913a655de80SLiam Girdwood 
1914a655de80SLiam Girdwood 			/* override any BE fixups */
1915a655de80SLiam Girdwood 			dai_link->be_hw_params_fixup =
1916a655de80SLiam Girdwood 				component->driver->be_hw_params_fixup;
1917a655de80SLiam Girdwood 
1918a655de80SLiam Girdwood 			/* most BE links don't set stream name, so set it to
1919a655de80SLiam Girdwood 			 * dai link name if it's NULL to help bind widgets.
1920a655de80SLiam Girdwood 			 */
1921a655de80SLiam Girdwood 			if (!dai_link->stream_name)
1922a655de80SLiam Girdwood 				dai_link->stream_name = dai_link->name;
1923a655de80SLiam Girdwood 		}
1924a655de80SLiam Girdwood 
1925a655de80SLiam Girdwood 		/* Inform userspace we are using alternate topology */
1926a655de80SLiam Girdwood 		if (component->driver->topology_name_prefix) {
1927a655de80SLiam Girdwood 
1928a655de80SLiam Girdwood 			/* topology shortname created ? */
1929a655de80SLiam Girdwood 			if (!card->topology_shortname_created) {
1930a655de80SLiam Girdwood 				comp_drv = component->driver;
1931a655de80SLiam Girdwood 
1932a655de80SLiam Girdwood 				snprintf(card->topology_shortname, 32, "%s-%s",
1933a655de80SLiam Girdwood 					 comp_drv->topology_name_prefix,
1934a655de80SLiam Girdwood 					 card->name);
1935a655de80SLiam Girdwood 				card->topology_shortname_created = true;
1936a655de80SLiam Girdwood 			}
1937a655de80SLiam Girdwood 
1938a655de80SLiam Girdwood 			/* use topology shortname */
1939a655de80SLiam Girdwood 			card->name = card->topology_shortname;
1940a655de80SLiam Girdwood 		}
1941a655de80SLiam Girdwood 	}
1942a655de80SLiam Girdwood }
1943a655de80SLiam Girdwood 
1944b19e6e7bSMark Brown static int snd_soc_instantiate_card(struct snd_soc_card *card)
1945f0fba2adSLiam Girdwood {
19461a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
194761b0088bSMengdong Lin 	struct snd_soc_dai_link *dai_link;
1948ce64c8b9SLars-Peter Clausen 	int ret, i, order;
194996dd3622SMark Brown 
195034e81ab4SLars-Peter Clausen 	mutex_lock(&client_mutex);
195101b9d99aSLiam Girdwood 	mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
1952f0fba2adSLiam Girdwood 
1953a655de80SLiam Girdwood 	/* check whether any platform is ignore machine FE and using topology */
1954a655de80SLiam Girdwood 	soc_check_tplg_fes(card);
1955a655de80SLiam Girdwood 
1956b19e6e7bSMark Brown 	/* bind DAIs */
1957b19e6e7bSMark Brown 	for (i = 0; i < card->num_links; i++) {
19586f2f1ff0SMengdong Lin 		ret = soc_bind_dai_link(card, &card->dai_link[i]);
1959b19e6e7bSMark Brown 		if (ret != 0)
1960b19e6e7bSMark Brown 			goto base_error;
1961db2a4165SFrank Mandarino 	}
1962db2a4165SFrank Mandarino 
196344c69bb1SLars-Peter Clausen 	/* bind aux_devs too */
1964b19e6e7bSMark Brown 	for (i = 0; i < card->num_aux_devs; i++) {
196544c69bb1SLars-Peter Clausen 		ret = soc_bind_aux_dev(card, i);
1966b19e6e7bSMark Brown 		if (ret != 0)
1967b19e6e7bSMark Brown 			goto base_error;
1968db2a4165SFrank Mandarino 	}
1969db2a4165SFrank Mandarino 
1970f8f80361SMengdong Lin 	/* add predefined DAI links to the list */
1971f8f80361SMengdong Lin 	for (i = 0; i < card->num_links; i++)
1972f8f80361SMengdong Lin 		snd_soc_add_dai_link(card, card->dai_link+i);
1973f8f80361SMengdong Lin 
1974f0fba2adSLiam Girdwood 	/* card bind complete so register a sound card */
1975102b5a8dSTakashi Iwai 	ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
1976f0fba2adSLiam Girdwood 			card->owner, 0, &card->snd_card);
1977f0fba2adSLiam Girdwood 	if (ret < 0) {
197810e8aa9aSMichał Mirosław 		dev_err(card->dev,
197910e8aa9aSMichał Mirosław 			"ASoC: can't create sound card for card %s: %d\n",
198010e8aa9aSMichał Mirosław 			card->name, ret);
1981b19e6e7bSMark Brown 		goto base_error;
1982db2a4165SFrank Mandarino 	}
1983db2a4165SFrank Mandarino 
19840757d834SLars-Peter Clausen 	soc_init_card_debugfs(card);
19850757d834SLars-Peter Clausen 
1986e37a4970SMark Brown 	card->dapm.bias_level = SND_SOC_BIAS_OFF;
1987e37a4970SMark Brown 	card->dapm.dev = card->dev;
1988e37a4970SMark Brown 	card->dapm.card = card;
1989e37a4970SMark Brown 	list_add(&card->dapm.list, &card->dapm_list);
1990e37a4970SMark Brown 
1991d5d1e0beSLars-Peter Clausen #ifdef CONFIG_DEBUG_FS
1992d5d1e0beSLars-Peter Clausen 	snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root);
1993d5d1e0beSLars-Peter Clausen #endif
1994d5d1e0beSLars-Peter Clausen 
199588ee1c61SMark Brown #ifdef CONFIG_PM_SLEEP
19966ed25978SAndy Green 	/* deferred resume work */
19976308419aSMark Brown 	INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
19981301a964SRandy Dunlap #endif
19996ed25978SAndy Green 
20009a841ebbSMark Brown 	if (card->dapm_widgets)
20019a841ebbSMark Brown 		snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
20029a841ebbSMark Brown 					  card->num_dapm_widgets);
20039a841ebbSMark Brown 
2004f23e860eSNicolin Chen 	if (card->of_dapm_widgets)
2005f23e860eSNicolin Chen 		snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets,
2006f23e860eSNicolin Chen 					  card->num_of_dapm_widgets);
2007f23e860eSNicolin Chen 
2008f0fba2adSLiam Girdwood 	/* initialise the sound card only once */
2009f0fba2adSLiam Girdwood 	if (card->probe) {
2010e7361ec4SMark Brown 		ret = card->probe(card);
2011f0fba2adSLiam Girdwood 		if (ret < 0)
2012f0fba2adSLiam Girdwood 			goto card_probe_error;
2013f0fba2adSLiam Girdwood 	}
2014f0fba2adSLiam Girdwood 
201562ae68faSStephen Warren 	/* probe all components used by DAI links on this card */
20160168bf0dSLiam Girdwood 	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
20170168bf0dSLiam Girdwood 			order++) {
20181a497983SMengdong Lin 		list_for_each_entry(rtd, &card->rtd_list, list) {
20191a497983SMengdong Lin 			ret = soc_probe_link_components(card, rtd, order);
202062ae68faSStephen Warren 			if (ret < 0) {
2021f110bfc7SLiam Girdwood 				dev_err(card->dev,
2022f110bfc7SLiam Girdwood 					"ASoC: failed to instantiate card %d\n",
2023f110bfc7SLiam Girdwood 					ret);
202462ae68faSStephen Warren 				goto probe_dai_err;
202562ae68faSStephen Warren 			}
202662ae68faSStephen Warren 		}
202762ae68faSStephen Warren 	}
202862ae68faSStephen Warren 
2029f2ed6b07SMengdong Lin 	/* probe auxiliary components */
2030f2ed6b07SMengdong Lin 	ret = soc_probe_aux_devices(card);
2031f2ed6b07SMengdong Lin 	if (ret < 0)
2032f2ed6b07SMengdong Lin 		goto probe_dai_err;
2033f2ed6b07SMengdong Lin 
203461b0088bSMengdong Lin 	/* Find new DAI links added during probing components and bind them.
203561b0088bSMengdong Lin 	 * Components with topology may bring new DAIs and DAI links.
203661b0088bSMengdong Lin 	 */
203761b0088bSMengdong Lin 	list_for_each_entry(dai_link, &card->dai_link_list, list) {
203861b0088bSMengdong Lin 		if (soc_is_dai_link_bound(card, dai_link))
203961b0088bSMengdong Lin 			continue;
204061b0088bSMengdong Lin 
204161b0088bSMengdong Lin 		ret = soc_init_dai_link(card, dai_link);
204261b0088bSMengdong Lin 		if (ret)
204361b0088bSMengdong Lin 			goto probe_dai_err;
204461b0088bSMengdong Lin 		ret = soc_bind_dai_link(card, dai_link);
204561b0088bSMengdong Lin 		if (ret)
204661b0088bSMengdong Lin 			goto probe_dai_err;
204761b0088bSMengdong Lin 	}
204861b0088bSMengdong Lin 
204962ae68faSStephen Warren 	/* probe all DAI links on this card */
205062ae68faSStephen Warren 	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
205162ae68faSStephen Warren 			order++) {
20521a497983SMengdong Lin 		list_for_each_entry(rtd, &card->rtd_list, list) {
20531a497983SMengdong Lin 			ret = soc_probe_link_dais(card, rtd, order);
2054fe3e78e0SMark Brown 			if (ret < 0) {
2055f110bfc7SLiam Girdwood 				dev_err(card->dev,
2056f110bfc7SLiam Girdwood 					"ASoC: failed to instantiate card %d\n",
2057f110bfc7SLiam Girdwood 					ret);
2058f0fba2adSLiam Girdwood 				goto probe_dai_err;
2059fe3e78e0SMark Brown 			}
2060fe3e78e0SMark Brown 		}
20610168bf0dSLiam Girdwood 	}
2062fe3e78e0SMark Brown 
2063888df395SMark Brown 	snd_soc_dapm_link_dai_widgets(card);
2064b893ea5fSLiam Girdwood 	snd_soc_dapm_connect_dai_link_widgets(card);
2065888df395SMark Brown 
2066b7af1dafSMark Brown 	if (card->controls)
2067022658beSLiam Girdwood 		snd_soc_add_card_controls(card, card->controls, card->num_controls);
2068b7af1dafSMark Brown 
2069b8ad29deSMark Brown 	if (card->dapm_routes)
2070b8ad29deSMark Brown 		snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
2071b8ad29deSMark Brown 					card->num_dapm_routes);
2072b8ad29deSMark Brown 
2073f23e860eSNicolin Chen 	if (card->of_dapm_routes)
2074f23e860eSNicolin Chen 		snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes,
2075f23e860eSNicolin Chen 					card->num_of_dapm_routes);
207675d9ac46SMark Brown 
2077861886d3STakashi Iwai 	/* try to set some sane longname if DMI is available */
2078861886d3STakashi Iwai 	snd_soc_set_dmi_name(card, NULL);
2079861886d3STakashi Iwai 
2080f0fba2adSLiam Girdwood 	snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
2081fe3e78e0SMark Brown 		 "%s", card->name);
2082f0fba2adSLiam Girdwood 	snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
208322de71baSLiam Girdwood 		 "%s", card->long_name ? card->long_name : card->name);
2084f0e8ed85SMark Brown 	snprintf(card->snd_card->driver, sizeof(card->snd_card->driver),
2085f0e8ed85SMark Brown 		 "%s", card->driver_name ? card->driver_name : card->name);
2086f0e8ed85SMark Brown 	for (i = 0; i < ARRAY_SIZE(card->snd_card->driver); i++) {
2087f0e8ed85SMark Brown 		switch (card->snd_card->driver[i]) {
2088f0e8ed85SMark Brown 		case '_':
2089f0e8ed85SMark Brown 		case '-':
2090f0e8ed85SMark Brown 		case '\0':
2091f0e8ed85SMark Brown 			break;
2092f0e8ed85SMark Brown 		default:
2093f0e8ed85SMark Brown 			if (!isalnum(card->snd_card->driver[i]))
2094f0e8ed85SMark Brown 				card->snd_card->driver[i] = '_';
2095f0e8ed85SMark Brown 			break;
2096f0e8ed85SMark Brown 		}
2097f0e8ed85SMark Brown 	}
2098fe3e78e0SMark Brown 
209928e9ad92SMark Brown 	if (card->late_probe) {
210028e9ad92SMark Brown 		ret = card->late_probe(card);
210128e9ad92SMark Brown 		if (ret < 0) {
2102f110bfc7SLiam Girdwood 			dev_err(card->dev, "ASoC: %s late_probe() failed: %d\n",
210328e9ad92SMark Brown 				card->name, ret);
210428e9ad92SMark Brown 			goto probe_aux_dev_err;
210528e9ad92SMark Brown 		}
210628e9ad92SMark Brown 	}
210728e9ad92SMark Brown 
2108824ef826SLars-Peter Clausen 	snd_soc_dapm_new_widgets(card);
21098c193b8dSLars-Peter Clausen 
2110f0fba2adSLiam Girdwood 	ret = snd_card_register(card->snd_card);
2111fe3e78e0SMark Brown 	if (ret < 0) {
2112f110bfc7SLiam Girdwood 		dev_err(card->dev, "ASoC: failed to register soundcard %d\n",
2113f110bfc7SLiam Girdwood 				ret);
21146b3ed785SAxel Lin 		goto probe_aux_dev_err;
2115fe3e78e0SMark Brown 	}
2116fe3e78e0SMark Brown 
2117435c5e25SMark Brown 	card->instantiated = 1;
21184f4c0072SMark Brown 	snd_soc_dapm_sync(&card->dapm);
2119f0fba2adSLiam Girdwood 	mutex_unlock(&card->mutex);
212034e81ab4SLars-Peter Clausen 	mutex_unlock(&client_mutex);
2121b19e6e7bSMark Brown 
2122b19e6e7bSMark Brown 	return 0;
2123db2a4165SFrank Mandarino 
21242eea392dSJarkko Nikula probe_aux_dev_err:
2125f2ed6b07SMengdong Lin 	soc_remove_aux_devices(card);
21262eea392dSJarkko Nikula 
2127f0fba2adSLiam Girdwood probe_dai_err:
21280671fd8eSKuninori Morimoto 	soc_remove_dai_links(card);
2129fe3e78e0SMark Brown 
2130f0fba2adSLiam Girdwood card_probe_error:
213187506549SMark Brown 	if (card->remove)
2132e7361ec4SMark Brown 		card->remove(card);
2133f0fba2adSLiam Girdwood 
21342210438bSLars-Peter Clausen 	snd_soc_dapm_free(&card->dapm);
21350757d834SLars-Peter Clausen 	soc_cleanup_card_debugfs(card);
2136f0fba2adSLiam Girdwood 	snd_card_free(card->snd_card);
2137f0fba2adSLiam Girdwood 
2138b19e6e7bSMark Brown base_error:
21391a497983SMengdong Lin 	soc_remove_pcm_runtimes(card);
2140f0fba2adSLiam Girdwood 	mutex_unlock(&card->mutex);
214134e81ab4SLars-Peter Clausen 	mutex_unlock(&client_mutex);
2142db2a4165SFrank Mandarino 
2143b19e6e7bSMark Brown 	return ret;
2144435c5e25SMark Brown }
2145435c5e25SMark Brown 
2146435c5e25SMark Brown /* probes a new socdev */
2147435c5e25SMark Brown static int soc_probe(struct platform_device *pdev)
2148435c5e25SMark Brown {
2149f0fba2adSLiam Girdwood 	struct snd_soc_card *card = platform_get_drvdata(pdev);
2150435c5e25SMark Brown 
215170a7ca34SVinod Koul 	/*
215270a7ca34SVinod Koul 	 * no card, so machine driver should be registering card
215370a7ca34SVinod Koul 	 * we should not be here in that case so ret error
215470a7ca34SVinod Koul 	 */
215570a7ca34SVinod Koul 	if (!card)
215670a7ca34SVinod Koul 		return -EINVAL;
215770a7ca34SVinod Koul 
2158fe4085e8SMark Brown 	dev_warn(&pdev->dev,
2159f110bfc7SLiam Girdwood 		 "ASoC: machine %s should use snd_soc_register_card()\n",
2160fe4085e8SMark Brown 		 card->name);
2161fe4085e8SMark Brown 
2162435c5e25SMark Brown 	/* Bodge while we unpick instantiation */
2163435c5e25SMark Brown 	card->dev = &pdev->dev;
2164f0fba2adSLiam Girdwood 
216528d528c8SMark Brown 	return snd_soc_register_card(card);
2166435c5e25SMark Brown }
2167435c5e25SMark Brown 
2168b0e26485SVinod Koul static int soc_cleanup_card_resources(struct snd_soc_card *card)
2169db2a4165SFrank Mandarino {
21701a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
2171db2a4165SFrank Mandarino 
2172f0fba2adSLiam Girdwood 	/* make sure any delayed work runs */
21731a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list)
217443829731STejun Heo 		flush_delayed_work(&rtd->delayed_work);
2175db2a4165SFrank Mandarino 
21764efda5f2STakashi Iwai 	/* free the ALSA card at first; this syncs with pending operations */
21774efda5f2STakashi Iwai 	snd_card_free(card->snd_card);
21784efda5f2STakashi Iwai 
2179f0fba2adSLiam Girdwood 	/* remove and free each DAI */
21800671fd8eSKuninori Morimoto 	soc_remove_dai_links(card);
21811a497983SMengdong Lin 	soc_remove_pcm_runtimes(card);
2182f0fba2adSLiam Girdwood 
2183f2ed6b07SMengdong Lin 	/* remove auxiliary devices */
2184f2ed6b07SMengdong Lin 	soc_remove_aux_devices(card);
2185f2ed6b07SMengdong Lin 
2186d1e81428SMark Brown 	snd_soc_dapm_free(&card->dapm);
2187a6052154SJarkko Nikula 	soc_cleanup_card_debugfs(card);
2188a6052154SJarkko Nikula 
2189f0fba2adSLiam Girdwood 	/* remove the card */
219087506549SMark Brown 	if (card->remove)
2191e7361ec4SMark Brown 		card->remove(card);
2192f0fba2adSLiam Girdwood 
2193b0e26485SVinod Koul 	return 0;
2194b2dfa62cSGuennadi Liakhovetski }
2195b0e26485SVinod Koul 
2196b0e26485SVinod Koul /* removes a socdev */
2197b0e26485SVinod Koul static int soc_remove(struct platform_device *pdev)
2198b0e26485SVinod Koul {
2199b0e26485SVinod Koul 	struct snd_soc_card *card = platform_get_drvdata(pdev);
2200b0e26485SVinod Koul 
2201c5af3a2eSMark Brown 	snd_soc_unregister_card(card);
2202db2a4165SFrank Mandarino 	return 0;
2203db2a4165SFrank Mandarino }
2204db2a4165SFrank Mandarino 
22056f8ab4acSMark Brown int snd_soc_poweroff(struct device *dev)
220651737470SMark Brown {
22076f8ab4acSMark Brown 	struct snd_soc_card *card = dev_get_drvdata(dev);
22081a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
220951737470SMark Brown 
221051737470SMark Brown 	if (!card->instantiated)
2211416356fcSMark Brown 		return 0;
221251737470SMark Brown 
221351737470SMark Brown 	/* Flush out pmdown_time work - we actually do want to run it
221451737470SMark Brown 	 * now, we're shutting down so no imminent restart. */
22151a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list)
221643829731STejun Heo 		flush_delayed_work(&rtd->delayed_work);
221751737470SMark Brown 
2218f0fba2adSLiam Girdwood 	snd_soc_dapm_shutdown(card);
2219416356fcSMark Brown 
2220988e8cc4SNicolin Chen 	/* deactivate pins to sleep state */
22211a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
222288bd870fSBenoit Cousson 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
22230b7990e3SKuninori Morimoto 		struct snd_soc_dai *codec_dai;
22241a497983SMengdong Lin 		int i;
222588bd870fSBenoit Cousson 
2226988e8cc4SNicolin Chen 		pinctrl_pm_select_sleep_state(cpu_dai->dev);
22270b7990e3SKuninori Morimoto 		for_each_rtd_codec_dai(rtd, i, codec_dai) {
222888bd870fSBenoit Cousson 			pinctrl_pm_select_sleep_state(codec_dai->dev);
222988bd870fSBenoit Cousson 		}
2230988e8cc4SNicolin Chen 	}
2231988e8cc4SNicolin Chen 
2232416356fcSMark Brown 	return 0;
223351737470SMark Brown }
22346f8ab4acSMark Brown EXPORT_SYMBOL_GPL(snd_soc_poweroff);
223551737470SMark Brown 
22366f8ab4acSMark Brown const struct dev_pm_ops snd_soc_pm_ops = {
2237b1dd5897SViresh Kumar 	.suspend = snd_soc_suspend,
2238b1dd5897SViresh Kumar 	.resume = snd_soc_resume,
2239b1dd5897SViresh Kumar 	.freeze = snd_soc_suspend,
2240b1dd5897SViresh Kumar 	.thaw = snd_soc_resume,
22416f8ab4acSMark Brown 	.poweroff = snd_soc_poweroff,
2242b1dd5897SViresh Kumar 	.restore = snd_soc_resume,
2243416356fcSMark Brown };
2244deb2607eSStephen Warren EXPORT_SYMBOL_GPL(snd_soc_pm_ops);
2245416356fcSMark Brown 
2246db2a4165SFrank Mandarino /* ASoC platform driver */
2247db2a4165SFrank Mandarino static struct platform_driver soc_driver = {
2248db2a4165SFrank Mandarino 	.driver		= {
2249db2a4165SFrank Mandarino 		.name		= "soc-audio",
22506f8ab4acSMark Brown 		.pm		= &snd_soc_pm_ops,
2251db2a4165SFrank Mandarino 	},
2252db2a4165SFrank Mandarino 	.probe		= soc_probe,
2253db2a4165SFrank Mandarino 	.remove		= soc_remove,
2254db2a4165SFrank Mandarino };
2255db2a4165SFrank Mandarino 
2256096e49d5SMark Brown /**
2257db2a4165SFrank Mandarino  * snd_soc_cnew - create new control
2258db2a4165SFrank Mandarino  * @_template: control template
2259db2a4165SFrank Mandarino  * @data: control private data
2260ac11a2b3SMark Brown  * @long_name: control long name
2261efb7ac3fSMark Brown  * @prefix: control name prefix
2262db2a4165SFrank Mandarino  *
2263db2a4165SFrank Mandarino  * Create a new mixer control from a template control.
2264db2a4165SFrank Mandarino  *
2265db2a4165SFrank Mandarino  * Returns 0 for success, else error.
2266db2a4165SFrank Mandarino  */
2267db2a4165SFrank Mandarino struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
22683056557fSMark Brown 				  void *data, const char *long_name,
2269efb7ac3fSMark Brown 				  const char *prefix)
2270db2a4165SFrank Mandarino {
2271db2a4165SFrank Mandarino 	struct snd_kcontrol_new template;
2272efb7ac3fSMark Brown 	struct snd_kcontrol *kcontrol;
2273efb7ac3fSMark Brown 	char *name = NULL;
2274db2a4165SFrank Mandarino 
2275db2a4165SFrank Mandarino 	memcpy(&template, _template, sizeof(template));
2276db2a4165SFrank Mandarino 	template.index = 0;
2277db2a4165SFrank Mandarino 
2278efb7ac3fSMark Brown 	if (!long_name)
2279efb7ac3fSMark Brown 		long_name = template.name;
2280efb7ac3fSMark Brown 
2281efb7ac3fSMark Brown 	if (prefix) {
22822b581074SLars-Peter Clausen 		name = kasprintf(GFP_KERNEL, "%s %s", prefix, long_name);
2283efb7ac3fSMark Brown 		if (!name)
2284efb7ac3fSMark Brown 			return NULL;
2285efb7ac3fSMark Brown 
2286efb7ac3fSMark Brown 		template.name = name;
2287efb7ac3fSMark Brown 	} else {
2288efb7ac3fSMark Brown 		template.name = long_name;
2289efb7ac3fSMark Brown 	}
2290efb7ac3fSMark Brown 
2291efb7ac3fSMark Brown 	kcontrol = snd_ctl_new1(&template, data);
2292efb7ac3fSMark Brown 
2293efb7ac3fSMark Brown 	kfree(name);
2294efb7ac3fSMark Brown 
2295efb7ac3fSMark Brown 	return kcontrol;
2296db2a4165SFrank Mandarino }
2297db2a4165SFrank Mandarino EXPORT_SYMBOL_GPL(snd_soc_cnew);
2298db2a4165SFrank Mandarino 
2299022658beSLiam Girdwood static int snd_soc_add_controls(struct snd_card *card, struct device *dev,
2300022658beSLiam Girdwood 	const struct snd_kcontrol_new *controls, int num_controls,
2301022658beSLiam Girdwood 	const char *prefix, void *data)
2302022658beSLiam Girdwood {
2303022658beSLiam Girdwood 	int err, i;
2304022658beSLiam Girdwood 
2305022658beSLiam Girdwood 	for (i = 0; i < num_controls; i++) {
2306022658beSLiam Girdwood 		const struct snd_kcontrol_new *control = &controls[i];
2307022658beSLiam Girdwood 		err = snd_ctl_add(card, snd_soc_cnew(control, data,
2308022658beSLiam Girdwood 						     control->name, prefix));
2309022658beSLiam Girdwood 		if (err < 0) {
2310f110bfc7SLiam Girdwood 			dev_err(dev, "ASoC: Failed to add %s: %d\n",
2311f110bfc7SLiam Girdwood 				control->name, err);
2312022658beSLiam Girdwood 			return err;
2313022658beSLiam Girdwood 		}
2314022658beSLiam Girdwood 	}
2315022658beSLiam Girdwood 
2316022658beSLiam Girdwood 	return 0;
2317022658beSLiam Girdwood }
2318022658beSLiam Girdwood 
23194fefd698SDimitris Papastamos struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
23204fefd698SDimitris Papastamos 					       const char *name)
23214fefd698SDimitris Papastamos {
23224fefd698SDimitris Papastamos 	struct snd_card *card = soc_card->snd_card;
23234fefd698SDimitris Papastamos 	struct snd_kcontrol *kctl;
23244fefd698SDimitris Papastamos 
23254fefd698SDimitris Papastamos 	if (unlikely(!name))
23264fefd698SDimitris Papastamos 		return NULL;
23274fefd698SDimitris Papastamos 
23284fefd698SDimitris Papastamos 	list_for_each_entry(kctl, &card->controls, list)
23294fefd698SDimitris Papastamos 		if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name)))
23304fefd698SDimitris Papastamos 			return kctl;
23314fefd698SDimitris Papastamos 	return NULL;
23324fefd698SDimitris Papastamos }
23334fefd698SDimitris Papastamos EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol);
23344fefd698SDimitris Papastamos 
2335db2a4165SFrank Mandarino /**
23360f2780adSLars-Peter Clausen  * snd_soc_add_component_controls - Add an array of controls to a component.
23370f2780adSLars-Peter Clausen  *
23380f2780adSLars-Peter Clausen  * @component: Component to add controls to
23390f2780adSLars-Peter Clausen  * @controls: Array of controls to add
23400f2780adSLars-Peter Clausen  * @num_controls: Number of elements in the array
23410f2780adSLars-Peter Clausen  *
23420f2780adSLars-Peter Clausen  * Return: 0 for success, else error.
23430f2780adSLars-Peter Clausen  */
23440f2780adSLars-Peter Clausen int snd_soc_add_component_controls(struct snd_soc_component *component,
23450f2780adSLars-Peter Clausen 	const struct snd_kcontrol_new *controls, unsigned int num_controls)
23460f2780adSLars-Peter Clausen {
23470f2780adSLars-Peter Clausen 	struct snd_card *card = component->card->snd_card;
23480f2780adSLars-Peter Clausen 
23490f2780adSLars-Peter Clausen 	return snd_soc_add_controls(card, component->dev, controls,
23500f2780adSLars-Peter Clausen 			num_controls, component->name_prefix, component);
23510f2780adSLars-Peter Clausen }
23520f2780adSLars-Peter Clausen EXPORT_SYMBOL_GPL(snd_soc_add_component_controls);
23530f2780adSLars-Peter Clausen 
23540f2780adSLars-Peter Clausen /**
2355022658beSLiam Girdwood  * snd_soc_add_card_controls - add an array of controls to a SoC card.
2356022658beSLiam Girdwood  * Convenience function to add a list of controls.
2357022658beSLiam Girdwood  *
2358022658beSLiam Girdwood  * @soc_card: SoC card to add controls to
2359022658beSLiam Girdwood  * @controls: array of controls to add
2360022658beSLiam Girdwood  * @num_controls: number of elements in the array
2361022658beSLiam Girdwood  *
2362022658beSLiam Girdwood  * Return 0 for success, else error.
2363022658beSLiam Girdwood  */
2364022658beSLiam Girdwood int snd_soc_add_card_controls(struct snd_soc_card *soc_card,
2365022658beSLiam Girdwood 	const struct snd_kcontrol_new *controls, int num_controls)
2366022658beSLiam Girdwood {
2367022658beSLiam Girdwood 	struct snd_card *card = soc_card->snd_card;
2368022658beSLiam Girdwood 
2369022658beSLiam Girdwood 	return snd_soc_add_controls(card, soc_card->dev, controls, num_controls,
2370022658beSLiam Girdwood 			NULL, soc_card);
2371022658beSLiam Girdwood }
2372022658beSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_add_card_controls);
2373022658beSLiam Girdwood 
2374022658beSLiam Girdwood /**
2375022658beSLiam Girdwood  * snd_soc_add_dai_controls - add an array of controls to a DAI.
2376022658beSLiam Girdwood  * Convienience function to add a list of controls.
2377022658beSLiam Girdwood  *
2378022658beSLiam Girdwood  * @dai: DAI to add controls to
2379022658beSLiam Girdwood  * @controls: array of controls to add
2380022658beSLiam Girdwood  * @num_controls: number of elements in the array
2381022658beSLiam Girdwood  *
2382022658beSLiam Girdwood  * Return 0 for success, else error.
2383022658beSLiam Girdwood  */
2384022658beSLiam Girdwood int snd_soc_add_dai_controls(struct snd_soc_dai *dai,
2385022658beSLiam Girdwood 	const struct snd_kcontrol_new *controls, int num_controls)
2386022658beSLiam Girdwood {
2387313665b9SLars-Peter Clausen 	struct snd_card *card = dai->component->card->snd_card;
2388022658beSLiam Girdwood 
2389022658beSLiam Girdwood 	return snd_soc_add_controls(card, dai->dev, controls, num_controls,
2390022658beSLiam Girdwood 			NULL, dai);
2391022658beSLiam Girdwood }
2392022658beSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls);
2393022658beSLiam Girdwood 
2394022658beSLiam Girdwood /**
23958c6529dbSLiam Girdwood  * snd_soc_dai_set_sysclk - configure DAI system or master clock.
23968c6529dbSLiam Girdwood  * @dai: DAI
23978c6529dbSLiam Girdwood  * @clk_id: DAI specific clock ID
23988c6529dbSLiam Girdwood  * @freq: new clock frequency in Hz
23998c6529dbSLiam Girdwood  * @dir: new clock direction - input/output.
24008c6529dbSLiam Girdwood  *
24018c6529dbSLiam Girdwood  * Configures the DAI master (MCLK) or system (SYSCLK) clocking.
24028c6529dbSLiam Girdwood  */
24038c6529dbSLiam Girdwood int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
24048c6529dbSLiam Girdwood 	unsigned int freq, int dir)
24058c6529dbSLiam Girdwood {
240646471925SKuninori Morimoto 	if (dai->driver->ops->set_sysclk)
2407f0fba2adSLiam Girdwood 		return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
240871ccef0dSKuninori Morimoto 
240971ccef0dSKuninori Morimoto 	return snd_soc_component_set_sysclk(dai->component, clk_id, 0,
2410ec4ee52aSMark Brown 					    freq, dir);
24118c6529dbSLiam Girdwood }
24128c6529dbSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
24138c6529dbSLiam Girdwood 
24148c6529dbSLiam Girdwood /**
241571ccef0dSKuninori Morimoto  * snd_soc_component_set_sysclk - configure COMPONENT system or master clock.
241671ccef0dSKuninori Morimoto  * @component: COMPONENT
241771ccef0dSKuninori Morimoto  * @clk_id: DAI specific clock ID
241871ccef0dSKuninori Morimoto  * @source: Source for the clock
241971ccef0dSKuninori Morimoto  * @freq: new clock frequency in Hz
242071ccef0dSKuninori Morimoto  * @dir: new clock direction - input/output.
242171ccef0dSKuninori Morimoto  *
242271ccef0dSKuninori Morimoto  * Configures the CODEC master (MCLK) or system (SYSCLK) clocking.
242371ccef0dSKuninori Morimoto  */
242471ccef0dSKuninori Morimoto int snd_soc_component_set_sysclk(struct snd_soc_component *component, int clk_id,
242571ccef0dSKuninori Morimoto 			     int source, unsigned int freq, int dir)
242671ccef0dSKuninori Morimoto {
242771ccef0dSKuninori Morimoto 	if (component->driver->set_sysclk)
242871ccef0dSKuninori Morimoto 		return component->driver->set_sysclk(component, clk_id, source,
242971ccef0dSKuninori Morimoto 						 freq, dir);
243071ccef0dSKuninori Morimoto 
243171ccef0dSKuninori Morimoto 	return -ENOTSUPP;
243271ccef0dSKuninori Morimoto }
243371ccef0dSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_component_set_sysclk);
243471ccef0dSKuninori Morimoto 
243571ccef0dSKuninori Morimoto /**
24368c6529dbSLiam Girdwood  * snd_soc_dai_set_clkdiv - configure DAI clock dividers.
24378c6529dbSLiam Girdwood  * @dai: DAI
2438ac11a2b3SMark Brown  * @div_id: DAI specific clock divider ID
24398c6529dbSLiam Girdwood  * @div: new clock divisor.
24408c6529dbSLiam Girdwood  *
24418c6529dbSLiam Girdwood  * Configures the clock dividers. This is used to derive the best DAI bit and
24428c6529dbSLiam Girdwood  * frame clocks from the system or master clock. It's best to set the DAI bit
24438c6529dbSLiam Girdwood  * and frame clocks as low as possible to save system power.
24448c6529dbSLiam Girdwood  */
24458c6529dbSLiam Girdwood int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
24468c6529dbSLiam Girdwood 	int div_id, int div)
24478c6529dbSLiam Girdwood {
244846471925SKuninori Morimoto 	if (dai->driver->ops->set_clkdiv)
2449f0fba2adSLiam Girdwood 		return dai->driver->ops->set_clkdiv(dai, div_id, div);
24508c6529dbSLiam Girdwood 	else
24518c6529dbSLiam Girdwood 		return -EINVAL;
24528c6529dbSLiam Girdwood }
24538c6529dbSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
24548c6529dbSLiam Girdwood 
24558c6529dbSLiam Girdwood /**
24568c6529dbSLiam Girdwood  * snd_soc_dai_set_pll - configure DAI PLL.
24578c6529dbSLiam Girdwood  * @dai: DAI
24588c6529dbSLiam Girdwood  * @pll_id: DAI specific PLL ID
245985488037SMark Brown  * @source: DAI specific source for the PLL
24608c6529dbSLiam Girdwood  * @freq_in: PLL input clock frequency in Hz
24618c6529dbSLiam Girdwood  * @freq_out: requested PLL output clock frequency in Hz
24628c6529dbSLiam Girdwood  *
24638c6529dbSLiam Girdwood  * Configures and enables PLL to generate output clock based on input clock.
24648c6529dbSLiam Girdwood  */
246585488037SMark Brown int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
246685488037SMark Brown 	unsigned int freq_in, unsigned int freq_out)
24678c6529dbSLiam Girdwood {
246846471925SKuninori Morimoto 	if (dai->driver->ops->set_pll)
2469f0fba2adSLiam Girdwood 		return dai->driver->ops->set_pll(dai, pll_id, source,
247085488037SMark Brown 					 freq_in, freq_out);
2471ef641e5dSKuninori Morimoto 
2472ef641e5dSKuninori Morimoto 	return snd_soc_component_set_pll(dai->component, pll_id, source,
2473ec4ee52aSMark Brown 					 freq_in, freq_out);
24748c6529dbSLiam Girdwood }
24758c6529dbSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
24768c6529dbSLiam Girdwood 
2477ec4ee52aSMark Brown /*
2478ef641e5dSKuninori Morimoto  * snd_soc_component_set_pll - configure component PLL.
2479ef641e5dSKuninori Morimoto  * @component: COMPONENT
2480ef641e5dSKuninori Morimoto  * @pll_id: DAI specific PLL ID
2481ef641e5dSKuninori Morimoto  * @source: DAI specific source for the PLL
2482ef641e5dSKuninori Morimoto  * @freq_in: PLL input clock frequency in Hz
2483ef641e5dSKuninori Morimoto  * @freq_out: requested PLL output clock frequency in Hz
2484ef641e5dSKuninori Morimoto  *
2485ef641e5dSKuninori Morimoto  * Configures and enables PLL to generate output clock based on input clock.
2486ef641e5dSKuninori Morimoto  */
2487ef641e5dSKuninori Morimoto int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id,
2488ef641e5dSKuninori Morimoto 			      int source, unsigned int freq_in,
2489ef641e5dSKuninori Morimoto 			      unsigned int freq_out)
2490ef641e5dSKuninori Morimoto {
2491ef641e5dSKuninori Morimoto 	if (component->driver->set_pll)
2492ef641e5dSKuninori Morimoto 		return component->driver->set_pll(component, pll_id, source,
2493ef641e5dSKuninori Morimoto 					      freq_in, freq_out);
2494ef641e5dSKuninori Morimoto 
2495ef641e5dSKuninori Morimoto 	return -EINVAL;
2496ef641e5dSKuninori Morimoto }
2497ef641e5dSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_component_set_pll);
2498ef641e5dSKuninori Morimoto 
24998c6529dbSLiam Girdwood /**
2500e54cf76bSLiam Girdwood  * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio.
2501e54cf76bSLiam Girdwood  * @dai: DAI
2502231b86b1SMasanari Iida  * @ratio: Ratio of BCLK to Sample rate.
2503e54cf76bSLiam Girdwood  *
2504e54cf76bSLiam Girdwood  * Configures the DAI for a preset BCLK to sample rate ratio.
2505e54cf76bSLiam Girdwood  */
2506e54cf76bSLiam Girdwood int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
2507e54cf76bSLiam Girdwood {
250846471925SKuninori Morimoto 	if (dai->driver->ops->set_bclk_ratio)
2509e54cf76bSLiam Girdwood 		return dai->driver->ops->set_bclk_ratio(dai, ratio);
2510e54cf76bSLiam Girdwood 	else
2511e54cf76bSLiam Girdwood 		return -EINVAL;
2512e54cf76bSLiam Girdwood }
2513e54cf76bSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
2514e54cf76bSLiam Girdwood 
2515e54cf76bSLiam Girdwood /**
25168c6529dbSLiam Girdwood  * snd_soc_dai_set_fmt - configure DAI hardware audio format.
25178c6529dbSLiam Girdwood  * @dai: DAI
2518bb19ba2aSRandy Dunlap  * @fmt: SND_SOC_DAIFMT_* format value.
25198c6529dbSLiam Girdwood  *
25208c6529dbSLiam Girdwood  * Configures the DAI hardware format and clocking.
25218c6529dbSLiam Girdwood  */
25228c6529dbSLiam Girdwood int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
25238c6529dbSLiam Girdwood {
25245e4ba569SShawn Guo 	if (dai->driver == NULL)
25258c6529dbSLiam Girdwood 		return -EINVAL;
25265e4ba569SShawn Guo 	if (dai->driver->ops->set_fmt == NULL)
25275e4ba569SShawn Guo 		return -ENOTSUPP;
25285e4ba569SShawn Guo 	return dai->driver->ops->set_fmt(dai, fmt);
25298c6529dbSLiam Girdwood }
25308c6529dbSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
25318c6529dbSLiam Girdwood 
25328c6529dbSLiam Girdwood /**
2533e5c21514SXiubo Li  * snd_soc_xlate_tdm_slot - generate tx/rx slot mask.
253489c67857SXiubo Li  * @slots: Number of slots in use.
253589c67857SXiubo Li  * @tx_mask: bitmask representing active TX slots.
253689c67857SXiubo Li  * @rx_mask: bitmask representing active RX slots.
253789c67857SXiubo Li  *
253889c67857SXiubo Li  * Generates the TDM tx and rx slot default masks for DAI.
253989c67857SXiubo Li  */
2540e5c21514SXiubo Li static int snd_soc_xlate_tdm_slot_mask(unsigned int slots,
254189c67857SXiubo Li 					  unsigned int *tx_mask,
254289c67857SXiubo Li 					  unsigned int *rx_mask)
254389c67857SXiubo Li {
254489c67857SXiubo Li 	if (*tx_mask || *rx_mask)
254589c67857SXiubo Li 		return 0;
254689c67857SXiubo Li 
254789c67857SXiubo Li 	if (!slots)
254889c67857SXiubo Li 		return -EINVAL;
254989c67857SXiubo Li 
255089c67857SXiubo Li 	*tx_mask = (1 << slots) - 1;
255189c67857SXiubo Li 	*rx_mask = (1 << slots) - 1;
255289c67857SXiubo Li 
255389c67857SXiubo Li 	return 0;
255489c67857SXiubo Li }
255589c67857SXiubo Li 
255689c67857SXiubo Li /**
2557e46c9366SLars-Peter Clausen  * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation
2558e46c9366SLars-Peter Clausen  * @dai: The DAI to configure
2559a5479e38SDaniel Ribeiro  * @tx_mask: bitmask representing active TX slots.
2560a5479e38SDaniel Ribeiro  * @rx_mask: bitmask representing active RX slots.
25618c6529dbSLiam Girdwood  * @slots: Number of slots in use.
2562a5479e38SDaniel Ribeiro  * @slot_width: Width in bits for each slot.
25638c6529dbSLiam Girdwood  *
2564e46c9366SLars-Peter Clausen  * This function configures the specified DAI for TDM operation. @slot contains
2565e46c9366SLars-Peter Clausen  * the total number of slots of the TDM stream and @slot_with the width of each
2566e46c9366SLars-Peter Clausen  * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the
2567e46c9366SLars-Peter Clausen  * active slots of the TDM stream for the specified DAI, i.e. which slots the
2568e46c9366SLars-Peter Clausen  * DAI should write to or read from. If a bit is set the corresponding slot is
2569e46c9366SLars-Peter Clausen  * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to
2570e46c9366SLars-Peter Clausen  * the first slot, bit 1 to the second slot and so on. The first active slot
2571e46c9366SLars-Peter Clausen  * maps to the first channel of the DAI, the second active slot to the second
2572e46c9366SLars-Peter Clausen  * channel and so on.
2573e46c9366SLars-Peter Clausen  *
2574e46c9366SLars-Peter Clausen  * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask,
2575e46c9366SLars-Peter Clausen  * @rx_mask and @slot_width will be ignored.
2576e46c9366SLars-Peter Clausen  *
2577e46c9366SLars-Peter Clausen  * Returns 0 on success, a negative error code otherwise.
25788c6529dbSLiam Girdwood  */
25798c6529dbSLiam Girdwood int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
2580a5479e38SDaniel Ribeiro 	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
25818c6529dbSLiam Girdwood {
258246471925SKuninori Morimoto 	if (dai->driver->ops->xlate_tdm_slot_mask)
2583e5c21514SXiubo Li 		dai->driver->ops->xlate_tdm_slot_mask(slots,
258489c67857SXiubo Li 						&tx_mask, &rx_mask);
258589c67857SXiubo Li 	else
2586e5c21514SXiubo Li 		snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
258789c67857SXiubo Li 
258888bd870fSBenoit Cousson 	dai->tx_mask = tx_mask;
258988bd870fSBenoit Cousson 	dai->rx_mask = rx_mask;
259088bd870fSBenoit Cousson 
259146471925SKuninori Morimoto 	if (dai->driver->ops->set_tdm_slot)
2592f0fba2adSLiam Girdwood 		return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
2593a5479e38SDaniel Ribeiro 				slots, slot_width);
25948c6529dbSLiam Girdwood 	else
2595b2cbb6e1SXiubo Li 		return -ENOTSUPP;
25968c6529dbSLiam Girdwood }
25978c6529dbSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
25988c6529dbSLiam Girdwood 
25998c6529dbSLiam Girdwood /**
2600472df3cbSBarry Song  * snd_soc_dai_set_channel_map - configure DAI audio channel map
2601472df3cbSBarry Song  * @dai: DAI
2602472df3cbSBarry Song  * @tx_num: how many TX channels
2603472df3cbSBarry Song  * @tx_slot: pointer to an array which imply the TX slot number channel
2604472df3cbSBarry Song  *           0~num-1 uses
2605472df3cbSBarry Song  * @rx_num: how many RX channels
2606472df3cbSBarry Song  * @rx_slot: pointer to an array which imply the RX slot number channel
2607472df3cbSBarry Song  *           0~num-1 uses
2608472df3cbSBarry Song  *
2609472df3cbSBarry Song  * configure the relationship between channel number and TDM slot number.
2610472df3cbSBarry Song  */
2611472df3cbSBarry Song int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
2612472df3cbSBarry Song 	unsigned int tx_num, unsigned int *tx_slot,
2613472df3cbSBarry Song 	unsigned int rx_num, unsigned int *rx_slot)
2614472df3cbSBarry Song {
261546471925SKuninori Morimoto 	if (dai->driver->ops->set_channel_map)
2616f0fba2adSLiam Girdwood 		return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
2617472df3cbSBarry Song 			rx_num, rx_slot);
2618472df3cbSBarry Song 	else
2619472df3cbSBarry Song 		return -EINVAL;
2620472df3cbSBarry Song }
2621472df3cbSBarry Song EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
2622472df3cbSBarry Song 
2623472df3cbSBarry Song /**
2624467b061fSSrinivas Kandagatla  * snd_soc_dai_get_channel_map - Get DAI audio channel map
2625467b061fSSrinivas Kandagatla  * @dai: DAI
2626467b061fSSrinivas Kandagatla  * @tx_num: how many TX channels
2627467b061fSSrinivas Kandagatla  * @tx_slot: pointer to an array which imply the TX slot number channel
2628467b061fSSrinivas Kandagatla  *           0~num-1 uses
2629467b061fSSrinivas Kandagatla  * @rx_num: how many RX channels
2630467b061fSSrinivas Kandagatla  * @rx_slot: pointer to an array which imply the RX slot number channel
2631467b061fSSrinivas Kandagatla  *           0~num-1 uses
2632467b061fSSrinivas Kandagatla  */
2633467b061fSSrinivas Kandagatla int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
2634467b061fSSrinivas Kandagatla 	unsigned int *tx_num, unsigned int *tx_slot,
2635467b061fSSrinivas Kandagatla 	unsigned int *rx_num, unsigned int *rx_slot)
2636467b061fSSrinivas Kandagatla {
2637467b061fSSrinivas Kandagatla 	if (dai->driver->ops->get_channel_map)
2638467b061fSSrinivas Kandagatla 		return dai->driver->ops->get_channel_map(dai, tx_num, tx_slot,
2639467b061fSSrinivas Kandagatla 			rx_num, rx_slot);
2640467b061fSSrinivas Kandagatla 	else
2641467b061fSSrinivas Kandagatla 		return -ENOTSUPP;
2642467b061fSSrinivas Kandagatla }
2643467b061fSSrinivas Kandagatla EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map);
2644467b061fSSrinivas Kandagatla 
2645467b061fSSrinivas Kandagatla /**
26468c6529dbSLiam Girdwood  * snd_soc_dai_set_tristate - configure DAI system or master clock.
26478c6529dbSLiam Girdwood  * @dai: DAI
26488c6529dbSLiam Girdwood  * @tristate: tristate enable
26498c6529dbSLiam Girdwood  *
26508c6529dbSLiam Girdwood  * Tristates the DAI so that others can use it.
26518c6529dbSLiam Girdwood  */
26528c6529dbSLiam Girdwood int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
26538c6529dbSLiam Girdwood {
265446471925SKuninori Morimoto 	if (dai->driver->ops->set_tristate)
2655f0fba2adSLiam Girdwood 		return dai->driver->ops->set_tristate(dai, tristate);
26568c6529dbSLiam Girdwood 	else
26578c6529dbSLiam Girdwood 		return -EINVAL;
26588c6529dbSLiam Girdwood }
26598c6529dbSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
26608c6529dbSLiam Girdwood 
26618c6529dbSLiam Girdwood /**
26628c6529dbSLiam Girdwood  * snd_soc_dai_digital_mute - configure DAI system or master clock.
26638c6529dbSLiam Girdwood  * @dai: DAI
26648c6529dbSLiam Girdwood  * @mute: mute enable
2665da18396fSMark Brown  * @direction: stream to mute
26668c6529dbSLiam Girdwood  *
26678c6529dbSLiam Girdwood  * Mutes the DAI DAC.
26688c6529dbSLiam Girdwood  */
2669da18396fSMark Brown int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
2670da18396fSMark Brown 			     int direction)
26718c6529dbSLiam Girdwood {
2672da18396fSMark Brown 	if (!dai->driver)
2673da18396fSMark Brown 		return -ENOTSUPP;
2674da18396fSMark Brown 
2675da18396fSMark Brown 	if (dai->driver->ops->mute_stream)
2676da18396fSMark Brown 		return dai->driver->ops->mute_stream(dai, mute, direction);
2677da18396fSMark Brown 	else if (direction == SNDRV_PCM_STREAM_PLAYBACK &&
2678da18396fSMark Brown 		 dai->driver->ops->digital_mute)
2679f0fba2adSLiam Girdwood 		return dai->driver->ops->digital_mute(dai, mute);
26808c6529dbSLiam Girdwood 	else
268104570c62SMark Brown 		return -ENOTSUPP;
26828c6529dbSLiam Girdwood }
26838c6529dbSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
26848c6529dbSLiam Girdwood 
2685c5af3a2eSMark Brown /**
2686c5af3a2eSMark Brown  * snd_soc_register_card - Register a card with the ASoC core
2687c5af3a2eSMark Brown  *
2688ac11a2b3SMark Brown  * @card: Card to register
2689c5af3a2eSMark Brown  *
2690c5af3a2eSMark Brown  */
269170a7ca34SVinod Koul int snd_soc_register_card(struct snd_soc_card *card)
2692c5af3a2eSMark Brown {
2693923c5e61SMengdong Lin 	int i, ret;
26941a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
2695f0fba2adSLiam Girdwood 
2696c5af3a2eSMark Brown 	if (!card->name || !card->dev)
2697c5af3a2eSMark Brown 		return -EINVAL;
2698c5af3a2eSMark Brown 
26995a504963SStephen Warren 	for (i = 0; i < card->num_links; i++) {
27005a504963SStephen Warren 		struct snd_soc_dai_link *link = &card->dai_link[i];
27015a504963SStephen Warren 
2702923c5e61SMengdong Lin 		ret = soc_init_dai_link(card, link);
270388bd870fSBenoit Cousson 		if (ret) {
2704923c5e61SMengdong Lin 			dev_err(card->dev, "ASoC: failed to init link %s\n",
2705923c5e61SMengdong Lin 				link->name);
270688bd870fSBenoit Cousson 			return ret;
270788bd870fSBenoit Cousson 		}
27085a504963SStephen Warren 	}
27095a504963SStephen Warren 
2710ed77cc12SMark Brown 	dev_set_drvdata(card->dev, card);
2711ed77cc12SMark Brown 
2712111c6419SStephen Warren 	snd_soc_initialize_card_lists(card);
2713111c6419SStephen Warren 
2714f8f80361SMengdong Lin 	INIT_LIST_HEAD(&card->dai_link_list);
2715f8f80361SMengdong Lin 	card->num_dai_links = 0;
2716f0fba2adSLiam Girdwood 
27171a497983SMengdong Lin 	INIT_LIST_HEAD(&card->rtd_list);
27189115171aSMark Brown 	card->num_rtd = 0;
2719db2a4165SFrank Mandarino 
2720db432b41SMark Brown 	INIT_LIST_HEAD(&card->dapm_dirty);
27218a978234SLiam Girdwood 	INIT_LIST_HEAD(&card->dobj_list);
2722db2a4165SFrank Mandarino 	card->instantiated = 0;
2723db2a4165SFrank Mandarino 	mutex_init(&card->mutex);
2724a73fb2dfSLiam Girdwood 	mutex_init(&card->dapm_mutex);
2725db2a4165SFrank Mandarino 
2726b19e6e7bSMark Brown 	ret = snd_soc_instantiate_card(card);
2727b19e6e7bSMark Brown 	if (ret != 0)
27284e2576bdSKuninori Morimoto 		return ret;
2729db2a4165SFrank Mandarino 
2730988e8cc4SNicolin Chen 	/* deactivate pins to sleep state */
27311a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list)  {
273288bd870fSBenoit Cousson 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
27330b7990e3SKuninori Morimoto 		struct snd_soc_dai *codec_dai;
273488bd870fSBenoit Cousson 		int j;
273588bd870fSBenoit Cousson 
27360b7990e3SKuninori Morimoto 		for_each_rtd_codec_dai(rtd, j, codec_dai) {
2737988e8cc4SNicolin Chen 			if (!codec_dai->active)
2738988e8cc4SNicolin Chen 				pinctrl_pm_select_sleep_state(codec_dai->dev);
273988bd870fSBenoit Cousson 		}
274088bd870fSBenoit Cousson 
2741988e8cc4SNicolin Chen 		if (!cpu_dai->active)
2742988e8cc4SNicolin Chen 			pinctrl_pm_select_sleep_state(cpu_dai->dev);
2743988e8cc4SNicolin Chen 	}
2744988e8cc4SNicolin Chen 
2745b19e6e7bSMark Brown 	return ret;
2746db2a4165SFrank Mandarino }
274770a7ca34SVinod Koul EXPORT_SYMBOL_GPL(snd_soc_register_card);
2748db2a4165SFrank Mandarino 
2749db2a4165SFrank Mandarino /**
2750db2a4165SFrank Mandarino  * snd_soc_unregister_card - Unregister a card with the ASoC core
2751db2a4165SFrank Mandarino  *
2752db2a4165SFrank Mandarino  * @card: Card to unregister
2753db2a4165SFrank Mandarino  *
2754db2a4165SFrank Mandarino  */
275570a7ca34SVinod Koul int snd_soc_unregister_card(struct snd_soc_card *card)
2756db2a4165SFrank Mandarino {
275701e0df66SLars-Peter Clausen 	if (card->instantiated) {
275801e0df66SLars-Peter Clausen 		card->instantiated = false;
27591c325f77SLars-Peter Clausen 		snd_soc_dapm_shutdown(card);
2760b0e26485SVinod Koul 		soc_cleanup_card_resources(card);
2761f110bfc7SLiam Girdwood 		dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name);
27628f6f9b29SKuninori Morimoto 	}
2763db2a4165SFrank Mandarino 
2764db2a4165SFrank Mandarino 	return 0;
2765db2a4165SFrank Mandarino }
276670a7ca34SVinod Koul EXPORT_SYMBOL_GPL(snd_soc_unregister_card);
2767db2a4165SFrank Mandarino 
2768db2a4165SFrank Mandarino /*
2769db2a4165SFrank Mandarino  * Simplify DAI link configuration by removing ".-1" from device names
2770db2a4165SFrank Mandarino  * and sanitizing names.
2771db2a4165SFrank Mandarino  */
27720b9a214aSDimitris Papastamos static char *fmt_single_name(struct device *dev, int *id)
2773db2a4165SFrank Mandarino {
2774db2a4165SFrank Mandarino 	char *found, name[NAME_SIZE];
2775db2a4165SFrank Mandarino 	int id1, id2;
2776db2a4165SFrank Mandarino 
2777db2a4165SFrank Mandarino 	if (dev_name(dev) == NULL)
2778db2a4165SFrank Mandarino 		return NULL;
2779db2a4165SFrank Mandarino 
278058818a77SDimitris Papastamos 	strlcpy(name, dev_name(dev), NAME_SIZE);
2781db2a4165SFrank Mandarino 
2782db2a4165SFrank Mandarino 	/* are we a "%s.%d" name (platform and SPI components) */
2783c5af3a2eSMark Brown 	found = strstr(name, dev->driver->name);
2784c5af3a2eSMark Brown 	if (found) {
2785c5af3a2eSMark Brown 		/* get ID */
2786c5af3a2eSMark Brown 		if (sscanf(&found[strlen(dev->driver->name)], ".%d", id) == 1) {
2787c5af3a2eSMark Brown 
2788c5af3a2eSMark Brown 			/* discard ID from name if ID == -1 */
2789c5af3a2eSMark Brown 			if (*id == -1)
2790c5af3a2eSMark Brown 				found[strlen(dev->driver->name)] = '\0';
2791c5af3a2eSMark Brown 		}
2792c5af3a2eSMark Brown 
2793c5af3a2eSMark Brown 	} else {
2794c5af3a2eSMark Brown 		/* I2C component devices are named "bus-addr"  */
2795c5af3a2eSMark Brown 		if (sscanf(name, "%x-%x", &id1, &id2) == 2) {
2796c5af3a2eSMark Brown 			char tmp[NAME_SIZE];
2797c5af3a2eSMark Brown 
2798c5af3a2eSMark Brown 			/* create unique ID number from I2C addr and bus */
2799c5af3a2eSMark Brown 			*id = ((id1 & 0xffff) << 16) + id2;
2800c5af3a2eSMark Brown 
2801c5af3a2eSMark Brown 			/* sanitize component name for DAI link creation */
2802c5af3a2eSMark Brown 			snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, name);
280358818a77SDimitris Papastamos 			strlcpy(name, tmp, NAME_SIZE);
2804c5af3a2eSMark Brown 		} else
2805c5af3a2eSMark Brown 			*id = 0;
2806c5af3a2eSMark Brown 	}
2807c5af3a2eSMark Brown 
2808c5af3a2eSMark Brown 	return kstrdup(name, GFP_KERNEL);
2809c5af3a2eSMark Brown }
2810c5af3a2eSMark Brown 
2811c5af3a2eSMark Brown /*
2812c5af3a2eSMark Brown  * Simplify DAI link naming for single devices with multiple DAIs by removing
2813c5af3a2eSMark Brown  * any ".-1" and using the DAI name (instead of device name).
2814c5af3a2eSMark Brown  */
2815c5af3a2eSMark Brown static inline char *fmt_multiple_name(struct device *dev,
2816c5af3a2eSMark Brown 		struct snd_soc_dai_driver *dai_drv)
2817c5af3a2eSMark Brown {
2818c5af3a2eSMark Brown 	if (dai_drv->name == NULL) {
281910e8aa9aSMichał Mirosław 		dev_err(dev,
282010e8aa9aSMichał Mirosław 			"ASoC: error - multiple DAI %s registered with no name\n",
282110e8aa9aSMichał Mirosław 			dev_name(dev));
2822c5af3a2eSMark Brown 		return NULL;
2823c5af3a2eSMark Brown 	}
2824c5af3a2eSMark Brown 
2825c5af3a2eSMark Brown 	return kstrdup(dai_drv->name, GFP_KERNEL);
2826c5af3a2eSMark Brown }
2827c5af3a2eSMark Brown 
2828c5af3a2eSMark Brown /**
282932c9ba54SLars-Peter Clausen  * snd_soc_unregister_dai - Unregister DAIs from the ASoC core
28309115171aSMark Brown  *
283132c9ba54SLars-Peter Clausen  * @component: The component for which the DAIs should be unregistered
28329115171aSMark Brown  */
283332c9ba54SLars-Peter Clausen static void snd_soc_unregister_dais(struct snd_soc_component *component)
28349115171aSMark Brown {
28355c1d5f09SLars-Peter Clausen 	struct snd_soc_dai *dai, *_dai;
28369115171aSMark Brown 
28375c1d5f09SLars-Peter Clausen 	list_for_each_entry_safe(dai, _dai, &component->dai_list, list) {
283832c9ba54SLars-Peter Clausen 		dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n",
283932c9ba54SLars-Peter Clausen 			dai->name);
28409115171aSMark Brown 		list_del(&dai->list);
2841f0fba2adSLiam Girdwood 		kfree(dai->name);
2842f0fba2adSLiam Girdwood 		kfree(dai);
28439115171aSMark Brown 	}
284432c9ba54SLars-Peter Clausen }
28459115171aSMark Brown 
28465e4fb372SMengdong Lin /* Create a DAI and add it to the component's DAI list */
28475e4fb372SMengdong Lin static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component,
28485e4fb372SMengdong Lin 	struct snd_soc_dai_driver *dai_drv,
28495e4fb372SMengdong Lin 	bool legacy_dai_naming)
28505e4fb372SMengdong Lin {
28515e4fb372SMengdong Lin 	struct device *dev = component->dev;
28525e4fb372SMengdong Lin 	struct snd_soc_dai *dai;
28535e4fb372SMengdong Lin 
28545e4fb372SMengdong Lin 	dev_dbg(dev, "ASoC: dynamically register DAI %s\n", dev_name(dev));
28555e4fb372SMengdong Lin 
28565e4fb372SMengdong Lin 	dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
28575e4fb372SMengdong Lin 	if (dai == NULL)
28585e4fb372SMengdong Lin 		return NULL;
28595e4fb372SMengdong Lin 
28605e4fb372SMengdong Lin 	/*
28615e4fb372SMengdong Lin 	 * Back in the old days when we still had component-less DAIs,
28625e4fb372SMengdong Lin 	 * instead of having a static name, component-less DAIs would
28635e4fb372SMengdong Lin 	 * inherit the name of the parent device so it is possible to
28645e4fb372SMengdong Lin 	 * register multiple instances of the DAI. We still need to keep
28655e4fb372SMengdong Lin 	 * the same naming style even though those DAIs are not
28665e4fb372SMengdong Lin 	 * component-less anymore.
28675e4fb372SMengdong Lin 	 */
28685e4fb372SMengdong Lin 	if (legacy_dai_naming &&
28695e4fb372SMengdong Lin 	   (dai_drv->id == 0 || dai_drv->name == NULL)) {
28705e4fb372SMengdong Lin 		dai->name = fmt_single_name(dev, &dai->id);
28715e4fb372SMengdong Lin 	} else {
28725e4fb372SMengdong Lin 		dai->name = fmt_multiple_name(dev, dai_drv);
28735e4fb372SMengdong Lin 		if (dai_drv->id)
28745e4fb372SMengdong Lin 			dai->id = dai_drv->id;
28755e4fb372SMengdong Lin 		else
28765e4fb372SMengdong Lin 			dai->id = component->num_dai;
28775e4fb372SMengdong Lin 	}
28785e4fb372SMengdong Lin 	if (dai->name == NULL) {
28795e4fb372SMengdong Lin 		kfree(dai);
28805e4fb372SMengdong Lin 		return NULL;
28815e4fb372SMengdong Lin 	}
28825e4fb372SMengdong Lin 
28835e4fb372SMengdong Lin 	dai->component = component;
28845e4fb372SMengdong Lin 	dai->dev = dev;
28855e4fb372SMengdong Lin 	dai->driver = dai_drv;
28865e4fb372SMengdong Lin 	if (!dai->driver->ops)
28875e4fb372SMengdong Lin 		dai->driver->ops = &null_dai_ops;
28885e4fb372SMengdong Lin 
288958bf4179SKuninori Morimoto 	list_add_tail(&dai->list, &component->dai_list);
28905e4fb372SMengdong Lin 	component->num_dai++;
28915e4fb372SMengdong Lin 
28925e4fb372SMengdong Lin 	dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
28935e4fb372SMengdong Lin 	return dai;
28945e4fb372SMengdong Lin }
28955e4fb372SMengdong Lin 
28969115171aSMark Brown /**
289732c9ba54SLars-Peter Clausen  * snd_soc_register_dais - Register a DAI with the ASoC core
28989115171aSMark Brown  *
28996106d129SLars-Peter Clausen  * @component: The component the DAIs are registered for
29006106d129SLars-Peter Clausen  * @dai_drv: DAI driver to use for the DAIs
2901ac11a2b3SMark Brown  * @count: Number of DAIs
29029115171aSMark Brown  */
290332c9ba54SLars-Peter Clausen static int snd_soc_register_dais(struct snd_soc_component *component,
29040e7b25c6SKuninori Morimoto 				 struct snd_soc_dai_driver *dai_drv, size_t count)
29059115171aSMark Brown {
29066106d129SLars-Peter Clausen 	struct device *dev = component->dev;
2907f0fba2adSLiam Girdwood 	struct snd_soc_dai *dai;
290832c9ba54SLars-Peter Clausen 	unsigned int i;
290932c9ba54SLars-Peter Clausen 	int ret;
2910f0fba2adSLiam Girdwood 
29115b5e0928SAlexey Dobriyan 	dev_dbg(dev, "ASoC: dai register %s #%zu\n", dev_name(dev), count);
29129115171aSMark Brown 
29139115171aSMark Brown 	for (i = 0; i < count; i++) {
2914f0fba2adSLiam Girdwood 
29155e4fb372SMengdong Lin 		dai = soc_add_dai(component, dai_drv + i,
29160e7b25c6SKuninori Morimoto 				  count == 1 && !component->driver->non_legacy_dai_naming);
2917c46e0079SAxel Lin 		if (dai == NULL) {
2918c46e0079SAxel Lin 			ret = -ENOMEM;
2919c46e0079SAxel Lin 			goto err;
2920c46e0079SAxel Lin 		}
2921f0fba2adSLiam Girdwood 	}
2922f0fba2adSLiam Girdwood 
29239115171aSMark Brown 	return 0;
29249115171aSMark Brown 
29259115171aSMark Brown err:
292632c9ba54SLars-Peter Clausen 	snd_soc_unregister_dais(component);
29279115171aSMark Brown 
29289115171aSMark Brown 	return ret;
29299115171aSMark Brown }
29309115171aSMark Brown 
293168003e6cSMengdong Lin /**
293268003e6cSMengdong Lin  * snd_soc_register_dai - Register a DAI dynamically & create its widgets
293368003e6cSMengdong Lin  *
293468003e6cSMengdong Lin  * @component: The component the DAIs are registered for
293568003e6cSMengdong Lin  * @dai_drv: DAI driver to use for the DAI
293668003e6cSMengdong Lin  *
293768003e6cSMengdong Lin  * Topology can use this API to register DAIs when probing a component.
293868003e6cSMengdong Lin  * These DAIs's widgets will be freed in the card cleanup and the DAIs
293968003e6cSMengdong Lin  * will be freed in the component cleanup.
294068003e6cSMengdong Lin  */
294168003e6cSMengdong Lin int snd_soc_register_dai(struct snd_soc_component *component,
294268003e6cSMengdong Lin 	struct snd_soc_dai_driver *dai_drv)
294368003e6cSMengdong Lin {
294468003e6cSMengdong Lin 	struct snd_soc_dapm_context *dapm =
294568003e6cSMengdong Lin 		snd_soc_component_get_dapm(component);
294668003e6cSMengdong Lin 	struct snd_soc_dai *dai;
294768003e6cSMengdong Lin 	int ret;
294868003e6cSMengdong Lin 
294968003e6cSMengdong Lin 	if (dai_drv->dobj.type != SND_SOC_DOBJ_PCM) {
295068003e6cSMengdong Lin 		dev_err(component->dev, "Invalid dai type %d\n",
295168003e6cSMengdong Lin 			dai_drv->dobj.type);
295268003e6cSMengdong Lin 		return -EINVAL;
295368003e6cSMengdong Lin 	}
295468003e6cSMengdong Lin 
295568003e6cSMengdong Lin 	lockdep_assert_held(&client_mutex);
295668003e6cSMengdong Lin 	dai = soc_add_dai(component, dai_drv, false);
295768003e6cSMengdong Lin 	if (!dai)
295868003e6cSMengdong Lin 		return -ENOMEM;
295968003e6cSMengdong Lin 
296068003e6cSMengdong Lin 	/* Create the DAI widgets here. After adding DAIs, topology may
296168003e6cSMengdong Lin 	 * also add routes that need these widgets as source or sink.
296268003e6cSMengdong Lin 	 */
296368003e6cSMengdong Lin 	ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
296468003e6cSMengdong Lin 	if (ret != 0) {
296568003e6cSMengdong Lin 		dev_err(component->dev,
296668003e6cSMengdong Lin 			"Failed to create DAI widgets %d\n", ret);
296768003e6cSMengdong Lin 	}
296868003e6cSMengdong Lin 
296968003e6cSMengdong Lin 	return ret;
297068003e6cSMengdong Lin }
297168003e6cSMengdong Lin EXPORT_SYMBOL_GPL(snd_soc_register_dai);
297268003e6cSMengdong Lin 
297314e8bdebSLars-Peter Clausen static void snd_soc_component_seq_notifier(struct snd_soc_dapm_context *dapm,
297414e8bdebSLars-Peter Clausen 	enum snd_soc_dapm_type type, int subseq)
2975d191bd8dSKuninori Morimoto {
297614e8bdebSLars-Peter Clausen 	struct snd_soc_component *component = dapm->component;
2977d191bd8dSKuninori Morimoto 
297814e8bdebSLars-Peter Clausen 	component->driver->seq_notifier(component, type, subseq);
297914e8bdebSLars-Peter Clausen }
2980d191bd8dSKuninori Morimoto 
298114e8bdebSLars-Peter Clausen static int snd_soc_component_stream_event(struct snd_soc_dapm_context *dapm,
298214e8bdebSLars-Peter Clausen 	int event)
298314e8bdebSLars-Peter Clausen {
298414e8bdebSLars-Peter Clausen 	struct snd_soc_component *component = dapm->component;
298514e8bdebSLars-Peter Clausen 
298614e8bdebSLars-Peter Clausen 	return component->driver->stream_event(component, event);
298714e8bdebSLars-Peter Clausen }
298814e8bdebSLars-Peter Clausen 
29897ba236ceSKuninori Morimoto static int snd_soc_component_set_bias_level(struct snd_soc_dapm_context *dapm,
29907ba236ceSKuninori Morimoto 					enum snd_soc_bias_level level)
29917ba236ceSKuninori Morimoto {
29927ba236ceSKuninori Morimoto 	struct snd_soc_component *component = dapm->component;
29937ba236ceSKuninori Morimoto 
29947ba236ceSKuninori Morimoto 	return component->driver->set_bias_level(component, level);
29957ba236ceSKuninori Morimoto }
29967ba236ceSKuninori Morimoto 
2997bb13109dSLars-Peter Clausen static int snd_soc_component_initialize(struct snd_soc_component *component,
2998bb13109dSLars-Peter Clausen 	const struct snd_soc_component_driver *driver, struct device *dev)
2999d191bd8dSKuninori Morimoto {
3000ce0fc93aSLars-Peter Clausen 	struct snd_soc_dapm_context *dapm;
3001ce0fc93aSLars-Peter Clausen 
3002bb13109dSLars-Peter Clausen 	component->name = fmt_single_name(dev, &component->id);
3003bb13109dSLars-Peter Clausen 	if (!component->name) {
3004bb13109dSLars-Peter Clausen 		dev_err(dev, "ASoC: Failed to allocate name\n");
3005d191bd8dSKuninori Morimoto 		return -ENOMEM;
3006d191bd8dSKuninori Morimoto 	}
3007d191bd8dSKuninori Morimoto 
3008bb13109dSLars-Peter Clausen 	component->dev = dev;
3009bb13109dSLars-Peter Clausen 	component->driver = driver;
3010e2c330b9SLars-Peter Clausen 
301188c27465SKuninori Morimoto 	dapm = snd_soc_component_get_dapm(component);
3012ce0fc93aSLars-Peter Clausen 	dapm->dev = dev;
3013ce0fc93aSLars-Peter Clausen 	dapm->component = component;
3014ce0fc93aSLars-Peter Clausen 	dapm->bias_level = SND_SOC_BIAS_OFF;
30157ba236ceSKuninori Morimoto 	dapm->idle_bias_off = !driver->idle_bias_on;
30167ba236ceSKuninori Morimoto 	dapm->suspend_bias_off = driver->suspend_bias_off;
301714e8bdebSLars-Peter Clausen 	if (driver->seq_notifier)
301814e8bdebSLars-Peter Clausen 		dapm->seq_notifier = snd_soc_component_seq_notifier;
301914e8bdebSLars-Peter Clausen 	if (driver->stream_event)
302014e8bdebSLars-Peter Clausen 		dapm->stream_event = snd_soc_component_stream_event;
30217ba236ceSKuninori Morimoto 	if (driver->set_bias_level)
30227ba236ceSKuninori Morimoto 		dapm->set_bias_level = snd_soc_component_set_bias_level;
3023ce0fc93aSLars-Peter Clausen 
3024bb13109dSLars-Peter Clausen 	INIT_LIST_HEAD(&component->dai_list);
3025bb13109dSLars-Peter Clausen 	mutex_init(&component->io_mutex);
3026bb13109dSLars-Peter Clausen 
3027bb13109dSLars-Peter Clausen 	return 0;
3028d191bd8dSKuninori Morimoto }
3029d191bd8dSKuninori Morimoto 
303020feb881SLars-Peter Clausen static void snd_soc_component_setup_regmap(struct snd_soc_component *component)
3031886f5692SLars-Peter Clausen {
3032886f5692SLars-Peter Clausen 	int val_bytes = regmap_get_val_bytes(component->regmap);
303320feb881SLars-Peter Clausen 
3034886f5692SLars-Peter Clausen 	/* Errors are legitimate for non-integer byte multiples */
3035886f5692SLars-Peter Clausen 	if (val_bytes > 0)
3036886f5692SLars-Peter Clausen 		component->val_bytes = val_bytes;
3037886f5692SLars-Peter Clausen }
303820feb881SLars-Peter Clausen 
3039e874bf5fSLars-Peter Clausen #ifdef CONFIG_REGMAP
3040e874bf5fSLars-Peter Clausen 
304120feb881SLars-Peter Clausen /**
304220feb881SLars-Peter Clausen  * snd_soc_component_init_regmap() - Initialize regmap instance for the component
304320feb881SLars-Peter Clausen  * @component: The component for which to initialize the regmap instance
304420feb881SLars-Peter Clausen  * @regmap: The regmap instance that should be used by the component
304520feb881SLars-Peter Clausen  *
304620feb881SLars-Peter Clausen  * This function allows deferred assignment of the regmap instance that is
304720feb881SLars-Peter Clausen  * associated with the component. Only use this if the regmap instance is not
304820feb881SLars-Peter Clausen  * yet ready when the component is registered. The function must also be called
304920feb881SLars-Peter Clausen  * before the first IO attempt of the component.
305020feb881SLars-Peter Clausen  */
305120feb881SLars-Peter Clausen void snd_soc_component_init_regmap(struct snd_soc_component *component,
305220feb881SLars-Peter Clausen 	struct regmap *regmap)
305320feb881SLars-Peter Clausen {
305420feb881SLars-Peter Clausen 	component->regmap = regmap;
305520feb881SLars-Peter Clausen 	snd_soc_component_setup_regmap(component);
3056886f5692SLars-Peter Clausen }
305720feb881SLars-Peter Clausen EXPORT_SYMBOL_GPL(snd_soc_component_init_regmap);
305820feb881SLars-Peter Clausen 
305920feb881SLars-Peter Clausen /**
306020feb881SLars-Peter Clausen  * snd_soc_component_exit_regmap() - De-initialize regmap instance for the component
306120feb881SLars-Peter Clausen  * @component: The component for which to de-initialize the regmap instance
306220feb881SLars-Peter Clausen  *
306320feb881SLars-Peter Clausen  * Calls regmap_exit() on the regmap instance associated to the component and
306420feb881SLars-Peter Clausen  * removes the regmap instance from the component.
306520feb881SLars-Peter Clausen  *
306620feb881SLars-Peter Clausen  * This function should only be used if snd_soc_component_init_regmap() was used
306720feb881SLars-Peter Clausen  * to initialize the regmap instance.
306820feb881SLars-Peter Clausen  */
306920feb881SLars-Peter Clausen void snd_soc_component_exit_regmap(struct snd_soc_component *component)
307020feb881SLars-Peter Clausen {
307120feb881SLars-Peter Clausen 	regmap_exit(component->regmap);
307220feb881SLars-Peter Clausen 	component->regmap = NULL;
307320feb881SLars-Peter Clausen }
307420feb881SLars-Peter Clausen EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap);
3075886f5692SLars-Peter Clausen 
3076e874bf5fSLars-Peter Clausen #endif
3077d191bd8dSKuninori Morimoto 
3078359c71eeSKuninori Morimoto static void snd_soc_component_add(struct snd_soc_component *component)
3079bb13109dSLars-Peter Clausen {
3080359c71eeSKuninori Morimoto 	mutex_lock(&client_mutex);
3081359c71eeSKuninori Morimoto 
3082999f7f5aSKuninori Morimoto 	if (!component->driver->write && !component->driver->read) {
308320feb881SLars-Peter Clausen 		if (!component->regmap)
308420feb881SLars-Peter Clausen 			component->regmap = dev_get_regmap(component->dev, NULL);
308520feb881SLars-Peter Clausen 		if (component->regmap)
308620feb881SLars-Peter Clausen 			snd_soc_component_setup_regmap(component);
308720feb881SLars-Peter Clausen 	}
3088886f5692SLars-Peter Clausen 
3089bb13109dSLars-Peter Clausen 	list_add(&component->list, &component_list);
30908a978234SLiam Girdwood 	INIT_LIST_HEAD(&component->dobj_list);
3091d191bd8dSKuninori Morimoto 
3092d191bd8dSKuninori Morimoto 	mutex_unlock(&client_mutex);
3093bb13109dSLars-Peter Clausen }
3094d191bd8dSKuninori Morimoto 
3095bb13109dSLars-Peter Clausen static void snd_soc_component_cleanup(struct snd_soc_component *component)
3096bb13109dSLars-Peter Clausen {
3097bb13109dSLars-Peter Clausen 	snd_soc_unregister_dais(component);
3098bb13109dSLars-Peter Clausen 	kfree(component->name);
3099bb13109dSLars-Peter Clausen }
3100d191bd8dSKuninori Morimoto 
3101bb13109dSLars-Peter Clausen static void snd_soc_component_del_unlocked(struct snd_soc_component *component)
3102bb13109dSLars-Peter Clausen {
3103c12c1aadSKuninori Morimoto 	struct snd_soc_card *card = component->card;
3104c12c1aadSKuninori Morimoto 
3105c12c1aadSKuninori Morimoto 	if (card)
3106c12c1aadSKuninori Morimoto 		snd_soc_unregister_card(card);
3107c12c1aadSKuninori Morimoto 
3108bb13109dSLars-Peter Clausen 	list_del(&component->list);
3109bb13109dSLars-Peter Clausen }
3110d191bd8dSKuninori Morimoto 
3111273d778eSKuninori Morimoto #define ENDIANNESS_MAP(name) \
3112273d778eSKuninori Morimoto 	(SNDRV_PCM_FMTBIT_##name##LE | SNDRV_PCM_FMTBIT_##name##BE)
3113273d778eSKuninori Morimoto static u64 endianness_format_map[] = {
3114273d778eSKuninori Morimoto 	ENDIANNESS_MAP(S16_),
3115273d778eSKuninori Morimoto 	ENDIANNESS_MAP(U16_),
3116273d778eSKuninori Morimoto 	ENDIANNESS_MAP(S24_),
3117273d778eSKuninori Morimoto 	ENDIANNESS_MAP(U24_),
3118273d778eSKuninori Morimoto 	ENDIANNESS_MAP(S32_),
3119273d778eSKuninori Morimoto 	ENDIANNESS_MAP(U32_),
3120273d778eSKuninori Morimoto 	ENDIANNESS_MAP(S24_3),
3121273d778eSKuninori Morimoto 	ENDIANNESS_MAP(U24_3),
3122273d778eSKuninori Morimoto 	ENDIANNESS_MAP(S20_3),
3123273d778eSKuninori Morimoto 	ENDIANNESS_MAP(U20_3),
3124273d778eSKuninori Morimoto 	ENDIANNESS_MAP(S18_3),
3125273d778eSKuninori Morimoto 	ENDIANNESS_MAP(U18_3),
3126273d778eSKuninori Morimoto 	ENDIANNESS_MAP(FLOAT_),
3127273d778eSKuninori Morimoto 	ENDIANNESS_MAP(FLOAT64_),
3128273d778eSKuninori Morimoto 	ENDIANNESS_MAP(IEC958_SUBFRAME_),
3129273d778eSKuninori Morimoto };
3130273d778eSKuninori Morimoto 
3131273d778eSKuninori Morimoto /*
3132273d778eSKuninori Morimoto  * Fix up the DAI formats for endianness: codecs don't actually see
3133273d778eSKuninori Morimoto  * the endianness of the data but we're using the CPU format
3134273d778eSKuninori Morimoto  * definitions which do need to include endianness so we ensure that
3135273d778eSKuninori Morimoto  * codec DAIs always have both big and little endian variants set.
3136273d778eSKuninori Morimoto  */
3137273d778eSKuninori Morimoto static void convert_endianness_formats(struct snd_soc_pcm_stream *stream)
3138273d778eSKuninori Morimoto {
3139273d778eSKuninori Morimoto 	int i;
3140273d778eSKuninori Morimoto 
3141273d778eSKuninori Morimoto 	for (i = 0; i < ARRAY_SIZE(endianness_format_map); i++)
3142273d778eSKuninori Morimoto 		if (stream->formats & endianness_format_map[i])
3143273d778eSKuninori Morimoto 			stream->formats |= endianness_format_map[i];
3144273d778eSKuninori Morimoto }
3145273d778eSKuninori Morimoto 
3146e0dac41bSKuninori Morimoto int snd_soc_add_component(struct device *dev,
3147e0dac41bSKuninori Morimoto 			struct snd_soc_component *component,
3148cf9e829eSKuninori Morimoto 			const struct snd_soc_component_driver *component_driver,
3149d191bd8dSKuninori Morimoto 			struct snd_soc_dai_driver *dai_drv,
3150d191bd8dSKuninori Morimoto 			int num_dai)
3151d191bd8dSKuninori Morimoto {
3152bb13109dSLars-Peter Clausen 	int ret;
3153273d778eSKuninori Morimoto 	int i;
3154d191bd8dSKuninori Morimoto 
3155cf9e829eSKuninori Morimoto 	ret = snd_soc_component_initialize(component, component_driver, dev);
3156bb13109dSLars-Peter Clausen 	if (ret)
3157bb13109dSLars-Peter Clausen 		goto err_free;
3158bb13109dSLars-Peter Clausen 
3159273d778eSKuninori Morimoto 	if (component_driver->endianness) {
3160273d778eSKuninori Morimoto 		for (i = 0; i < num_dai; i++) {
3161273d778eSKuninori Morimoto 			convert_endianness_formats(&dai_drv[i].playback);
3162273d778eSKuninori Morimoto 			convert_endianness_formats(&dai_drv[i].capture);
3163273d778eSKuninori Morimoto 		}
3164273d778eSKuninori Morimoto 	}
3165273d778eSKuninori Morimoto 
31660e7b25c6SKuninori Morimoto 	ret = snd_soc_register_dais(component, dai_drv, num_dai);
3167bb13109dSLars-Peter Clausen 	if (ret < 0) {
3168f42cf8d6SMasanari Iida 		dev_err(dev, "ASoC: Failed to register DAIs: %d\n", ret);
3169bb13109dSLars-Peter Clausen 		goto err_cleanup;
3170bb13109dSLars-Peter Clausen 	}
3171bb13109dSLars-Peter Clausen 
3172cf9e829eSKuninori Morimoto 	snd_soc_component_add(component);
3173bb13109dSLars-Peter Clausen 
3174bb13109dSLars-Peter Clausen 	return 0;
3175bb13109dSLars-Peter Clausen 
3176bb13109dSLars-Peter Clausen err_cleanup:
3177cf9e829eSKuninori Morimoto 	snd_soc_component_cleanup(component);
3178bb13109dSLars-Peter Clausen err_free:
3179bb13109dSLars-Peter Clausen 	return ret;
3180d191bd8dSKuninori Morimoto }
3181e0dac41bSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_add_component);
3182e0dac41bSKuninori Morimoto 
3183e0dac41bSKuninori Morimoto int snd_soc_register_component(struct device *dev,
3184e0dac41bSKuninori Morimoto 			const struct snd_soc_component_driver *component_driver,
3185e0dac41bSKuninori Morimoto 			struct snd_soc_dai_driver *dai_drv,
3186e0dac41bSKuninori Morimoto 			int num_dai)
3187e0dac41bSKuninori Morimoto {
3188e0dac41bSKuninori Morimoto 	struct snd_soc_component *component;
3189e0dac41bSKuninori Morimoto 
31907ecbd6a9SKuninori Morimoto 	component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL);
319108e61d03SKuninori Morimoto 	if (!component)
3192e0dac41bSKuninori Morimoto 		return -ENOMEM;
3193e0dac41bSKuninori Morimoto 
3194e0dac41bSKuninori Morimoto 	return snd_soc_add_component(dev, component, component_driver,
3195e0dac41bSKuninori Morimoto 				     dai_drv, num_dai);
3196e0dac41bSKuninori Morimoto }
3197d191bd8dSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_register_component);
3198d191bd8dSKuninori Morimoto 
3199d191bd8dSKuninori Morimoto /**
32002eccea8cSKuninori Morimoto  * snd_soc_unregister_component - Unregister all related component
32012eccea8cSKuninori Morimoto  * from the ASoC core
3202d191bd8dSKuninori Morimoto  *
3203628536eaSJonathan Corbet  * @dev: The device to unregister
3204d191bd8dSKuninori Morimoto  */
32052eccea8cSKuninori Morimoto static int __snd_soc_unregister_component(struct device *dev)
3206d191bd8dSKuninori Morimoto {
3207cf9e829eSKuninori Morimoto 	struct snd_soc_component *component;
320821a03528SKuninori Morimoto 	int found = 0;
3209d191bd8dSKuninori Morimoto 
321034e81ab4SLars-Peter Clausen 	mutex_lock(&client_mutex);
3211cf9e829eSKuninori Morimoto 	list_for_each_entry(component, &component_list, list) {
3212999f7f5aSKuninori Morimoto 		if (dev != component->dev)
321321a03528SKuninori Morimoto 			continue;
3214d191bd8dSKuninori Morimoto 
3215cf9e829eSKuninori Morimoto 		snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL);
3216cf9e829eSKuninori Morimoto 		snd_soc_component_del_unlocked(component);
321721a03528SKuninori Morimoto 		found = 1;
321821a03528SKuninori Morimoto 		break;
3219d191bd8dSKuninori Morimoto 	}
3220d191bd8dSKuninori Morimoto 	mutex_unlock(&client_mutex);
3221d191bd8dSKuninori Morimoto 
322221a03528SKuninori Morimoto 	if (found) {
3223cf9e829eSKuninori Morimoto 		snd_soc_component_cleanup(component);
3224d191bd8dSKuninori Morimoto 	}
32252eccea8cSKuninori Morimoto 
32262eccea8cSKuninori Morimoto 	return found;
32272eccea8cSKuninori Morimoto }
32282eccea8cSKuninori Morimoto 
32292eccea8cSKuninori Morimoto void snd_soc_unregister_component(struct device *dev)
32302eccea8cSKuninori Morimoto {
32312eccea8cSKuninori Morimoto 	while (__snd_soc_unregister_component(dev));
3232d191bd8dSKuninori Morimoto }
3233d191bd8dSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
3234d191bd8dSKuninori Morimoto 
32357dd5d0d9SKuninori Morimoto struct snd_soc_component *snd_soc_lookup_component(struct device *dev,
32367dd5d0d9SKuninori Morimoto 						   const char *driver_name)
32377dd5d0d9SKuninori Morimoto {
32387dd5d0d9SKuninori Morimoto 	struct snd_soc_component *component;
32397dd5d0d9SKuninori Morimoto 	struct snd_soc_component *ret;
32407dd5d0d9SKuninori Morimoto 
32417dd5d0d9SKuninori Morimoto 	ret = NULL;
32427dd5d0d9SKuninori Morimoto 	mutex_lock(&client_mutex);
32437dd5d0d9SKuninori Morimoto 	list_for_each_entry(component, &component_list, list) {
32447dd5d0d9SKuninori Morimoto 		if (dev != component->dev)
32457dd5d0d9SKuninori Morimoto 			continue;
32467dd5d0d9SKuninori Morimoto 
32477dd5d0d9SKuninori Morimoto 		if (driver_name &&
32487dd5d0d9SKuninori Morimoto 		    (driver_name != component->driver->name) &&
32497dd5d0d9SKuninori Morimoto 		    (strcmp(component->driver->name, driver_name) != 0))
32507dd5d0d9SKuninori Morimoto 			continue;
32517dd5d0d9SKuninori Morimoto 
32527dd5d0d9SKuninori Morimoto 		ret = component;
32537dd5d0d9SKuninori Morimoto 		break;
32547dd5d0d9SKuninori Morimoto 	}
32557dd5d0d9SKuninori Morimoto 	mutex_unlock(&client_mutex);
32567dd5d0d9SKuninori Morimoto 
32577dd5d0d9SKuninori Morimoto 	return ret;
32587dd5d0d9SKuninori Morimoto }
32597dd5d0d9SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_lookup_component);
32607dd5d0d9SKuninori Morimoto 
3261bec4fa05SStephen Warren /* Retrieve a card's name from device tree */
3262b07609ceSKuninori Morimoto int snd_soc_of_parse_card_name(struct snd_soc_card *card,
3263bec4fa05SStephen Warren 			       const char *propname)
3264bec4fa05SStephen Warren {
3265b07609ceSKuninori Morimoto 	struct device_node *np;
3266bec4fa05SStephen Warren 	int ret;
3267bec4fa05SStephen Warren 
32687e07e7c0STushar Behera 	if (!card->dev) {
32697e07e7c0STushar Behera 		pr_err("card->dev is not set before calling %s\n", __func__);
32707e07e7c0STushar Behera 		return -EINVAL;
32717e07e7c0STushar Behera 	}
32727e07e7c0STushar Behera 
32737e07e7c0STushar Behera 	np = card->dev->of_node;
32747e07e7c0STushar Behera 
3275bec4fa05SStephen Warren 	ret = of_property_read_string_index(np, propname, 0, &card->name);
3276bec4fa05SStephen Warren 	/*
3277bec4fa05SStephen Warren 	 * EINVAL means the property does not exist. This is fine providing
3278bec4fa05SStephen Warren 	 * card->name was previously set, which is checked later in
3279bec4fa05SStephen Warren 	 * snd_soc_register_card.
3280bec4fa05SStephen Warren 	 */
3281bec4fa05SStephen Warren 	if (ret < 0 && ret != -EINVAL) {
3282bec4fa05SStephen Warren 		dev_err(card->dev,
3283f110bfc7SLiam Girdwood 			"ASoC: Property '%s' could not be read: %d\n",
3284bec4fa05SStephen Warren 			propname, ret);
3285bec4fa05SStephen Warren 		return ret;
3286bec4fa05SStephen Warren 	}
3287bec4fa05SStephen Warren 
3288bec4fa05SStephen Warren 	return 0;
3289bec4fa05SStephen Warren }
3290b07609ceSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name);
3291bec4fa05SStephen Warren 
32929a6d4860SXiubo Li static const struct snd_soc_dapm_widget simple_widgets[] = {
32939a6d4860SXiubo Li 	SND_SOC_DAPM_MIC("Microphone", NULL),
32949a6d4860SXiubo Li 	SND_SOC_DAPM_LINE("Line", NULL),
32959a6d4860SXiubo Li 	SND_SOC_DAPM_HP("Headphone", NULL),
32969a6d4860SXiubo Li 	SND_SOC_DAPM_SPK("Speaker", NULL),
32979a6d4860SXiubo Li };
32989a6d4860SXiubo Li 
329921efde50SKuninori Morimoto int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
33009a6d4860SXiubo Li 					  const char *propname)
33019a6d4860SXiubo Li {
330221efde50SKuninori Morimoto 	struct device_node *np = card->dev->of_node;
33039a6d4860SXiubo Li 	struct snd_soc_dapm_widget *widgets;
33049a6d4860SXiubo Li 	const char *template, *wname;
33059a6d4860SXiubo Li 	int i, j, num_widgets, ret;
33069a6d4860SXiubo Li 
33079a6d4860SXiubo Li 	num_widgets = of_property_count_strings(np, propname);
33089a6d4860SXiubo Li 	if (num_widgets < 0) {
33099a6d4860SXiubo Li 		dev_err(card->dev,
33109a6d4860SXiubo Li 			"ASoC: Property '%s' does not exist\n",	propname);
33119a6d4860SXiubo Li 		return -EINVAL;
33129a6d4860SXiubo Li 	}
33139a6d4860SXiubo Li 	if (num_widgets & 1) {
33149a6d4860SXiubo Li 		dev_err(card->dev,
33159a6d4860SXiubo Li 			"ASoC: Property '%s' length is not even\n", propname);
33169a6d4860SXiubo Li 		return -EINVAL;
33179a6d4860SXiubo Li 	}
33189a6d4860SXiubo Li 
33199a6d4860SXiubo Li 	num_widgets /= 2;
33209a6d4860SXiubo Li 	if (!num_widgets) {
33219a6d4860SXiubo Li 		dev_err(card->dev, "ASoC: Property '%s's length is zero\n",
33229a6d4860SXiubo Li 			propname);
33239a6d4860SXiubo Li 		return -EINVAL;
33249a6d4860SXiubo Li 	}
33259a6d4860SXiubo Li 
33269a6d4860SXiubo Li 	widgets = devm_kcalloc(card->dev, num_widgets, sizeof(*widgets),
33279a6d4860SXiubo Li 			       GFP_KERNEL);
33289a6d4860SXiubo Li 	if (!widgets) {
33299a6d4860SXiubo Li 		dev_err(card->dev,
33309a6d4860SXiubo Li 			"ASoC: Could not allocate memory for widgets\n");
33319a6d4860SXiubo Li 		return -ENOMEM;
33329a6d4860SXiubo Li 	}
33339a6d4860SXiubo Li 
33349a6d4860SXiubo Li 	for (i = 0; i < num_widgets; i++) {
33359a6d4860SXiubo Li 		ret = of_property_read_string_index(np, propname,
33369a6d4860SXiubo Li 			2 * i, &template);
33379a6d4860SXiubo Li 		if (ret) {
33389a6d4860SXiubo Li 			dev_err(card->dev,
33399a6d4860SXiubo Li 				"ASoC: Property '%s' index %d read error:%d\n",
33409a6d4860SXiubo Li 				propname, 2 * i, ret);
33419a6d4860SXiubo Li 			return -EINVAL;
33429a6d4860SXiubo Li 		}
33439a6d4860SXiubo Li 
33449a6d4860SXiubo Li 		for (j = 0; j < ARRAY_SIZE(simple_widgets); j++) {
33459a6d4860SXiubo Li 			if (!strncmp(template, simple_widgets[j].name,
33469a6d4860SXiubo Li 				     strlen(simple_widgets[j].name))) {
33479a6d4860SXiubo Li 				widgets[i] = simple_widgets[j];
33489a6d4860SXiubo Li 				break;
33499a6d4860SXiubo Li 			}
33509a6d4860SXiubo Li 		}
33519a6d4860SXiubo Li 
33529a6d4860SXiubo Li 		if (j >= ARRAY_SIZE(simple_widgets)) {
33539a6d4860SXiubo Li 			dev_err(card->dev,
33549a6d4860SXiubo Li 				"ASoC: DAPM widget '%s' is not supported\n",
33559a6d4860SXiubo Li 				template);
33569a6d4860SXiubo Li 			return -EINVAL;
33579a6d4860SXiubo Li 		}
33589a6d4860SXiubo Li 
33599a6d4860SXiubo Li 		ret = of_property_read_string_index(np, propname,
33609a6d4860SXiubo Li 						    (2 * i) + 1,
33619a6d4860SXiubo Li 						    &wname);
33629a6d4860SXiubo Li 		if (ret) {
33639a6d4860SXiubo Li 			dev_err(card->dev,
33649a6d4860SXiubo Li 				"ASoC: Property '%s' index %d read error:%d\n",
33659a6d4860SXiubo Li 				propname, (2 * i) + 1, ret);
33669a6d4860SXiubo Li 			return -EINVAL;
33679a6d4860SXiubo Li 		}
33689a6d4860SXiubo Li 
33699a6d4860SXiubo Li 		widgets[i].name = wname;
33709a6d4860SXiubo Li 	}
33719a6d4860SXiubo Li 
3372f23e860eSNicolin Chen 	card->of_dapm_widgets = widgets;
3373f23e860eSNicolin Chen 	card->num_of_dapm_widgets = num_widgets;
33749a6d4860SXiubo Li 
33759a6d4860SXiubo Li 	return 0;
33769a6d4860SXiubo Li }
337721efde50SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets);
33789a6d4860SXiubo Li 
3379cbdfab3bSJerome Brunet int snd_soc_of_get_slot_mask(struct device_node *np,
33806131084aSJyri Sarha 			     const char *prop_name,
33816131084aSJyri Sarha 			     unsigned int *mask)
33826131084aSJyri Sarha {
33836131084aSJyri Sarha 	u32 val;
33846c84e591SJyri Sarha 	const __be32 *of_slot_mask = of_get_property(np, prop_name, &val);
33856131084aSJyri Sarha 	int i;
33866131084aSJyri Sarha 
33876131084aSJyri Sarha 	if (!of_slot_mask)
33886131084aSJyri Sarha 		return 0;
33896131084aSJyri Sarha 	val /= sizeof(u32);
33906131084aSJyri Sarha 	for (i = 0; i < val; i++)
33916131084aSJyri Sarha 		if (be32_to_cpup(&of_slot_mask[i]))
33926131084aSJyri Sarha 			*mask |= (1 << i);
33936131084aSJyri Sarha 
33946131084aSJyri Sarha 	return val;
33956131084aSJyri Sarha }
3396cbdfab3bSJerome Brunet EXPORT_SYMBOL_GPL(snd_soc_of_get_slot_mask);
33976131084aSJyri Sarha 
339889c67857SXiubo Li int snd_soc_of_parse_tdm_slot(struct device_node *np,
33996131084aSJyri Sarha 			      unsigned int *tx_mask,
34006131084aSJyri Sarha 			      unsigned int *rx_mask,
340189c67857SXiubo Li 			      unsigned int *slots,
340289c67857SXiubo Li 			      unsigned int *slot_width)
340389c67857SXiubo Li {
340489c67857SXiubo Li 	u32 val;
340589c67857SXiubo Li 	int ret;
340689c67857SXiubo Li 
34076131084aSJyri Sarha 	if (tx_mask)
34086131084aSJyri Sarha 		snd_soc_of_get_slot_mask(np, "dai-tdm-slot-tx-mask", tx_mask);
34096131084aSJyri Sarha 	if (rx_mask)
34106131084aSJyri Sarha 		snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", rx_mask);
34116131084aSJyri Sarha 
341289c67857SXiubo Li 	if (of_property_read_bool(np, "dai-tdm-slot-num")) {
341389c67857SXiubo Li 		ret = of_property_read_u32(np, "dai-tdm-slot-num", &val);
341489c67857SXiubo Li 		if (ret)
341589c67857SXiubo Li 			return ret;
341689c67857SXiubo Li 
341789c67857SXiubo Li 		if (slots)
341889c67857SXiubo Li 			*slots = val;
341989c67857SXiubo Li 	}
342089c67857SXiubo Li 
342189c67857SXiubo Li 	if (of_property_read_bool(np, "dai-tdm-slot-width")) {
342289c67857SXiubo Li 		ret = of_property_read_u32(np, "dai-tdm-slot-width", &val);
342389c67857SXiubo Li 		if (ret)
342489c67857SXiubo Li 			return ret;
342589c67857SXiubo Li 
342689c67857SXiubo Li 		if (slot_width)
342789c67857SXiubo Li 			*slot_width = val;
342889c67857SXiubo Li 	}
342989c67857SXiubo Li 
343089c67857SXiubo Li 	return 0;
343189c67857SXiubo Li }
343289c67857SXiubo Li EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot);
343389c67857SXiubo Li 
3434440a3006SKuninori Morimoto void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
34355e3cdaa2SKuninori Morimoto 				   struct snd_soc_codec_conf *codec_conf,
34365e3cdaa2SKuninori Morimoto 				   struct device_node *of_node,
34375e3cdaa2SKuninori Morimoto 				   const char *propname)
34385e3cdaa2SKuninori Morimoto {
3439440a3006SKuninori Morimoto 	struct device_node *np = card->dev->of_node;
34405e3cdaa2SKuninori Morimoto 	const char *str;
34415e3cdaa2SKuninori Morimoto 	int ret;
34425e3cdaa2SKuninori Morimoto 
34435e3cdaa2SKuninori Morimoto 	ret = of_property_read_string(np, propname, &str);
34445e3cdaa2SKuninori Morimoto 	if (ret < 0) {
34455e3cdaa2SKuninori Morimoto 		/* no prefix is not error */
34465e3cdaa2SKuninori Morimoto 		return;
34475e3cdaa2SKuninori Morimoto 	}
34485e3cdaa2SKuninori Morimoto 
34495e3cdaa2SKuninori Morimoto 	codec_conf->of_node	= of_node;
34505e3cdaa2SKuninori Morimoto 	codec_conf->name_prefix	= str;
34515e3cdaa2SKuninori Morimoto }
3452440a3006SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix);
34535e3cdaa2SKuninori Morimoto 
34542bc644afSKuninori Morimoto int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
3455a4a54dd5SStephen Warren 				   const char *propname)
3456a4a54dd5SStephen Warren {
34572bc644afSKuninori Morimoto 	struct device_node *np = card->dev->of_node;
3458e3b1e6a1SMark Brown 	int num_routes;
3459a4a54dd5SStephen Warren 	struct snd_soc_dapm_route *routes;
3460a4a54dd5SStephen Warren 	int i, ret;
3461a4a54dd5SStephen Warren 
3462a4a54dd5SStephen Warren 	num_routes = of_property_count_strings(np, propname);
3463c34ce320SRichard Zhao 	if (num_routes < 0 || num_routes & 1) {
346410e8aa9aSMichał Mirosław 		dev_err(card->dev,
346510e8aa9aSMichał Mirosław 			"ASoC: Property '%s' does not exist or its length is not even\n",
346610e8aa9aSMichał Mirosław 			propname);
3467a4a54dd5SStephen Warren 		return -EINVAL;
3468a4a54dd5SStephen Warren 	}
3469a4a54dd5SStephen Warren 	num_routes /= 2;
3470a4a54dd5SStephen Warren 	if (!num_routes) {
3471f110bfc7SLiam Girdwood 		dev_err(card->dev, "ASoC: Property '%s's length is zero\n",
3472a4a54dd5SStephen Warren 			propname);
3473a4a54dd5SStephen Warren 		return -EINVAL;
3474a4a54dd5SStephen Warren 	}
3475a4a54dd5SStephen Warren 
3476a86854d0SKees Cook 	routes = devm_kcalloc(card->dev, num_routes, sizeof(*routes),
3477a4a54dd5SStephen Warren 			      GFP_KERNEL);
3478a4a54dd5SStephen Warren 	if (!routes) {
3479a4a54dd5SStephen Warren 		dev_err(card->dev,
3480f110bfc7SLiam Girdwood 			"ASoC: Could not allocate DAPM route table\n");
3481a4a54dd5SStephen Warren 		return -EINVAL;
3482a4a54dd5SStephen Warren 	}
3483a4a54dd5SStephen Warren 
3484a4a54dd5SStephen Warren 	for (i = 0; i < num_routes; i++) {
3485a4a54dd5SStephen Warren 		ret = of_property_read_string_index(np, propname,
3486e3b1e6a1SMark Brown 			2 * i, &routes[i].sink);
3487a4a54dd5SStephen Warren 		if (ret) {
3488c871bd0bSMark Brown 			dev_err(card->dev,
3489c871bd0bSMark Brown 				"ASoC: Property '%s' index %d could not be read: %d\n",
3490c871bd0bSMark Brown 				propname, 2 * i, ret);
3491a4a54dd5SStephen Warren 			return -EINVAL;
3492a4a54dd5SStephen Warren 		}
3493a4a54dd5SStephen Warren 		ret = of_property_read_string_index(np, propname,
3494e3b1e6a1SMark Brown 			(2 * i) + 1, &routes[i].source);
3495a4a54dd5SStephen Warren 		if (ret) {
3496a4a54dd5SStephen Warren 			dev_err(card->dev,
3497c871bd0bSMark Brown 				"ASoC: Property '%s' index %d could not be read: %d\n",
3498c871bd0bSMark Brown 				propname, (2 * i) + 1, ret);
3499a4a54dd5SStephen Warren 			return -EINVAL;
3500a4a54dd5SStephen Warren 		}
3501a4a54dd5SStephen Warren 	}
3502a4a54dd5SStephen Warren 
3503f23e860eSNicolin Chen 	card->num_of_dapm_routes = num_routes;
3504f23e860eSNicolin Chen 	card->of_dapm_routes = routes;
3505a4a54dd5SStephen Warren 
3506a4a54dd5SStephen Warren 	return 0;
3507a4a54dd5SStephen Warren }
35082bc644afSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing);
3509a4a54dd5SStephen Warren 
3510a7930ed4SKuninori Morimoto unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
3511389cb834SJyri Sarha 				     const char *prefix,
3512389cb834SJyri Sarha 				     struct device_node **bitclkmaster,
3513389cb834SJyri Sarha 				     struct device_node **framemaster)
3514a7930ed4SKuninori Morimoto {
3515a7930ed4SKuninori Morimoto 	int ret, i;
3516a7930ed4SKuninori Morimoto 	char prop[128];
3517a7930ed4SKuninori Morimoto 	unsigned int format = 0;
3518a7930ed4SKuninori Morimoto 	int bit, frame;
3519a7930ed4SKuninori Morimoto 	const char *str;
3520a7930ed4SKuninori Morimoto 	struct {
3521a7930ed4SKuninori Morimoto 		char *name;
3522a7930ed4SKuninori Morimoto 		unsigned int val;
3523a7930ed4SKuninori Morimoto 	} of_fmt_table[] = {
3524a7930ed4SKuninori Morimoto 		{ "i2s",	SND_SOC_DAIFMT_I2S },
3525a7930ed4SKuninori Morimoto 		{ "right_j",	SND_SOC_DAIFMT_RIGHT_J },
3526a7930ed4SKuninori Morimoto 		{ "left_j",	SND_SOC_DAIFMT_LEFT_J },
3527a7930ed4SKuninori Morimoto 		{ "dsp_a",	SND_SOC_DAIFMT_DSP_A },
3528a7930ed4SKuninori Morimoto 		{ "dsp_b",	SND_SOC_DAIFMT_DSP_B },
3529a7930ed4SKuninori Morimoto 		{ "ac97",	SND_SOC_DAIFMT_AC97 },
3530a7930ed4SKuninori Morimoto 		{ "pdm",	SND_SOC_DAIFMT_PDM},
3531a7930ed4SKuninori Morimoto 		{ "msb",	SND_SOC_DAIFMT_MSB },
3532a7930ed4SKuninori Morimoto 		{ "lsb",	SND_SOC_DAIFMT_LSB },
3533a7930ed4SKuninori Morimoto 	};
3534a7930ed4SKuninori Morimoto 
3535a7930ed4SKuninori Morimoto 	if (!prefix)
3536a7930ed4SKuninori Morimoto 		prefix = "";
3537a7930ed4SKuninori Morimoto 
3538a7930ed4SKuninori Morimoto 	/*
35395711c979SKuninori Morimoto 	 * check "dai-format = xxx"
35405711c979SKuninori Morimoto 	 * or    "[prefix]format = xxx"
3541a7930ed4SKuninori Morimoto 	 * SND_SOC_DAIFMT_FORMAT_MASK area
3542a7930ed4SKuninori Morimoto 	 */
35435711c979SKuninori Morimoto 	ret = of_property_read_string(np, "dai-format", &str);
35445711c979SKuninori Morimoto 	if (ret < 0) {
3545a7930ed4SKuninori Morimoto 		snprintf(prop, sizeof(prop), "%sformat", prefix);
3546a7930ed4SKuninori Morimoto 		ret = of_property_read_string(np, prop, &str);
35475711c979SKuninori Morimoto 	}
3548a7930ed4SKuninori Morimoto 	if (ret == 0) {
3549a7930ed4SKuninori Morimoto 		for (i = 0; i < ARRAY_SIZE(of_fmt_table); i++) {
3550a7930ed4SKuninori Morimoto 			if (strcmp(str, of_fmt_table[i].name) == 0) {
3551a7930ed4SKuninori Morimoto 				format |= of_fmt_table[i].val;
3552a7930ed4SKuninori Morimoto 				break;
3553a7930ed4SKuninori Morimoto 			}
3554a7930ed4SKuninori Morimoto 		}
3555a7930ed4SKuninori Morimoto 	}
3556a7930ed4SKuninori Morimoto 
3557a7930ed4SKuninori Morimoto 	/*
35588c2d6a9fSKuninori Morimoto 	 * check "[prefix]continuous-clock"
3559a7930ed4SKuninori Morimoto 	 * SND_SOC_DAIFMT_CLOCK_MASK area
3560a7930ed4SKuninori Morimoto 	 */
35618c2d6a9fSKuninori Morimoto 	snprintf(prop, sizeof(prop), "%scontinuous-clock", prefix);
356251930295SJulia Lawall 	if (of_property_read_bool(np, prop))
35638c2d6a9fSKuninori Morimoto 		format |= SND_SOC_DAIFMT_CONT;
35648c2d6a9fSKuninori Morimoto 	else
35658c2d6a9fSKuninori Morimoto 		format |= SND_SOC_DAIFMT_GATED;
3566a7930ed4SKuninori Morimoto 
3567a7930ed4SKuninori Morimoto 	/*
3568a7930ed4SKuninori Morimoto 	 * check "[prefix]bitclock-inversion"
3569a7930ed4SKuninori Morimoto 	 * check "[prefix]frame-inversion"
3570a7930ed4SKuninori Morimoto 	 * SND_SOC_DAIFMT_INV_MASK area
3571a7930ed4SKuninori Morimoto 	 */
3572a7930ed4SKuninori Morimoto 	snprintf(prop, sizeof(prop), "%sbitclock-inversion", prefix);
3573a7930ed4SKuninori Morimoto 	bit = !!of_get_property(np, prop, NULL);
3574a7930ed4SKuninori Morimoto 
3575a7930ed4SKuninori Morimoto 	snprintf(prop, sizeof(prop), "%sframe-inversion", prefix);
3576a7930ed4SKuninori Morimoto 	frame = !!of_get_property(np, prop, NULL);
3577a7930ed4SKuninori Morimoto 
3578a7930ed4SKuninori Morimoto 	switch ((bit << 4) + frame) {
3579a7930ed4SKuninori Morimoto 	case 0x11:
3580a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_IB_IF;
3581a7930ed4SKuninori Morimoto 		break;
3582a7930ed4SKuninori Morimoto 	case 0x10:
3583a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_IB_NF;
3584a7930ed4SKuninori Morimoto 		break;
3585a7930ed4SKuninori Morimoto 	case 0x01:
3586a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_NB_IF;
3587a7930ed4SKuninori Morimoto 		break;
3588a7930ed4SKuninori Morimoto 	default:
3589a7930ed4SKuninori Morimoto 		/* SND_SOC_DAIFMT_NB_NF is default */
3590a7930ed4SKuninori Morimoto 		break;
3591a7930ed4SKuninori Morimoto 	}
3592a7930ed4SKuninori Morimoto 
3593a7930ed4SKuninori Morimoto 	/*
3594a7930ed4SKuninori Morimoto 	 * check "[prefix]bitclock-master"
3595a7930ed4SKuninori Morimoto 	 * check "[prefix]frame-master"
3596a7930ed4SKuninori Morimoto 	 * SND_SOC_DAIFMT_MASTER_MASK area
3597a7930ed4SKuninori Morimoto 	 */
3598a7930ed4SKuninori Morimoto 	snprintf(prop, sizeof(prop), "%sbitclock-master", prefix);
3599a7930ed4SKuninori Morimoto 	bit = !!of_get_property(np, prop, NULL);
3600389cb834SJyri Sarha 	if (bit && bitclkmaster)
3601389cb834SJyri Sarha 		*bitclkmaster = of_parse_phandle(np, prop, 0);
3602a7930ed4SKuninori Morimoto 
3603a7930ed4SKuninori Morimoto 	snprintf(prop, sizeof(prop), "%sframe-master", prefix);
3604a7930ed4SKuninori Morimoto 	frame = !!of_get_property(np, prop, NULL);
3605389cb834SJyri Sarha 	if (frame && framemaster)
3606389cb834SJyri Sarha 		*framemaster = of_parse_phandle(np, prop, 0);
3607a7930ed4SKuninori Morimoto 
3608a7930ed4SKuninori Morimoto 	switch ((bit << 4) + frame) {
3609a7930ed4SKuninori Morimoto 	case 0x11:
3610a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_CBM_CFM;
3611a7930ed4SKuninori Morimoto 		break;
3612a7930ed4SKuninori Morimoto 	case 0x10:
3613a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_CBM_CFS;
3614a7930ed4SKuninori Morimoto 		break;
3615a7930ed4SKuninori Morimoto 	case 0x01:
3616a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_CBS_CFM;
3617a7930ed4SKuninori Morimoto 		break;
3618a7930ed4SKuninori Morimoto 	default:
3619a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_CBS_CFS;
3620a7930ed4SKuninori Morimoto 		break;
3621a7930ed4SKuninori Morimoto 	}
3622a7930ed4SKuninori Morimoto 
3623a7930ed4SKuninori Morimoto 	return format;
3624a7930ed4SKuninori Morimoto }
3625a7930ed4SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt);
3626a7930ed4SKuninori Morimoto 
3627a180e8b9SKuninori Morimoto int snd_soc_get_dai_id(struct device_node *ep)
3628a180e8b9SKuninori Morimoto {
3629a180e8b9SKuninori Morimoto 	struct snd_soc_component *pos;
3630a180e8b9SKuninori Morimoto 	struct device_node *node;
3631a180e8b9SKuninori Morimoto 	int ret;
3632a180e8b9SKuninori Morimoto 
3633a180e8b9SKuninori Morimoto 	node = of_graph_get_port_parent(ep);
3634a180e8b9SKuninori Morimoto 
3635a180e8b9SKuninori Morimoto 	/*
3636a180e8b9SKuninori Morimoto 	 * For example HDMI case, HDMI has video/sound port,
3637a180e8b9SKuninori Morimoto 	 * but ALSA SoC needs sound port number only.
3638a180e8b9SKuninori Morimoto 	 * Thus counting HDMI DT port/endpoint doesn't work.
3639a180e8b9SKuninori Morimoto 	 * Then, it should have .of_xlate_dai_id
3640a180e8b9SKuninori Morimoto 	 */
3641a180e8b9SKuninori Morimoto 	ret = -ENOTSUPP;
3642a180e8b9SKuninori Morimoto 	mutex_lock(&client_mutex);
3643a180e8b9SKuninori Morimoto 	list_for_each_entry(pos, &component_list, list) {
3644a180e8b9SKuninori Morimoto 		struct device_node *component_of_node = pos->dev->of_node;
3645a180e8b9SKuninori Morimoto 
3646a180e8b9SKuninori Morimoto 		if (!component_of_node && pos->dev->parent)
3647a180e8b9SKuninori Morimoto 			component_of_node = pos->dev->parent->of_node;
3648a180e8b9SKuninori Morimoto 
3649a180e8b9SKuninori Morimoto 		if (component_of_node != node)
3650a180e8b9SKuninori Morimoto 			continue;
3651a180e8b9SKuninori Morimoto 
3652a180e8b9SKuninori Morimoto 		if (pos->driver->of_xlate_dai_id)
3653a180e8b9SKuninori Morimoto 			ret = pos->driver->of_xlate_dai_id(pos, ep);
3654a180e8b9SKuninori Morimoto 
3655a180e8b9SKuninori Morimoto 		break;
3656a180e8b9SKuninori Morimoto 	}
3657a180e8b9SKuninori Morimoto 	mutex_unlock(&client_mutex);
3658a180e8b9SKuninori Morimoto 
3659c0a480d1STony Lindgren 	of_node_put(node);
3660c0a480d1STony Lindgren 
3661a180e8b9SKuninori Morimoto 	return ret;
3662a180e8b9SKuninori Morimoto }
3663a180e8b9SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_get_dai_id);
3664a180e8b9SKuninori Morimoto 
36651ad8ec53SKuninori Morimoto int snd_soc_get_dai_name(struct of_phandle_args *args,
3666cb470087SKuninori Morimoto 				const char **dai_name)
3667cb470087SKuninori Morimoto {
3668cb470087SKuninori Morimoto 	struct snd_soc_component *pos;
36693e0aa8d8SJyri Sarha 	struct device_node *component_of_node;
367093b0f3eeSJean-Francois Moine 	int ret = -EPROBE_DEFER;
3671cb470087SKuninori Morimoto 
3672cb470087SKuninori Morimoto 	mutex_lock(&client_mutex);
3673cb470087SKuninori Morimoto 	list_for_each_entry(pos, &component_list, list) {
36743e0aa8d8SJyri Sarha 		component_of_node = pos->dev->of_node;
36753e0aa8d8SJyri Sarha 		if (!component_of_node && pos->dev->parent)
36763e0aa8d8SJyri Sarha 			component_of_node = pos->dev->parent->of_node;
36773e0aa8d8SJyri Sarha 
36783e0aa8d8SJyri Sarha 		if (component_of_node != args->np)
3679cb470087SKuninori Morimoto 			continue;
3680cb470087SKuninori Morimoto 
36816833c452SKuninori Morimoto 		if (pos->driver->of_xlate_dai_name) {
368293b0f3eeSJean-Francois Moine 			ret = pos->driver->of_xlate_dai_name(pos,
368393b0f3eeSJean-Francois Moine 							     args,
368493b0f3eeSJean-Francois Moine 							     dai_name);
36856833c452SKuninori Morimoto 		} else {
368658bf4179SKuninori Morimoto 			struct snd_soc_dai *dai;
36876833c452SKuninori Morimoto 			int id = -1;
36886833c452SKuninori Morimoto 
368993b0f3eeSJean-Francois Moine 			switch (args->args_count) {
36906833c452SKuninori Morimoto 			case 0:
36916833c452SKuninori Morimoto 				id = 0; /* same as dai_drv[0] */
36926833c452SKuninori Morimoto 				break;
36936833c452SKuninori Morimoto 			case 1:
369493b0f3eeSJean-Francois Moine 				id = args->args[0];
36956833c452SKuninori Morimoto 				break;
36966833c452SKuninori Morimoto 			default:
36976833c452SKuninori Morimoto 				/* not supported */
3698cb470087SKuninori Morimoto 				break;
3699cb470087SKuninori Morimoto 			}
3700cb470087SKuninori Morimoto 
37016833c452SKuninori Morimoto 			if (id < 0 || id >= pos->num_dai) {
37026833c452SKuninori Morimoto 				ret = -EINVAL;
37033dcba280SNicolin Chen 				continue;
37046833c452SKuninori Morimoto 			}
3705e41975edSXiubo Li 
3706e41975edSXiubo Li 			ret = 0;
3707e41975edSXiubo Li 
370858bf4179SKuninori Morimoto 			/* find target DAI */
370958bf4179SKuninori Morimoto 			list_for_each_entry(dai, &pos->dai_list, list) {
371058bf4179SKuninori Morimoto 				if (id == 0)
371158bf4179SKuninori Morimoto 					break;
371258bf4179SKuninori Morimoto 				id--;
371358bf4179SKuninori Morimoto 			}
371458bf4179SKuninori Morimoto 
371558bf4179SKuninori Morimoto 			*dai_name = dai->driver->name;
3716e41975edSXiubo Li 			if (!*dai_name)
3717e41975edSXiubo Li 				*dai_name = pos->name;
37186833c452SKuninori Morimoto 		}
37196833c452SKuninori Morimoto 
3720cb470087SKuninori Morimoto 		break;
3721cb470087SKuninori Morimoto 	}
3722cb470087SKuninori Morimoto 	mutex_unlock(&client_mutex);
372393b0f3eeSJean-Francois Moine 	return ret;
372493b0f3eeSJean-Francois Moine }
37251ad8ec53SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_get_dai_name);
372693b0f3eeSJean-Francois Moine 
372793b0f3eeSJean-Francois Moine int snd_soc_of_get_dai_name(struct device_node *of_node,
372893b0f3eeSJean-Francois Moine 			    const char **dai_name)
372993b0f3eeSJean-Francois Moine {
373093b0f3eeSJean-Francois Moine 	struct of_phandle_args args;
373193b0f3eeSJean-Francois Moine 	int ret;
373293b0f3eeSJean-Francois Moine 
373393b0f3eeSJean-Francois Moine 	ret = of_parse_phandle_with_args(of_node, "sound-dai",
373493b0f3eeSJean-Francois Moine 					 "#sound-dai-cells", 0, &args);
373593b0f3eeSJean-Francois Moine 	if (ret)
373693b0f3eeSJean-Francois Moine 		return ret;
373793b0f3eeSJean-Francois Moine 
373893b0f3eeSJean-Francois Moine 	ret = snd_soc_get_dai_name(&args, dai_name);
3739cb470087SKuninori Morimoto 
3740cb470087SKuninori Morimoto 	of_node_put(args.np);
3741cb470087SKuninori Morimoto 
3742cb470087SKuninori Morimoto 	return ret;
3743cb470087SKuninori Morimoto }
3744cb470087SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name);
3745cb470087SKuninori Morimoto 
374693b0f3eeSJean-Francois Moine /*
374794685763SSylwester Nawrocki  * snd_soc_of_put_dai_link_codecs - Dereference device nodes in the codecs array
374894685763SSylwester Nawrocki  * @dai_link: DAI link
374994685763SSylwester Nawrocki  *
375094685763SSylwester Nawrocki  * Dereference device nodes acquired by snd_soc_of_get_dai_link_codecs().
375194685763SSylwester Nawrocki  */
375294685763SSylwester Nawrocki void snd_soc_of_put_dai_link_codecs(struct snd_soc_dai_link *dai_link)
375394685763SSylwester Nawrocki {
37543db769f1SKuninori Morimoto 	struct snd_soc_dai_link_component *component;
375594685763SSylwester Nawrocki 	int index;
375694685763SSylwester Nawrocki 
37573db769f1SKuninori Morimoto 	for_each_link_codecs(dai_link, index, component) {
375894685763SSylwester Nawrocki 		if (!component->of_node)
375994685763SSylwester Nawrocki 			break;
376094685763SSylwester Nawrocki 		of_node_put(component->of_node);
376194685763SSylwester Nawrocki 		component->of_node = NULL;
376294685763SSylwester Nawrocki 	}
376394685763SSylwester Nawrocki }
376494685763SSylwester Nawrocki EXPORT_SYMBOL_GPL(snd_soc_of_put_dai_link_codecs);
376594685763SSylwester Nawrocki 
376694685763SSylwester Nawrocki /*
376793b0f3eeSJean-Francois Moine  * snd_soc_of_get_dai_link_codecs - Parse a list of CODECs in the devicetree
376893b0f3eeSJean-Francois Moine  * @dev: Card device
376993b0f3eeSJean-Francois Moine  * @of_node: Device node
377093b0f3eeSJean-Francois Moine  * @dai_link: DAI link
377193b0f3eeSJean-Francois Moine  *
377293b0f3eeSJean-Francois Moine  * Builds an array of CODEC DAI components from the DAI link property
377393b0f3eeSJean-Francois Moine  * 'sound-dai'.
377493b0f3eeSJean-Francois Moine  * The array is set in the DAI link and the number of DAIs is set accordingly.
377594685763SSylwester Nawrocki  * The device nodes in the array (of_node) must be dereferenced by calling
377694685763SSylwester Nawrocki  * snd_soc_of_put_dai_link_codecs() on @dai_link.
377793b0f3eeSJean-Francois Moine  *
377893b0f3eeSJean-Francois Moine  * Returns 0 for success
377993b0f3eeSJean-Francois Moine  */
378093b0f3eeSJean-Francois Moine int snd_soc_of_get_dai_link_codecs(struct device *dev,
378193b0f3eeSJean-Francois Moine 				   struct device_node *of_node,
378293b0f3eeSJean-Francois Moine 				   struct snd_soc_dai_link *dai_link)
378393b0f3eeSJean-Francois Moine {
378493b0f3eeSJean-Francois Moine 	struct of_phandle_args args;
378593b0f3eeSJean-Francois Moine 	struct snd_soc_dai_link_component *component;
378693b0f3eeSJean-Francois Moine 	char *name;
378793b0f3eeSJean-Francois Moine 	int index, num_codecs, ret;
378893b0f3eeSJean-Francois Moine 
378993b0f3eeSJean-Francois Moine 	/* Count the number of CODECs */
379093b0f3eeSJean-Francois Moine 	name = "sound-dai";
379193b0f3eeSJean-Francois Moine 	num_codecs = of_count_phandle_with_args(of_node, name,
379293b0f3eeSJean-Francois Moine 						"#sound-dai-cells");
379393b0f3eeSJean-Francois Moine 	if (num_codecs <= 0) {
379493b0f3eeSJean-Francois Moine 		if (num_codecs == -ENOENT)
379593b0f3eeSJean-Francois Moine 			dev_err(dev, "No 'sound-dai' property\n");
379693b0f3eeSJean-Francois Moine 		else
379793b0f3eeSJean-Francois Moine 			dev_err(dev, "Bad phandle in 'sound-dai'\n");
379893b0f3eeSJean-Francois Moine 		return num_codecs;
379993b0f3eeSJean-Francois Moine 	}
3800a86854d0SKees Cook 	component = devm_kcalloc(dev,
3801a86854d0SKees Cook 				 num_codecs, sizeof(*component),
380293b0f3eeSJean-Francois Moine 				 GFP_KERNEL);
380393b0f3eeSJean-Francois Moine 	if (!component)
380493b0f3eeSJean-Francois Moine 		return -ENOMEM;
380593b0f3eeSJean-Francois Moine 	dai_link->codecs = component;
380693b0f3eeSJean-Francois Moine 	dai_link->num_codecs = num_codecs;
380793b0f3eeSJean-Francois Moine 
380893b0f3eeSJean-Francois Moine 	/* Parse the list */
38093db769f1SKuninori Morimoto 	for_each_link_codecs(dai_link, index, component) {
381093b0f3eeSJean-Francois Moine 		ret = of_parse_phandle_with_args(of_node, name,
381193b0f3eeSJean-Francois Moine 						 "#sound-dai-cells",
381293b0f3eeSJean-Francois Moine 						  index, &args);
381393b0f3eeSJean-Francois Moine 		if (ret)
381493b0f3eeSJean-Francois Moine 			goto err;
381593b0f3eeSJean-Francois Moine 		component->of_node = args.np;
381693b0f3eeSJean-Francois Moine 		ret = snd_soc_get_dai_name(&args, &component->dai_name);
381793b0f3eeSJean-Francois Moine 		if (ret < 0)
381893b0f3eeSJean-Francois Moine 			goto err;
381993b0f3eeSJean-Francois Moine 	}
382093b0f3eeSJean-Francois Moine 	return 0;
382193b0f3eeSJean-Francois Moine err:
382294685763SSylwester Nawrocki 	snd_soc_of_put_dai_link_codecs(dai_link);
382393b0f3eeSJean-Francois Moine 	dai_link->codecs = NULL;
382493b0f3eeSJean-Francois Moine 	dai_link->num_codecs = 0;
382593b0f3eeSJean-Francois Moine 	return ret;
382693b0f3eeSJean-Francois Moine }
382793b0f3eeSJean-Francois Moine EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_link_codecs);
382893b0f3eeSJean-Francois Moine 
3829c9b3a40fSTakashi Iwai static int __init snd_soc_init(void)
3830db2a4165SFrank Mandarino {
38316553bf06SLars-Peter Clausen 	snd_soc_debugfs_init();
3832fb257897SMark Brown 	snd_soc_util_init();
3833fb257897SMark Brown 
3834db2a4165SFrank Mandarino 	return platform_driver_register(&soc_driver);
3835db2a4165SFrank Mandarino }
38364abe8e16SMark Brown module_init(snd_soc_init);
3837db2a4165SFrank Mandarino 
38387d8c16a6SMark Brown static void __exit snd_soc_exit(void)
3839db2a4165SFrank Mandarino {
3840fb257897SMark Brown 	snd_soc_util_exit();
38416553bf06SLars-Peter Clausen 	snd_soc_debugfs_exit();
3842fb257897SMark Brown 
3843db2a4165SFrank Mandarino 	platform_driver_unregister(&soc_driver);
3844db2a4165SFrank Mandarino }
3845db2a4165SFrank Mandarino module_exit(snd_soc_exit);
3846db2a4165SFrank Mandarino 
3847db2a4165SFrank Mandarino /* Module information */
3848d331124dSLiam Girdwood MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
3849db2a4165SFrank Mandarino MODULE_DESCRIPTION("ALSA SoC Core");
3850db2a4165SFrank Mandarino MODULE_LICENSE("GPL");
3851db2a4165SFrank Mandarino MODULE_ALIAS("platform:soc-audio");
3852