162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// soc-core.c  --  ALSA SoC Audio Layer
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci// Copyright 2005 Wolfson Microelectronics PLC.
662306a36Sopenharmony_ci// Copyright 2005 Openedhand Ltd.
762306a36Sopenharmony_ci// Copyright (C) 2010 Slimlogic Ltd.
862306a36Sopenharmony_ci// Copyright (C) 2010 Texas Instruments Inc.
962306a36Sopenharmony_ci//
1062306a36Sopenharmony_ci// Author: Liam Girdwood <lrg@slimlogic.co.uk>
1162306a36Sopenharmony_ci//         with code, comments and ideas from :-
1262306a36Sopenharmony_ci//         Richard Purdie <richard@openedhand.com>
1362306a36Sopenharmony_ci//
1462306a36Sopenharmony_ci//  TODO:
1562306a36Sopenharmony_ci//   o Add hw rules to enforce rates, etc.
1662306a36Sopenharmony_ci//   o More testing with other codecs/machines.
1762306a36Sopenharmony_ci//   o Add more codecs and platforms to ensure good API coverage.
1862306a36Sopenharmony_ci//   o Support TDM on PCM and I2S
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <linux/module.h>
2162306a36Sopenharmony_ci#include <linux/moduleparam.h>
2262306a36Sopenharmony_ci#include <linux/init.h>
2362306a36Sopenharmony_ci#include <linux/delay.h>
2462306a36Sopenharmony_ci#include <linux/pm.h>
2562306a36Sopenharmony_ci#include <linux/bitops.h>
2662306a36Sopenharmony_ci#include <linux/debugfs.h>
2762306a36Sopenharmony_ci#include <linux/platform_device.h>
2862306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h>
2962306a36Sopenharmony_ci#include <linux/ctype.h>
3062306a36Sopenharmony_ci#include <linux/slab.h>
3162306a36Sopenharmony_ci#include <linux/of.h>
3262306a36Sopenharmony_ci#include <linux/of_graph.h>
3362306a36Sopenharmony_ci#include <linux/dmi.h>
3462306a36Sopenharmony_ci#include <linux/acpi.h>
3562306a36Sopenharmony_ci#include <sound/core.h>
3662306a36Sopenharmony_ci#include <sound/pcm.h>
3762306a36Sopenharmony_ci#include <sound/pcm_params.h>
3862306a36Sopenharmony_ci#include <sound/soc.h>
3962306a36Sopenharmony_ci#include <sound/soc-dpcm.h>
4062306a36Sopenharmony_ci#include <sound/soc-topology.h>
4162306a36Sopenharmony_ci#include <sound/soc-link.h>
4262306a36Sopenharmony_ci#include <sound/initval.h>
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define CREATE_TRACE_POINTS
4562306a36Sopenharmony_ci#include <trace/events/asoc.h>
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic DEFINE_MUTEX(client_mutex);
4862306a36Sopenharmony_cistatic LIST_HEAD(component_list);
4962306a36Sopenharmony_cistatic LIST_HEAD(unbind_card_list);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define for_each_component(component)			\
5262306a36Sopenharmony_ci	list_for_each_entry(component, &component_list, list)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/*
5562306a36Sopenharmony_ci * This is used if driver don't need to have CPU/Codec/Platform
5662306a36Sopenharmony_ci * dai_link. see soc.h
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_cistruct snd_soc_dai_link_component null_dailink_component[0];
5962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(null_dailink_component);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/*
6262306a36Sopenharmony_ci * This is a timeout to do a DAPM powerdown after a stream is closed().
6362306a36Sopenharmony_ci * It can be used to eliminate pops between different playback streams, e.g.
6462306a36Sopenharmony_ci * between two audio tracks.
6562306a36Sopenharmony_ci */
6662306a36Sopenharmony_cistatic int pmdown_time = 5000;
6762306a36Sopenharmony_cimodule_param(pmdown_time, int, 0);
6862306a36Sopenharmony_ciMODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)");
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic ssize_t pmdown_time_show(struct device *dev,
7162306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	return sysfs_emit(buf, "%ld\n", rtd->pmdown_time);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic ssize_t pmdown_time_store(struct device *dev,
7962306a36Sopenharmony_ci				 struct device_attribute *attr,
8062306a36Sopenharmony_ci				 const char *buf, size_t count)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
8362306a36Sopenharmony_ci	int ret;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	ret = kstrtol(buf, 10, &rtd->pmdown_time);
8662306a36Sopenharmony_ci	if (ret)
8762306a36Sopenharmony_ci		return ret;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	return count;
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic DEVICE_ATTR_RW(pmdown_time);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic struct attribute *soc_dev_attrs[] = {
9562306a36Sopenharmony_ci	&dev_attr_pmdown_time.attr,
9662306a36Sopenharmony_ci	NULL
9762306a36Sopenharmony_ci};
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic umode_t soc_dev_attr_is_visible(struct kobject *kobj,
10062306a36Sopenharmony_ci				       struct attribute *attr, int idx)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
10362306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (!rtd)
10662306a36Sopenharmony_ci		return 0;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (attr == &dev_attr_pmdown_time.attr)
10962306a36Sopenharmony_ci		return attr->mode; /* always visible */
11062306a36Sopenharmony_ci	return rtd->dai_link->num_codecs ? attr->mode : 0; /* enabled only with codec */
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic const struct attribute_group soc_dapm_dev_group = {
11462306a36Sopenharmony_ci	.attrs = soc_dapm_dev_attrs,
11562306a36Sopenharmony_ci	.is_visible = soc_dev_attr_is_visible,
11662306a36Sopenharmony_ci};
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic const struct attribute_group soc_dev_group = {
11962306a36Sopenharmony_ci	.attrs = soc_dev_attrs,
12062306a36Sopenharmony_ci	.is_visible = soc_dev_attr_is_visible,
12162306a36Sopenharmony_ci};
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic const struct attribute_group *soc_dev_attr_groups[] = {
12462306a36Sopenharmony_ci	&soc_dapm_dev_group,
12562306a36Sopenharmony_ci	&soc_dev_group,
12662306a36Sopenharmony_ci	NULL
12762306a36Sopenharmony_ci};
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
13062306a36Sopenharmony_cistruct dentry *snd_soc_debugfs_root;
13162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_debugfs_root);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic void soc_init_component_debugfs(struct snd_soc_component *component)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	if (!component->card->debugfs_card_root)
13662306a36Sopenharmony_ci		return;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	if (component->debugfs_prefix) {
13962306a36Sopenharmony_ci		char *name;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci		name = kasprintf(GFP_KERNEL, "%s:%s",
14262306a36Sopenharmony_ci			component->debugfs_prefix, component->name);
14362306a36Sopenharmony_ci		if (name) {
14462306a36Sopenharmony_ci			component->debugfs_root = debugfs_create_dir(name,
14562306a36Sopenharmony_ci				component->card->debugfs_card_root);
14662306a36Sopenharmony_ci			kfree(name);
14762306a36Sopenharmony_ci		}
14862306a36Sopenharmony_ci	} else {
14962306a36Sopenharmony_ci		component->debugfs_root = debugfs_create_dir(component->name,
15062306a36Sopenharmony_ci				component->card->debugfs_card_root);
15162306a36Sopenharmony_ci	}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	snd_soc_dapm_debugfs_init(snd_soc_component_get_dapm(component),
15462306a36Sopenharmony_ci		component->debugfs_root);
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistatic void soc_cleanup_component_debugfs(struct snd_soc_component *component)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	if (!component->debugfs_root)
16062306a36Sopenharmony_ci		return;
16162306a36Sopenharmony_ci	debugfs_remove_recursive(component->debugfs_root);
16262306a36Sopenharmony_ci	component->debugfs_root = NULL;
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic int dai_list_show(struct seq_file *m, void *v)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	struct snd_soc_component *component;
16862306a36Sopenharmony_ci	struct snd_soc_dai *dai;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	mutex_lock(&client_mutex);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	for_each_component(component)
17362306a36Sopenharmony_ci		for_each_component_dais(component, dai)
17462306a36Sopenharmony_ci			seq_printf(m, "%s\n", dai->name);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	mutex_unlock(&client_mutex);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	return 0;
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(dai_list);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic int component_list_show(struct seq_file *m, void *v)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	struct snd_soc_component *component;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	mutex_lock(&client_mutex);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	for_each_component(component)
18962306a36Sopenharmony_ci		seq_printf(m, "%s\n", component->name);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	mutex_unlock(&client_mutex);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	return 0;
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(component_list);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic void soc_init_card_debugfs(struct snd_soc_card *card)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	card->debugfs_card_root = debugfs_create_dir(card->name,
20062306a36Sopenharmony_ci						     snd_soc_debugfs_root);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	debugfs_create_u32("dapm_pop_time", 0644, card->debugfs_card_root,
20362306a36Sopenharmony_ci			   &card->pop_time);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root);
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic void soc_cleanup_card_debugfs(struct snd_soc_card *card)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	debugfs_remove_recursive(card->debugfs_card_root);
21162306a36Sopenharmony_ci	card->debugfs_card_root = NULL;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistatic void snd_soc_debugfs_init(void)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL,
21962306a36Sopenharmony_ci			    &dai_list_fops);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	debugfs_create_file("components", 0444, snd_soc_debugfs_root, NULL,
22262306a36Sopenharmony_ci			    &component_list_fops);
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic void snd_soc_debugfs_exit(void)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	debugfs_remove_recursive(snd_soc_debugfs_root);
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci#else
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic inline void soc_init_component_debugfs(struct snd_soc_component *component) { }
23362306a36Sopenharmony_cistatic inline void soc_cleanup_component_debugfs(struct snd_soc_component *component) { }
23462306a36Sopenharmony_cistatic inline void soc_init_card_debugfs(struct snd_soc_card *card) { }
23562306a36Sopenharmony_cistatic inline void soc_cleanup_card_debugfs(struct snd_soc_card *card) { }
23662306a36Sopenharmony_cistatic inline void snd_soc_debugfs_init(void) { }
23762306a36Sopenharmony_cistatic inline void snd_soc_debugfs_exit(void) { }
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci#endif
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic int snd_soc_is_match_dai_args(struct of_phandle_args *args1,
24262306a36Sopenharmony_ci				     struct of_phandle_args *args2)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	if (!args1 || !args2)
24562306a36Sopenharmony_ci		return 0;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (args1->np != args2->np)
24862306a36Sopenharmony_ci		return 0;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	for (int i = 0; i < args1->args_count; i++)
25162306a36Sopenharmony_ci		if (args1->args[i] != args2->args[i])
25262306a36Sopenharmony_ci			return 0;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	return 1;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic inline int snd_soc_dlc_component_is_empty(struct snd_soc_dai_link_component *dlc)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	return !(dlc->dai_args || dlc->name || dlc->of_node);
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic inline int snd_soc_dlc_component_is_invalid(struct snd_soc_dai_link_component *dlc)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	return (dlc->name && dlc->of_node);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic inline int snd_soc_dlc_dai_is_empty(struct snd_soc_dai_link_component *dlc)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	return !(dlc->dai_args || dlc->dai_name);
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic int snd_soc_is_matching_dai(const struct snd_soc_dai_link_component *dlc,
27362306a36Sopenharmony_ci				   struct snd_soc_dai *dai)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	if (!dlc)
27662306a36Sopenharmony_ci		return 0;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	if (dlc->dai_args)
27962306a36Sopenharmony_ci		return snd_soc_is_match_dai_args(dai->driver->dai_args, dlc->dai_args);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	if (!dlc->dai_name)
28262306a36Sopenharmony_ci		return 1;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	/* see snd_soc_dai_name_get() */
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	if (strcmp(dlc->dai_name, dai->name) == 0)
28762306a36Sopenharmony_ci		return 1;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (dai->driver->name &&
29062306a36Sopenharmony_ci	    strcmp(dai->driver->name, dlc->dai_name) == 0)
29162306a36Sopenharmony_ci		return 1;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	if (dai->component->name &&
29462306a36Sopenharmony_ci	    strcmp(dlc->dai_name, dai->component->name) == 0)
29562306a36Sopenharmony_ci		return 1;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	return 0;
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ciconst char *snd_soc_dai_name_get(struct snd_soc_dai *dai)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	/* see snd_soc_is_matching_dai() */
30362306a36Sopenharmony_ci	if (dai->name)
30462306a36Sopenharmony_ci		return dai->name;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	if (dai->driver->name)
30762306a36Sopenharmony_ci		return dai->driver->name;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	if (dai->component->name)
31062306a36Sopenharmony_ci		return dai->component->name;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	return NULL;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dai_name_get);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic int snd_soc_rtd_add_component(struct snd_soc_pcm_runtime *rtd,
31762306a36Sopenharmony_ci				     struct snd_soc_component *component)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	struct snd_soc_component *comp;
32062306a36Sopenharmony_ci	int i;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	for_each_rtd_components(rtd, i, comp) {
32362306a36Sopenharmony_ci		/* already connected */
32462306a36Sopenharmony_ci		if (comp == component)
32562306a36Sopenharmony_ci			return 0;
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	/* see for_each_rtd_components */
32962306a36Sopenharmony_ci	rtd->components[rtd->num_components] = component;
33062306a36Sopenharmony_ci	rtd->num_components++;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	return 0;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistruct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd,
33662306a36Sopenharmony_ci						const char *driver_name)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	struct snd_soc_component *component;
33962306a36Sopenharmony_ci	int i;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	if (!driver_name)
34262306a36Sopenharmony_ci		return NULL;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	/*
34562306a36Sopenharmony_ci	 * NOTE
34662306a36Sopenharmony_ci	 *
34762306a36Sopenharmony_ci	 * snd_soc_rtdcom_lookup() will find component from rtd by using
34862306a36Sopenharmony_ci	 * specified driver name.
34962306a36Sopenharmony_ci	 * But, if many components which have same driver name are connected
35062306a36Sopenharmony_ci	 * to 1 rtd, this function will return 1st found component.
35162306a36Sopenharmony_ci	 */
35262306a36Sopenharmony_ci	for_each_rtd_components(rtd, i, component) {
35362306a36Sopenharmony_ci		const char *component_name = component->driver->name;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci		if (!component_name)
35662306a36Sopenharmony_ci			continue;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci		if ((component_name == driver_name) ||
35962306a36Sopenharmony_ci		    strcmp(component_name, driver_name) == 0)
36062306a36Sopenharmony_ci			return component;
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	return NULL;
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_rtdcom_lookup);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistruct snd_soc_component
36862306a36Sopenharmony_ci*snd_soc_lookup_component_nolocked(struct device *dev, const char *driver_name)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	struct snd_soc_component *component;
37162306a36Sopenharmony_ci	struct snd_soc_component *found_component;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	found_component = NULL;
37462306a36Sopenharmony_ci	for_each_component(component) {
37562306a36Sopenharmony_ci		if ((dev == component->dev) &&
37662306a36Sopenharmony_ci		    (!driver_name ||
37762306a36Sopenharmony_ci		     (driver_name == component->driver->name) ||
37862306a36Sopenharmony_ci		     (strcmp(component->driver->name, driver_name) == 0))) {
37962306a36Sopenharmony_ci			found_component = component;
38062306a36Sopenharmony_ci			break;
38162306a36Sopenharmony_ci		}
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	return found_component;
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_lookup_component_nolocked);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_cistruct snd_soc_component *snd_soc_lookup_component(struct device *dev,
38962306a36Sopenharmony_ci						   const char *driver_name)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	struct snd_soc_component *component;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	mutex_lock(&client_mutex);
39462306a36Sopenharmony_ci	component = snd_soc_lookup_component_nolocked(dev, driver_name);
39562306a36Sopenharmony_ci	mutex_unlock(&client_mutex);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	return component;
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_lookup_component);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_cistruct snd_soc_pcm_runtime
40262306a36Sopenharmony_ci*snd_soc_get_pcm_runtime(struct snd_soc_card *card,
40362306a36Sopenharmony_ci			 struct snd_soc_dai_link *dai_link)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	for_each_card_rtds(card, rtd) {
40862306a36Sopenharmony_ci		if (rtd->dai_link == dai_link)
40962306a36Sopenharmony_ci			return rtd;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci	dev_dbg(card->dev, "ASoC: failed to find rtd %s\n", dai_link->name);
41262306a36Sopenharmony_ci	return NULL;
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime);
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci/*
41762306a36Sopenharmony_ci * Power down the audio subsystem pmdown_time msecs after close is called.
41862306a36Sopenharmony_ci * This is to ensure there are no pops or clicks in between any music tracks
41962306a36Sopenharmony_ci * due to DAPM power cycling.
42062306a36Sopenharmony_ci */
42162306a36Sopenharmony_civoid snd_soc_close_delayed_work(struct snd_soc_pcm_runtime *rtd)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
42462306a36Sopenharmony_ci	int playback = SNDRV_PCM_STREAM_PLAYBACK;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	snd_soc_dpcm_mutex_lock(rtd);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	dev_dbg(rtd->dev,
42962306a36Sopenharmony_ci		"ASoC: pop wq checking: %s status: %s waiting: %s\n",
43062306a36Sopenharmony_ci		codec_dai->driver->playback.stream_name,
43162306a36Sopenharmony_ci		snd_soc_dai_stream_active(codec_dai, playback) ?
43262306a36Sopenharmony_ci		"active" : "inactive",
43362306a36Sopenharmony_ci		rtd->pop_wait ? "yes" : "no");
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	/* are we waiting on this codec DAI stream */
43662306a36Sopenharmony_ci	if (rtd->pop_wait == 1) {
43762306a36Sopenharmony_ci		rtd->pop_wait = 0;
43862306a36Sopenharmony_ci		snd_soc_dapm_stream_event(rtd, playback,
43962306a36Sopenharmony_ci					  SND_SOC_DAPM_STREAM_STOP);
44062306a36Sopenharmony_ci	}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	snd_soc_dpcm_mutex_unlock(rtd);
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_close_delayed_work);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic void soc_release_rtd_dev(struct device *dev)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	/* "dev" means "rtd->dev" */
44962306a36Sopenharmony_ci	kfree(dev);
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_cistatic void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	if (!rtd)
45562306a36Sopenharmony_ci		return;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	list_del(&rtd->list);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	if (delayed_work_pending(&rtd->delayed_work))
46062306a36Sopenharmony_ci		flush_delayed_work(&rtd->delayed_work);
46162306a36Sopenharmony_ci	snd_soc_pcm_component_free(rtd);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	/*
46462306a36Sopenharmony_ci	 * we don't need to call kfree() for rtd->dev
46562306a36Sopenharmony_ci	 * see
46662306a36Sopenharmony_ci	 *	soc_release_rtd_dev()
46762306a36Sopenharmony_ci	 *
46862306a36Sopenharmony_ci	 * We don't need rtd->dev NULL check, because
46962306a36Sopenharmony_ci	 * it is alloced *before* rtd.
47062306a36Sopenharmony_ci	 * see
47162306a36Sopenharmony_ci	 *	soc_new_pcm_runtime()
47262306a36Sopenharmony_ci	 *
47362306a36Sopenharmony_ci	 * We don't need to mind freeing for rtd,
47462306a36Sopenharmony_ci	 * because it was created from dev (= rtd->dev)
47562306a36Sopenharmony_ci	 * see
47662306a36Sopenharmony_ci	 *	soc_new_pcm_runtime()
47762306a36Sopenharmony_ci	 *
47862306a36Sopenharmony_ci	 *		rtd = devm_kzalloc(dev, ...);
47962306a36Sopenharmony_ci	 *		rtd->dev = dev
48062306a36Sopenharmony_ci	 */
48162306a36Sopenharmony_ci	device_unregister(rtd->dev);
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_cistatic void close_delayed_work(struct work_struct *work) {
48562306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd =
48662306a36Sopenharmony_ci			container_of(work, struct snd_soc_pcm_runtime,
48762306a36Sopenharmony_ci				     delayed_work.work);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	if (rtd->close_delayed_work_func)
49062306a36Sopenharmony_ci		rtd->close_delayed_work_func(rtd);
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
49462306a36Sopenharmony_ci	struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd;
49762306a36Sopenharmony_ci	struct snd_soc_component *component;
49862306a36Sopenharmony_ci	struct device *dev;
49962306a36Sopenharmony_ci	int ret;
50062306a36Sopenharmony_ci	int stream;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	/*
50362306a36Sopenharmony_ci	 * for rtd->dev
50462306a36Sopenharmony_ci	 */
50562306a36Sopenharmony_ci	dev = kzalloc(sizeof(struct device), GFP_KERNEL);
50662306a36Sopenharmony_ci	if (!dev)
50762306a36Sopenharmony_ci		return NULL;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	dev->parent	= card->dev;
51062306a36Sopenharmony_ci	dev->release	= soc_release_rtd_dev;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	dev_set_name(dev, "%s", dai_link->name);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	ret = device_register(dev);
51562306a36Sopenharmony_ci	if (ret < 0) {
51662306a36Sopenharmony_ci		put_device(dev); /* soc_release_rtd_dev */
51762306a36Sopenharmony_ci		return NULL;
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	/*
52162306a36Sopenharmony_ci	 * for rtd
52262306a36Sopenharmony_ci	 */
52362306a36Sopenharmony_ci	rtd = devm_kzalloc(dev,
52462306a36Sopenharmony_ci			   sizeof(*rtd) +
52562306a36Sopenharmony_ci			   sizeof(component) * (dai_link->num_cpus +
52662306a36Sopenharmony_ci						 dai_link->num_codecs +
52762306a36Sopenharmony_ci						 dai_link->num_platforms),
52862306a36Sopenharmony_ci			   GFP_KERNEL);
52962306a36Sopenharmony_ci	if (!rtd) {
53062306a36Sopenharmony_ci		device_unregister(dev);
53162306a36Sopenharmony_ci		return NULL;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	rtd->dev = dev;
53562306a36Sopenharmony_ci	INIT_LIST_HEAD(&rtd->list);
53662306a36Sopenharmony_ci	for_each_pcm_streams(stream) {
53762306a36Sopenharmony_ci		INIT_LIST_HEAD(&rtd->dpcm[stream].be_clients);
53862306a36Sopenharmony_ci		INIT_LIST_HEAD(&rtd->dpcm[stream].fe_clients);
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci	dev_set_drvdata(dev, rtd);
54162306a36Sopenharmony_ci	INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	/*
54462306a36Sopenharmony_ci	 * for rtd->dais
54562306a36Sopenharmony_ci	 */
54662306a36Sopenharmony_ci	rtd->dais = devm_kcalloc(dev, dai_link->num_cpus + dai_link->num_codecs,
54762306a36Sopenharmony_ci					sizeof(struct snd_soc_dai *),
54862306a36Sopenharmony_ci					GFP_KERNEL);
54962306a36Sopenharmony_ci	if (!rtd->dais)
55062306a36Sopenharmony_ci		goto free_rtd;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	/*
55362306a36Sopenharmony_ci	 * dais = [][][][][][][][][][][][][][][][][][]
55462306a36Sopenharmony_ci	 *	  ^cpu_dais         ^codec_dais
55562306a36Sopenharmony_ci	 *	  |--- num_cpus ---|--- num_codecs --|
55662306a36Sopenharmony_ci	 * see
55762306a36Sopenharmony_ci	 *	asoc_rtd_to_cpu()
55862306a36Sopenharmony_ci	 *	asoc_rtd_to_codec()
55962306a36Sopenharmony_ci	 */
56062306a36Sopenharmony_ci	rtd->card	= card;
56162306a36Sopenharmony_ci	rtd->dai_link	= dai_link;
56262306a36Sopenharmony_ci	rtd->num	= card->num_rtd++;
56362306a36Sopenharmony_ci	rtd->pmdown_time = pmdown_time;			/* default power off timeout */
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	/* see for_each_card_rtds */
56662306a36Sopenharmony_ci	list_add_tail(&rtd->list, &card->rtd_list);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	ret = device_add_groups(dev, soc_dev_attr_groups);
56962306a36Sopenharmony_ci	if (ret < 0)
57062306a36Sopenharmony_ci		goto free_rtd;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	return rtd;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_cifree_rtd:
57562306a36Sopenharmony_ci	soc_free_pcm_runtime(rtd);
57662306a36Sopenharmony_ci	return NULL;
57762306a36Sopenharmony_ci}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_cistatic void snd_soc_flush_all_delayed_work(struct snd_soc_card *card)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	for_each_card_rtds(card, rtd)
58462306a36Sopenharmony_ci		flush_delayed_work(&rtd->delayed_work);
58562306a36Sopenharmony_ci}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
58862306a36Sopenharmony_cistatic void soc_playback_digital_mute(struct snd_soc_card *card, int mute)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd;
59162306a36Sopenharmony_ci	struct snd_soc_dai *dai;
59262306a36Sopenharmony_ci	int playback = SNDRV_PCM_STREAM_PLAYBACK;
59362306a36Sopenharmony_ci	int i;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	for_each_card_rtds(card, rtd) {
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci		if (rtd->dai_link->ignore_suspend)
59862306a36Sopenharmony_ci			continue;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci		for_each_rtd_dais(rtd, i, dai) {
60162306a36Sopenharmony_ci			if (snd_soc_dai_stream_active(dai, playback))
60262306a36Sopenharmony_ci				snd_soc_dai_digital_mute(dai, mute, playback);
60362306a36Sopenharmony_ci		}
60462306a36Sopenharmony_ci	}
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic void soc_dapm_suspend_resume(struct snd_soc_card *card, int event)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd;
61062306a36Sopenharmony_ci	int stream;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	for_each_card_rtds(card, rtd) {
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci		if (rtd->dai_link->ignore_suspend)
61562306a36Sopenharmony_ci			continue;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci		for_each_pcm_streams(stream)
61862306a36Sopenharmony_ci			snd_soc_dapm_stream_event(rtd, stream, event);
61962306a36Sopenharmony_ci	}
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci/* powers down audio subsystem for suspend */
62362306a36Sopenharmony_ciint snd_soc_suspend(struct device *dev)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	struct snd_soc_card *card = dev_get_drvdata(dev);
62662306a36Sopenharmony_ci	struct snd_soc_component *component;
62762306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd;
62862306a36Sopenharmony_ci	int i;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	/* If the card is not initialized yet there is nothing to do */
63162306a36Sopenharmony_ci	if (!snd_soc_card_is_instantiated(card))
63262306a36Sopenharmony_ci		return 0;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	/*
63562306a36Sopenharmony_ci	 * Due to the resume being scheduled into a workqueue we could
63662306a36Sopenharmony_ci	 * suspend before that's finished - wait for it to complete.
63762306a36Sopenharmony_ci	 */
63862306a36Sopenharmony_ci	snd_power_wait(card->snd_card);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	/* we're going to block userspace touching us until resume completes */
64162306a36Sopenharmony_ci	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	/* mute any active DACs */
64462306a36Sopenharmony_ci	soc_playback_digital_mute(card, 1);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	/* suspend all pcms */
64762306a36Sopenharmony_ci	for_each_card_rtds(card, rtd) {
64862306a36Sopenharmony_ci		if (rtd->dai_link->ignore_suspend)
64962306a36Sopenharmony_ci			continue;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci		snd_pcm_suspend_all(rtd->pcm);
65262306a36Sopenharmony_ci	}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	snd_soc_card_suspend_pre(card);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	/* close any waiting streams */
65762306a36Sopenharmony_ci	snd_soc_flush_all_delayed_work(card);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	soc_dapm_suspend_resume(card, SND_SOC_DAPM_STREAM_SUSPEND);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	/* Recheck all endpoints too, their state is affected by suspend */
66262306a36Sopenharmony_ci	dapm_mark_endpoints_dirty(card);
66362306a36Sopenharmony_ci	snd_soc_dapm_sync(&card->dapm);
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	/* suspend all COMPONENTs */
66662306a36Sopenharmony_ci	for_each_card_rtds(card, rtd) {
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci		if (rtd->dai_link->ignore_suspend)
66962306a36Sopenharmony_ci			continue;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci		for_each_rtd_components(rtd, i, component) {
67262306a36Sopenharmony_ci			struct snd_soc_dapm_context *dapm =
67362306a36Sopenharmony_ci				snd_soc_component_get_dapm(component);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci			/*
67662306a36Sopenharmony_ci			 * ignore if component was already suspended
67762306a36Sopenharmony_ci			 */
67862306a36Sopenharmony_ci			if (snd_soc_component_is_suspended(component))
67962306a36Sopenharmony_ci				continue;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci			/*
68262306a36Sopenharmony_ci			 * If there are paths active then the COMPONENT will be
68362306a36Sopenharmony_ci			 * held with bias _ON and should not be suspended.
68462306a36Sopenharmony_ci			 */
68562306a36Sopenharmony_ci			switch (snd_soc_dapm_get_bias_level(dapm)) {
68662306a36Sopenharmony_ci			case SND_SOC_BIAS_STANDBY:
68762306a36Sopenharmony_ci				/*
68862306a36Sopenharmony_ci				 * If the COMPONENT is capable of idle
68962306a36Sopenharmony_ci				 * bias off then being in STANDBY
69062306a36Sopenharmony_ci				 * means it's doing something,
69162306a36Sopenharmony_ci				 * otherwise fall through.
69262306a36Sopenharmony_ci				 */
69362306a36Sopenharmony_ci				if (dapm->idle_bias_off) {
69462306a36Sopenharmony_ci					dev_dbg(component->dev,
69562306a36Sopenharmony_ci						"ASoC: idle_bias_off CODEC on over suspend\n");
69662306a36Sopenharmony_ci					break;
69762306a36Sopenharmony_ci				}
69862306a36Sopenharmony_ci				fallthrough;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci			case SND_SOC_BIAS_OFF:
70162306a36Sopenharmony_ci				snd_soc_component_suspend(component);
70262306a36Sopenharmony_ci				if (component->regmap)
70362306a36Sopenharmony_ci					regcache_mark_dirty(component->regmap);
70462306a36Sopenharmony_ci				/* deactivate pins to sleep state */
70562306a36Sopenharmony_ci				pinctrl_pm_select_sleep_state(component->dev);
70662306a36Sopenharmony_ci				break;
70762306a36Sopenharmony_ci			default:
70862306a36Sopenharmony_ci				dev_dbg(component->dev,
70962306a36Sopenharmony_ci					"ASoC: COMPONENT is on over suspend\n");
71062306a36Sopenharmony_ci				break;
71162306a36Sopenharmony_ci			}
71262306a36Sopenharmony_ci		}
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	snd_soc_card_suspend_post(card);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	return 0;
71862306a36Sopenharmony_ci}
71962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_suspend);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci/*
72262306a36Sopenharmony_ci * deferred resume work, so resume can complete before we finished
72362306a36Sopenharmony_ci * setting our codec back up, which can be very slow on I2C
72462306a36Sopenharmony_ci */
72562306a36Sopenharmony_cistatic void soc_resume_deferred(struct work_struct *work)
72662306a36Sopenharmony_ci{
72762306a36Sopenharmony_ci	struct snd_soc_card *card =
72862306a36Sopenharmony_ci			container_of(work, struct snd_soc_card,
72962306a36Sopenharmony_ci				     deferred_resume_work);
73062306a36Sopenharmony_ci	struct snd_soc_component *component;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	/*
73362306a36Sopenharmony_ci	 * our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
73462306a36Sopenharmony_ci	 * so userspace apps are blocked from touching us
73562306a36Sopenharmony_ci	 */
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	dev_dbg(card->dev, "ASoC: starting resume work\n");
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	/* Bring us up into D2 so that DAPM starts enabling things */
74062306a36Sopenharmony_ci	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D2);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	snd_soc_card_resume_pre(card);
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	for_each_card_components(card, component) {
74562306a36Sopenharmony_ci		if (snd_soc_component_is_suspended(component))
74662306a36Sopenharmony_ci			snd_soc_component_resume(component);
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	soc_dapm_suspend_resume(card, SND_SOC_DAPM_STREAM_RESUME);
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	/* unmute any active DACs */
75262306a36Sopenharmony_ci	soc_playback_digital_mute(card, 0);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	snd_soc_card_resume_post(card);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	dev_dbg(card->dev, "ASoC: resume work completed\n");
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	/* Recheck all endpoints too, their state is affected by suspend */
75962306a36Sopenharmony_ci	dapm_mark_endpoints_dirty(card);
76062306a36Sopenharmony_ci	snd_soc_dapm_sync(&card->dapm);
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	/* userspace can access us now we are back as we were before */
76362306a36Sopenharmony_ci	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0);
76462306a36Sopenharmony_ci}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci/* powers up audio subsystem after a suspend */
76762306a36Sopenharmony_ciint snd_soc_resume(struct device *dev)
76862306a36Sopenharmony_ci{
76962306a36Sopenharmony_ci	struct snd_soc_card *card = dev_get_drvdata(dev);
77062306a36Sopenharmony_ci	struct snd_soc_component *component;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	/* If the card is not initialized yet there is nothing to do */
77362306a36Sopenharmony_ci	if (!snd_soc_card_is_instantiated(card))
77462306a36Sopenharmony_ci		return 0;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	/* activate pins from sleep state */
77762306a36Sopenharmony_ci	for_each_card_components(card, component)
77862306a36Sopenharmony_ci		if (snd_soc_component_active(component))
77962306a36Sopenharmony_ci			pinctrl_pm_select_default_state(component->dev);
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	dev_dbg(dev, "ASoC: Scheduling resume work\n");
78262306a36Sopenharmony_ci	if (!schedule_work(&card->deferred_resume_work))
78362306a36Sopenharmony_ci		dev_err(dev, "ASoC: resume work item may be lost\n");
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	return 0;
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_resume);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_cistatic void soc_resume_init(struct snd_soc_card *card)
79062306a36Sopenharmony_ci{
79162306a36Sopenharmony_ci	/* deferred resume work */
79262306a36Sopenharmony_ci	INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
79362306a36Sopenharmony_ci}
79462306a36Sopenharmony_ci#else
79562306a36Sopenharmony_ci#define snd_soc_suspend NULL
79662306a36Sopenharmony_ci#define snd_soc_resume NULL
79762306a36Sopenharmony_cistatic inline void soc_resume_init(struct snd_soc_card *card) { }
79862306a36Sopenharmony_ci#endif
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_cistatic struct device_node
80162306a36Sopenharmony_ci*soc_component_to_node(struct snd_soc_component *component)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	struct device_node *of_node;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	of_node = component->dev->of_node;
80662306a36Sopenharmony_ci	if (!of_node && component->dev->parent)
80762306a36Sopenharmony_ci		of_node = component->dev->parent->of_node;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	return of_node;
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_cistruct of_phandle_args *snd_soc_copy_dai_args(struct device *dev, struct of_phandle_args *args)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	struct of_phandle_args *ret = devm_kzalloc(dev, sizeof(*ret), GFP_KERNEL);
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	if (!ret)
81762306a36Sopenharmony_ci		return NULL;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	*ret = *args;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	return ret;
82262306a36Sopenharmony_ci}
82362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_copy_dai_args);
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_cistatic int snd_soc_is_matching_component(
82662306a36Sopenharmony_ci	const struct snd_soc_dai_link_component *dlc,
82762306a36Sopenharmony_ci	struct snd_soc_component *component)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	struct device_node *component_of_node;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	if (!dlc)
83262306a36Sopenharmony_ci		return 0;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	if (dlc->dai_args) {
83562306a36Sopenharmony_ci		struct snd_soc_dai *dai;
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci		for_each_component_dais(component, dai)
83862306a36Sopenharmony_ci			if (snd_soc_is_matching_dai(dlc, dai))
83962306a36Sopenharmony_ci				return 1;
84062306a36Sopenharmony_ci		return 0;
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	component_of_node = soc_component_to_node(component);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	if (dlc->of_node && component_of_node != dlc->of_node)
84662306a36Sopenharmony_ci		return 0;
84762306a36Sopenharmony_ci	if (dlc->name && strcmp(component->name, dlc->name))
84862306a36Sopenharmony_ci		return 0;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	return 1;
85162306a36Sopenharmony_ci}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_cistatic struct snd_soc_component *soc_find_component(
85462306a36Sopenharmony_ci	const struct snd_soc_dai_link_component *dlc)
85562306a36Sopenharmony_ci{
85662306a36Sopenharmony_ci	struct snd_soc_component *component;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	lockdep_assert_held(&client_mutex);
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	/*
86162306a36Sopenharmony_ci	 * NOTE
86262306a36Sopenharmony_ci	 *
86362306a36Sopenharmony_ci	 * It returns *1st* found component, but some driver
86462306a36Sopenharmony_ci	 * has few components by same of_node/name
86562306a36Sopenharmony_ci	 * ex)
86662306a36Sopenharmony_ci	 *	CPU component and generic DMAEngine component
86762306a36Sopenharmony_ci	 */
86862306a36Sopenharmony_ci	for_each_component(component)
86962306a36Sopenharmony_ci		if (snd_soc_is_matching_component(dlc, component))
87062306a36Sopenharmony_ci			return component;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	return NULL;
87362306a36Sopenharmony_ci}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci/**
87662306a36Sopenharmony_ci * snd_soc_find_dai - Find a registered DAI
87762306a36Sopenharmony_ci *
87862306a36Sopenharmony_ci * @dlc: name of the DAI or the DAI driver and optional component info to match
87962306a36Sopenharmony_ci *
88062306a36Sopenharmony_ci * This function will search all registered components and their DAIs to
88162306a36Sopenharmony_ci * find the DAI of the same name. The component's of_node and name
88262306a36Sopenharmony_ci * should also match if being specified.
88362306a36Sopenharmony_ci *
88462306a36Sopenharmony_ci * Return: pointer of DAI, or NULL if not found.
88562306a36Sopenharmony_ci */
88662306a36Sopenharmony_cistruct snd_soc_dai *snd_soc_find_dai(
88762306a36Sopenharmony_ci	const struct snd_soc_dai_link_component *dlc)
88862306a36Sopenharmony_ci{
88962306a36Sopenharmony_ci	struct snd_soc_component *component;
89062306a36Sopenharmony_ci	struct snd_soc_dai *dai;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	lockdep_assert_held(&client_mutex);
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	/* Find CPU DAI from registered DAIs */
89562306a36Sopenharmony_ci	for_each_component(component)
89662306a36Sopenharmony_ci		if (snd_soc_is_matching_component(dlc, component))
89762306a36Sopenharmony_ci			for_each_component_dais(component, dai)
89862306a36Sopenharmony_ci				if (snd_soc_is_matching_dai(dlc, dai))
89962306a36Sopenharmony_ci					return dai;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	return NULL;
90262306a36Sopenharmony_ci}
90362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_find_dai);
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_cistruct snd_soc_dai *snd_soc_find_dai_with_mutex(
90662306a36Sopenharmony_ci	const struct snd_soc_dai_link_component *dlc)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	struct snd_soc_dai *dai;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	mutex_lock(&client_mutex);
91162306a36Sopenharmony_ci	dai = snd_soc_find_dai(dlc);
91262306a36Sopenharmony_ci	mutex_unlock(&client_mutex);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	return dai;
91562306a36Sopenharmony_ci}
91662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_find_dai_with_mutex);
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_cistatic int soc_dai_link_sanity_check(struct snd_soc_card *card,
91962306a36Sopenharmony_ci				     struct snd_soc_dai_link *link)
92062306a36Sopenharmony_ci{
92162306a36Sopenharmony_ci	int i;
92262306a36Sopenharmony_ci	struct snd_soc_dai_link_component *dlc;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	/* Codec check */
92562306a36Sopenharmony_ci	for_each_link_codecs(link, i, dlc) {
92662306a36Sopenharmony_ci		/*
92762306a36Sopenharmony_ci		 * Codec must be specified by 1 of name or OF node,
92862306a36Sopenharmony_ci		 * not both or neither.
92962306a36Sopenharmony_ci		 */
93062306a36Sopenharmony_ci		if (snd_soc_dlc_component_is_invalid(dlc))
93162306a36Sopenharmony_ci			goto component_invalid;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci		if (snd_soc_dlc_component_is_empty(dlc))
93462306a36Sopenharmony_ci			goto component_empty;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci		/* Codec DAI name must be specified */
93762306a36Sopenharmony_ci		if (snd_soc_dlc_dai_is_empty(dlc))
93862306a36Sopenharmony_ci			goto dai_empty;
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci		/*
94162306a36Sopenharmony_ci		 * Defer card registration if codec component is not added to
94262306a36Sopenharmony_ci		 * component list.
94362306a36Sopenharmony_ci		 */
94462306a36Sopenharmony_ci		if (!soc_find_component(dlc))
94562306a36Sopenharmony_ci			goto component_not_found;
94662306a36Sopenharmony_ci	}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	/* Platform check */
94962306a36Sopenharmony_ci	for_each_link_platforms(link, i, dlc) {
95062306a36Sopenharmony_ci		/*
95162306a36Sopenharmony_ci		 * Platform may be specified by either name or OF node, but it
95262306a36Sopenharmony_ci		 * can be left unspecified, then no components will be inserted
95362306a36Sopenharmony_ci		 * in the rtdcom list
95462306a36Sopenharmony_ci		 */
95562306a36Sopenharmony_ci		if (snd_soc_dlc_component_is_invalid(dlc))
95662306a36Sopenharmony_ci			goto component_invalid;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci		if (snd_soc_dlc_component_is_empty(dlc))
95962306a36Sopenharmony_ci			goto component_empty;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci		/*
96262306a36Sopenharmony_ci		 * Defer card registration if platform component is not added to
96362306a36Sopenharmony_ci		 * component list.
96462306a36Sopenharmony_ci		 */
96562306a36Sopenharmony_ci		if (!soc_find_component(dlc))
96662306a36Sopenharmony_ci			goto component_not_found;
96762306a36Sopenharmony_ci	}
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	/* CPU check */
97062306a36Sopenharmony_ci	for_each_link_cpus(link, i, dlc) {
97162306a36Sopenharmony_ci		/*
97262306a36Sopenharmony_ci		 * CPU device may be specified by either name or OF node, but
97362306a36Sopenharmony_ci		 * can be left unspecified, and will be matched based on DAI
97462306a36Sopenharmony_ci		 * name alone..
97562306a36Sopenharmony_ci		 */
97662306a36Sopenharmony_ci		if (snd_soc_dlc_component_is_invalid(dlc))
97762306a36Sopenharmony_ci			goto component_invalid;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci		if (snd_soc_dlc_component_is_empty(dlc)) {
98162306a36Sopenharmony_ci			/*
98262306a36Sopenharmony_ci			 * At least one of CPU DAI name or CPU device name/node must be specified
98362306a36Sopenharmony_ci			 */
98462306a36Sopenharmony_ci			if (snd_soc_dlc_dai_is_empty(dlc))
98562306a36Sopenharmony_ci				goto component_dai_empty;
98662306a36Sopenharmony_ci		} else {
98762306a36Sopenharmony_ci			/*
98862306a36Sopenharmony_ci			 * Defer card registration if Component is not added
98962306a36Sopenharmony_ci			 */
99062306a36Sopenharmony_ci			if (!soc_find_component(dlc))
99162306a36Sopenharmony_ci				goto component_not_found;
99262306a36Sopenharmony_ci		}
99362306a36Sopenharmony_ci	}
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	return 0;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_cicomponent_invalid:
99862306a36Sopenharmony_ci	dev_err(card->dev, "ASoC: Both Component name/of_node are set for %s\n", link->name);
99962306a36Sopenharmony_ci	return -EINVAL;
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_cicomponent_empty:
100262306a36Sopenharmony_ci	dev_err(card->dev, "ASoC: Neither Component name/of_node are set for %s\n", link->name);
100362306a36Sopenharmony_ci	return -EINVAL;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_cicomponent_not_found:
100662306a36Sopenharmony_ci	dev_dbg(card->dev, "ASoC: Component %s not found for link %s\n", dlc->name, link->name);
100762306a36Sopenharmony_ci	return -EPROBE_DEFER;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_cidai_empty:
101062306a36Sopenharmony_ci	dev_err(card->dev, "ASoC: DAI name is not set for %s\n", link->name);
101162306a36Sopenharmony_ci	return -EINVAL;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_cicomponent_dai_empty:
101462306a36Sopenharmony_ci	dev_err(card->dev, "ASoC: Neither DAI/Component name/of_node are set for %s\n", link->name);
101562306a36Sopenharmony_ci	return -EINVAL;
101662306a36Sopenharmony_ci}
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci/**
101962306a36Sopenharmony_ci * snd_soc_remove_pcm_runtime - Remove a pcm_runtime from card
102062306a36Sopenharmony_ci * @card: The ASoC card to which the pcm_runtime has
102162306a36Sopenharmony_ci * @rtd: The pcm_runtime to remove
102262306a36Sopenharmony_ci *
102362306a36Sopenharmony_ci * This function removes a pcm_runtime from the ASoC card.
102462306a36Sopenharmony_ci */
102562306a36Sopenharmony_civoid snd_soc_remove_pcm_runtime(struct snd_soc_card *card,
102662306a36Sopenharmony_ci				struct snd_soc_pcm_runtime *rtd)
102762306a36Sopenharmony_ci{
102862306a36Sopenharmony_ci	lockdep_assert_held(&client_mutex);
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	/*
103162306a36Sopenharmony_ci	 * Notify the machine driver for extra destruction
103262306a36Sopenharmony_ci	 */
103362306a36Sopenharmony_ci	snd_soc_card_remove_dai_link(card, rtd->dai_link);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	soc_free_pcm_runtime(rtd);
103662306a36Sopenharmony_ci}
103762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_remove_pcm_runtime);
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci/**
104062306a36Sopenharmony_ci * snd_soc_add_pcm_runtime - Add a pcm_runtime dynamically via dai_link
104162306a36Sopenharmony_ci * @card: The ASoC card to which the pcm_runtime is added
104262306a36Sopenharmony_ci * @dai_link: The DAI link to find pcm_runtime
104362306a36Sopenharmony_ci *
104462306a36Sopenharmony_ci * This function adds a pcm_runtime ASoC card by using dai_link.
104562306a36Sopenharmony_ci *
104662306a36Sopenharmony_ci * Note: Topology can use this API to add pcm_runtime when probing the
104762306a36Sopenharmony_ci * topology component. And machine drivers can still define static
104862306a36Sopenharmony_ci * DAI links in dai_link array.
104962306a36Sopenharmony_ci */
105062306a36Sopenharmony_cistatic int snd_soc_add_pcm_runtime(struct snd_soc_card *card,
105162306a36Sopenharmony_ci				   struct snd_soc_dai_link *dai_link)
105262306a36Sopenharmony_ci{
105362306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd;
105462306a36Sopenharmony_ci	struct snd_soc_dai_link_component *codec, *platform, *cpu;
105562306a36Sopenharmony_ci	struct snd_soc_component *component;
105662306a36Sopenharmony_ci	int i, ret;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	lockdep_assert_held(&client_mutex);
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	/*
106162306a36Sopenharmony_ci	 * Notify the machine driver for extra initialization
106262306a36Sopenharmony_ci	 */
106362306a36Sopenharmony_ci	ret = snd_soc_card_add_dai_link(card, dai_link);
106462306a36Sopenharmony_ci	if (ret < 0)
106562306a36Sopenharmony_ci		return ret;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	if (dai_link->ignore)
106862306a36Sopenharmony_ci		return 0;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name);
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	ret = soc_dai_link_sanity_check(card, dai_link);
107362306a36Sopenharmony_ci	if (ret < 0)
107462306a36Sopenharmony_ci		return ret;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	rtd = soc_new_pcm_runtime(card, dai_link);
107762306a36Sopenharmony_ci	if (!rtd)
107862306a36Sopenharmony_ci		return -ENOMEM;
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	for_each_link_cpus(dai_link, i, cpu) {
108162306a36Sopenharmony_ci		asoc_rtd_to_cpu(rtd, i) = snd_soc_find_dai(cpu);
108262306a36Sopenharmony_ci		if (!asoc_rtd_to_cpu(rtd, i)) {
108362306a36Sopenharmony_ci			dev_info(card->dev, "ASoC: CPU DAI %s not registered\n",
108462306a36Sopenharmony_ci				 cpu->dai_name);
108562306a36Sopenharmony_ci			goto _err_defer;
108662306a36Sopenharmony_ci		}
108762306a36Sopenharmony_ci		snd_soc_rtd_add_component(rtd, asoc_rtd_to_cpu(rtd, i)->component);
108862306a36Sopenharmony_ci	}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	/* Find CODEC from registered CODECs */
109162306a36Sopenharmony_ci	for_each_link_codecs(dai_link, i, codec) {
109262306a36Sopenharmony_ci		asoc_rtd_to_codec(rtd, i) = snd_soc_find_dai(codec);
109362306a36Sopenharmony_ci		if (!asoc_rtd_to_codec(rtd, i)) {
109462306a36Sopenharmony_ci			dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n",
109562306a36Sopenharmony_ci				 codec->dai_name);
109662306a36Sopenharmony_ci			goto _err_defer;
109762306a36Sopenharmony_ci		}
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci		snd_soc_rtd_add_component(rtd, asoc_rtd_to_codec(rtd, i)->component);
110062306a36Sopenharmony_ci	}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	/* Find PLATFORM from registered PLATFORMs */
110362306a36Sopenharmony_ci	for_each_link_platforms(dai_link, i, platform) {
110462306a36Sopenharmony_ci		for_each_component(component) {
110562306a36Sopenharmony_ci			if (!snd_soc_is_matching_component(platform, component))
110662306a36Sopenharmony_ci				continue;
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci			snd_soc_rtd_add_component(rtd, component);
110962306a36Sopenharmony_ci		}
111062306a36Sopenharmony_ci	}
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	return 0;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci_err_defer:
111562306a36Sopenharmony_ci	snd_soc_remove_pcm_runtime(card, rtd);
111662306a36Sopenharmony_ci	return -EPROBE_DEFER;
111762306a36Sopenharmony_ci}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ciint snd_soc_add_pcm_runtimes(struct snd_soc_card *card,
112062306a36Sopenharmony_ci			     struct snd_soc_dai_link *dai_link,
112162306a36Sopenharmony_ci			     int num_dai_link)
112262306a36Sopenharmony_ci{
112362306a36Sopenharmony_ci	for (int i = 0; i < num_dai_link; i++) {
112462306a36Sopenharmony_ci		int ret = snd_soc_add_pcm_runtime(card, dai_link + i);
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci		if (ret < 0)
112762306a36Sopenharmony_ci			return ret;
112862306a36Sopenharmony_ci	}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	return 0;
113162306a36Sopenharmony_ci}
113262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_add_pcm_runtimes);
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_cistatic void snd_soc_runtime_get_dai_fmt(struct snd_soc_pcm_runtime *rtd)
113562306a36Sopenharmony_ci{
113662306a36Sopenharmony_ci	struct snd_soc_dai_link *dai_link = rtd->dai_link;
113762306a36Sopenharmony_ci	struct snd_soc_dai *dai, *not_used;
113862306a36Sopenharmony_ci	u64 pos, possible_fmt;
113962306a36Sopenharmony_ci	unsigned int mask = 0, dai_fmt = 0;
114062306a36Sopenharmony_ci	int i, j, priority, pri, until;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	/*
114362306a36Sopenharmony_ci	 * Get selectable format from each DAIs.
114462306a36Sopenharmony_ci	 *
114562306a36Sopenharmony_ci	 ****************************
114662306a36Sopenharmony_ci	 *            NOTE
114762306a36Sopenharmony_ci	 * Using .auto_selectable_formats is not mandatory,
114862306a36Sopenharmony_ci	 * we can select format manually from Sound Card.
114962306a36Sopenharmony_ci	 * When use it, driver should list well tested format only.
115062306a36Sopenharmony_ci	 ****************************
115162306a36Sopenharmony_ci	 *
115262306a36Sopenharmony_ci	 * ex)
115362306a36Sopenharmony_ci	 *	auto_selectable_formats (= SND_SOC_POSSIBLE_xxx)
115462306a36Sopenharmony_ci	 *		 (A)	 (B)	 (C)
115562306a36Sopenharmony_ci	 *	DAI0_: { 0x000F, 0x00F0, 0x0F00 };
115662306a36Sopenharmony_ci	 *	DAI1 : { 0xF000, 0x0F00 };
115762306a36Sopenharmony_ci	 *		 (X)	 (Y)
115862306a36Sopenharmony_ci	 *
115962306a36Sopenharmony_ci	 * "until" will be 3 in this case (MAX array size from DAI0 and DAI1)
116062306a36Sopenharmony_ci	 * Here is dev_dbg() message and comments
116162306a36Sopenharmony_ci	 *
116262306a36Sopenharmony_ci	 * priority = 1
116362306a36Sopenharmony_ci	 * DAI0: (pri, fmt) = (1, 000000000000000F) // 1st check (A) DAI1 is not selected
116462306a36Sopenharmony_ci	 * DAI1: (pri, fmt) = (0, 0000000000000000) //               Necessary Waste
116562306a36Sopenharmony_ci	 * DAI0: (pri, fmt) = (1, 000000000000000F) // 2nd check (A)
116662306a36Sopenharmony_ci	 * DAI1: (pri, fmt) = (1, 000000000000F000) //           (X)
116762306a36Sopenharmony_ci	 * priority = 2
116862306a36Sopenharmony_ci	 * DAI0: (pri, fmt) = (2, 00000000000000FF) // 3rd check (A) + (B)
116962306a36Sopenharmony_ci	 * DAI1: (pri, fmt) = (1, 000000000000F000) //           (X)
117062306a36Sopenharmony_ci	 * DAI0: (pri, fmt) = (2, 00000000000000FF) // 4th check (A) + (B)
117162306a36Sopenharmony_ci	 * DAI1: (pri, fmt) = (2, 000000000000FF00) //           (X) + (Y)
117262306a36Sopenharmony_ci	 * priority = 3
117362306a36Sopenharmony_ci	 * DAI0: (pri, fmt) = (3, 0000000000000FFF) // 5th check (A) + (B) + (C)
117462306a36Sopenharmony_ci	 * DAI1: (pri, fmt) = (2, 000000000000FF00) //           (X) + (Y)
117562306a36Sopenharmony_ci	 * found auto selected format: 0000000000000F00
117662306a36Sopenharmony_ci	 */
117762306a36Sopenharmony_ci	until = snd_soc_dai_get_fmt_max_priority(rtd);
117862306a36Sopenharmony_ci	for (priority = 1; priority <= until; priority++) {
117962306a36Sopenharmony_ci		for_each_rtd_dais(rtd, j, not_used) {
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci			possible_fmt = ULLONG_MAX;
118262306a36Sopenharmony_ci			for_each_rtd_dais(rtd, i, dai) {
118362306a36Sopenharmony_ci				u64 fmt = 0;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci				pri = (j >= i) ? priority : priority - 1;
118662306a36Sopenharmony_ci				fmt = snd_soc_dai_get_fmt(dai, pri);
118762306a36Sopenharmony_ci				possible_fmt &= fmt;
118862306a36Sopenharmony_ci			}
118962306a36Sopenharmony_ci			if (possible_fmt)
119062306a36Sopenharmony_ci				goto found;
119162306a36Sopenharmony_ci		}
119262306a36Sopenharmony_ci	}
119362306a36Sopenharmony_ci	/* Not Found */
119462306a36Sopenharmony_ci	return;
119562306a36Sopenharmony_cifound:
119662306a36Sopenharmony_ci	/*
119762306a36Sopenharmony_ci	 * convert POSSIBLE_DAIFMT to DAIFMT
119862306a36Sopenharmony_ci	 *
119962306a36Sopenharmony_ci	 * Some basic/default settings on each is defined as 0.
120062306a36Sopenharmony_ci	 * see
120162306a36Sopenharmony_ci	 *	SND_SOC_DAIFMT_NB_NF
120262306a36Sopenharmony_ci	 *	SND_SOC_DAIFMT_GATED
120362306a36Sopenharmony_ci	 *
120462306a36Sopenharmony_ci	 * SND_SOC_DAIFMT_xxx_MASK can't notice it if Sound Card specify
120562306a36Sopenharmony_ci	 * these value, and will be overwrite to auto selected value.
120662306a36Sopenharmony_ci	 *
120762306a36Sopenharmony_ci	 * To avoid such issue, loop from 63 to 0 here.
120862306a36Sopenharmony_ci	 * Small number of SND_SOC_POSSIBLE_xxx will be Hi priority.
120962306a36Sopenharmony_ci	 * Basic/Default settings of each part and aboves are defined
121062306a36Sopenharmony_ci	 * as Hi priority (= small number) of SND_SOC_POSSIBLE_xxx.
121162306a36Sopenharmony_ci	 */
121262306a36Sopenharmony_ci	for (i = 63; i >= 0; i--) {
121362306a36Sopenharmony_ci		pos = 1ULL << i;
121462306a36Sopenharmony_ci		switch (possible_fmt & pos) {
121562306a36Sopenharmony_ci		/*
121662306a36Sopenharmony_ci		 * for format
121762306a36Sopenharmony_ci		 */
121862306a36Sopenharmony_ci		case SND_SOC_POSSIBLE_DAIFMT_I2S:
121962306a36Sopenharmony_ci		case SND_SOC_POSSIBLE_DAIFMT_RIGHT_J:
122062306a36Sopenharmony_ci		case SND_SOC_POSSIBLE_DAIFMT_LEFT_J:
122162306a36Sopenharmony_ci		case SND_SOC_POSSIBLE_DAIFMT_DSP_A:
122262306a36Sopenharmony_ci		case SND_SOC_POSSIBLE_DAIFMT_DSP_B:
122362306a36Sopenharmony_ci		case SND_SOC_POSSIBLE_DAIFMT_AC97:
122462306a36Sopenharmony_ci		case SND_SOC_POSSIBLE_DAIFMT_PDM:
122562306a36Sopenharmony_ci			dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_FORMAT_MASK) | i;
122662306a36Sopenharmony_ci			break;
122762306a36Sopenharmony_ci		/*
122862306a36Sopenharmony_ci		 * for clock
122962306a36Sopenharmony_ci		 */
123062306a36Sopenharmony_ci		case SND_SOC_POSSIBLE_DAIFMT_CONT:
123162306a36Sopenharmony_ci			dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_CLOCK_MASK) | SND_SOC_DAIFMT_CONT;
123262306a36Sopenharmony_ci			break;
123362306a36Sopenharmony_ci		case SND_SOC_POSSIBLE_DAIFMT_GATED:
123462306a36Sopenharmony_ci			dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_CLOCK_MASK) | SND_SOC_DAIFMT_GATED;
123562306a36Sopenharmony_ci			break;
123662306a36Sopenharmony_ci		/*
123762306a36Sopenharmony_ci		 * for clock invert
123862306a36Sopenharmony_ci		 */
123962306a36Sopenharmony_ci		case SND_SOC_POSSIBLE_DAIFMT_NB_NF:
124062306a36Sopenharmony_ci			dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_INV_MASK) | SND_SOC_DAIFMT_NB_NF;
124162306a36Sopenharmony_ci			break;
124262306a36Sopenharmony_ci		case SND_SOC_POSSIBLE_DAIFMT_NB_IF:
124362306a36Sopenharmony_ci			dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_INV_MASK) | SND_SOC_DAIFMT_NB_IF;
124462306a36Sopenharmony_ci			break;
124562306a36Sopenharmony_ci		case SND_SOC_POSSIBLE_DAIFMT_IB_NF:
124662306a36Sopenharmony_ci			dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_INV_MASK) | SND_SOC_DAIFMT_IB_NF;
124762306a36Sopenharmony_ci			break;
124862306a36Sopenharmony_ci		case SND_SOC_POSSIBLE_DAIFMT_IB_IF:
124962306a36Sopenharmony_ci			dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_INV_MASK) | SND_SOC_DAIFMT_IB_IF;
125062306a36Sopenharmony_ci			break;
125162306a36Sopenharmony_ci		/*
125262306a36Sopenharmony_ci		 * for clock provider / consumer
125362306a36Sopenharmony_ci		 */
125462306a36Sopenharmony_ci		case SND_SOC_POSSIBLE_DAIFMT_CBP_CFP:
125562306a36Sopenharmony_ci			dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) | SND_SOC_DAIFMT_CBP_CFP;
125662306a36Sopenharmony_ci			break;
125762306a36Sopenharmony_ci		case SND_SOC_POSSIBLE_DAIFMT_CBC_CFP:
125862306a36Sopenharmony_ci			dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) | SND_SOC_DAIFMT_CBC_CFP;
125962306a36Sopenharmony_ci			break;
126062306a36Sopenharmony_ci		case SND_SOC_POSSIBLE_DAIFMT_CBP_CFC:
126162306a36Sopenharmony_ci			dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) | SND_SOC_DAIFMT_CBP_CFC;
126262306a36Sopenharmony_ci			break;
126362306a36Sopenharmony_ci		case SND_SOC_POSSIBLE_DAIFMT_CBC_CFC:
126462306a36Sopenharmony_ci			dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) | SND_SOC_DAIFMT_CBC_CFC;
126562306a36Sopenharmony_ci			break;
126662306a36Sopenharmony_ci		}
126762306a36Sopenharmony_ci	}
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	/*
127062306a36Sopenharmony_ci	 * Some driver might have very complex limitation.
127162306a36Sopenharmony_ci	 * In such case, user want to auto-select non-limitation part,
127262306a36Sopenharmony_ci	 * and want to manually specify complex part.
127362306a36Sopenharmony_ci	 *
127462306a36Sopenharmony_ci	 * Or for example, if both CPU and Codec can be clock provider,
127562306a36Sopenharmony_ci	 * but because of its quality, user want to specify it manually.
127662306a36Sopenharmony_ci	 *
127762306a36Sopenharmony_ci	 * Use manually specified settings if sound card did.
127862306a36Sopenharmony_ci	 */
127962306a36Sopenharmony_ci	if (!(dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK))
128062306a36Sopenharmony_ci		mask |= SND_SOC_DAIFMT_FORMAT_MASK;
128162306a36Sopenharmony_ci	if (!(dai_link->dai_fmt & SND_SOC_DAIFMT_CLOCK_MASK))
128262306a36Sopenharmony_ci		mask |= SND_SOC_DAIFMT_CLOCK_MASK;
128362306a36Sopenharmony_ci	if (!(dai_link->dai_fmt & SND_SOC_DAIFMT_INV_MASK))
128462306a36Sopenharmony_ci		mask |= SND_SOC_DAIFMT_INV_MASK;
128562306a36Sopenharmony_ci	if (!(dai_link->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK))
128662306a36Sopenharmony_ci		mask |= SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	dai_link->dai_fmt |= (dai_fmt & mask);
128962306a36Sopenharmony_ci}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci/**
129262306a36Sopenharmony_ci * snd_soc_runtime_set_dai_fmt() - Change DAI link format for a ASoC runtime
129362306a36Sopenharmony_ci * @rtd: The runtime for which the DAI link format should be changed
129462306a36Sopenharmony_ci * @dai_fmt: The new DAI link format
129562306a36Sopenharmony_ci *
129662306a36Sopenharmony_ci * This function updates the DAI link format for all DAIs connected to the DAI
129762306a36Sopenharmony_ci * link for the specified runtime.
129862306a36Sopenharmony_ci *
129962306a36Sopenharmony_ci * Note: For setups with a static format set the dai_fmt field in the
130062306a36Sopenharmony_ci * corresponding snd_dai_link struct instead of using this function.
130162306a36Sopenharmony_ci *
130262306a36Sopenharmony_ci * Returns 0 on success, otherwise a negative error code.
130362306a36Sopenharmony_ci */
130462306a36Sopenharmony_ciint snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
130562306a36Sopenharmony_ci				unsigned int dai_fmt)
130662306a36Sopenharmony_ci{
130762306a36Sopenharmony_ci	struct snd_soc_dai *cpu_dai;
130862306a36Sopenharmony_ci	struct snd_soc_dai *codec_dai;
130962306a36Sopenharmony_ci	unsigned int i;
131062306a36Sopenharmony_ci	int ret;
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	if (!dai_fmt)
131362306a36Sopenharmony_ci		return 0;
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	for_each_rtd_codec_dais(rtd, i, codec_dai) {
131662306a36Sopenharmony_ci		ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
131762306a36Sopenharmony_ci		if (ret != 0 && ret != -ENOTSUPP)
131862306a36Sopenharmony_ci			return ret;
131962306a36Sopenharmony_ci	}
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	/* Flip the polarity for the "CPU" end of link */
132262306a36Sopenharmony_ci	dai_fmt = snd_soc_daifmt_clock_provider_flipped(dai_fmt);
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
132562306a36Sopenharmony_ci		ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
132662306a36Sopenharmony_ci		if (ret != 0 && ret != -ENOTSUPP)
132762306a36Sopenharmony_ci			return ret;
132862306a36Sopenharmony_ci	}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	return 0;
133162306a36Sopenharmony_ci}
133262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt);
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_cistatic int soc_init_pcm_runtime(struct snd_soc_card *card,
133562306a36Sopenharmony_ci				struct snd_soc_pcm_runtime *rtd)
133662306a36Sopenharmony_ci{
133762306a36Sopenharmony_ci	struct snd_soc_dai_link *dai_link = rtd->dai_link;
133862306a36Sopenharmony_ci	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
133962306a36Sopenharmony_ci	struct snd_soc_component *component;
134062306a36Sopenharmony_ci	int ret, num, i;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	/* do machine specific initialization */
134362306a36Sopenharmony_ci	ret = snd_soc_link_init(rtd);
134462306a36Sopenharmony_ci	if (ret < 0)
134562306a36Sopenharmony_ci		return ret;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	snd_soc_runtime_get_dai_fmt(rtd);
134862306a36Sopenharmony_ci	ret = snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt);
134962306a36Sopenharmony_ci	if (ret)
135062306a36Sopenharmony_ci		goto err;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	/* add DPCM sysfs entries */
135362306a36Sopenharmony_ci	soc_dpcm_debugfs_add(rtd);
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	num = rtd->num;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	/*
135862306a36Sopenharmony_ci	 * most drivers will register their PCMs using DAI link ordering but
135962306a36Sopenharmony_ci	 * topology based drivers can use the DAI link id field to set PCM
136062306a36Sopenharmony_ci	 * device number and then use rtd + a base offset of the BEs.
136162306a36Sopenharmony_ci	 */
136262306a36Sopenharmony_ci	for_each_rtd_components(rtd, i, component) {
136362306a36Sopenharmony_ci		if (!component->driver->use_dai_pcm_id)
136462306a36Sopenharmony_ci			continue;
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci		if (rtd->dai_link->no_pcm)
136762306a36Sopenharmony_ci			num += component->driver->be_pcm_base;
136862306a36Sopenharmony_ci		else
136962306a36Sopenharmony_ci			num = rtd->dai_link->id;
137062306a36Sopenharmony_ci	}
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	/* create compress_device if possible */
137362306a36Sopenharmony_ci	ret = snd_soc_dai_compress_new(cpu_dai, rtd, num);
137462306a36Sopenharmony_ci	if (ret != -ENOTSUPP)
137562306a36Sopenharmony_ci		goto err;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	/* create the pcm */
137862306a36Sopenharmony_ci	ret = soc_new_pcm(rtd, num);
137962306a36Sopenharmony_ci	if (ret < 0) {
138062306a36Sopenharmony_ci		dev_err(card->dev, "ASoC: can't create pcm %s :%d\n",
138162306a36Sopenharmony_ci			dai_link->stream_name, ret);
138262306a36Sopenharmony_ci		goto err;
138362306a36Sopenharmony_ci	}
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	ret = snd_soc_pcm_dai_new(rtd);
138662306a36Sopenharmony_ci	if (ret < 0)
138762306a36Sopenharmony_ci		goto err;
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	rtd->initialized = true;
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	return 0;
139262306a36Sopenharmony_cierr:
139362306a36Sopenharmony_ci	snd_soc_link_exit(rtd);
139462306a36Sopenharmony_ci	return ret;
139562306a36Sopenharmony_ci}
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_cistatic void soc_set_name_prefix(struct snd_soc_card *card,
139862306a36Sopenharmony_ci				struct snd_soc_component *component)
139962306a36Sopenharmony_ci{
140062306a36Sopenharmony_ci	struct device_node *of_node = soc_component_to_node(component);
140162306a36Sopenharmony_ci	const char *str;
140262306a36Sopenharmony_ci	int ret, i;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	for (i = 0; i < card->num_configs; i++) {
140562306a36Sopenharmony_ci		struct snd_soc_codec_conf *map = &card->codec_conf[i];
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci		if (snd_soc_is_matching_component(&map->dlc, component) &&
140862306a36Sopenharmony_ci		    map->name_prefix) {
140962306a36Sopenharmony_ci			component->name_prefix = map->name_prefix;
141062306a36Sopenharmony_ci			return;
141162306a36Sopenharmony_ci		}
141262306a36Sopenharmony_ci	}
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	/*
141562306a36Sopenharmony_ci	 * If there is no configuration table or no match in the table,
141662306a36Sopenharmony_ci	 * check if a prefix is provided in the node
141762306a36Sopenharmony_ci	 */
141862306a36Sopenharmony_ci	ret = of_property_read_string(of_node, "sound-name-prefix", &str);
141962306a36Sopenharmony_ci	if (ret < 0)
142062306a36Sopenharmony_ci		return;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	component->name_prefix = str;
142362306a36Sopenharmony_ci}
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_cistatic void soc_remove_component(struct snd_soc_component *component,
142662306a36Sopenharmony_ci				 int probed)
142762306a36Sopenharmony_ci{
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	if (!component->card)
143062306a36Sopenharmony_ci		return;
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	if (probed)
143362306a36Sopenharmony_ci		snd_soc_component_remove(component);
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	list_del_init(&component->card_list);
143662306a36Sopenharmony_ci	snd_soc_dapm_free(snd_soc_component_get_dapm(component));
143762306a36Sopenharmony_ci	soc_cleanup_component_debugfs(component);
143862306a36Sopenharmony_ci	component->card = NULL;
143962306a36Sopenharmony_ci	snd_soc_component_module_put_when_remove(component);
144062306a36Sopenharmony_ci}
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_cistatic int soc_probe_component(struct snd_soc_card *card,
144362306a36Sopenharmony_ci			       struct snd_soc_component *component)
144462306a36Sopenharmony_ci{
144562306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm =
144662306a36Sopenharmony_ci		snd_soc_component_get_dapm(component);
144762306a36Sopenharmony_ci	struct snd_soc_dai *dai;
144862306a36Sopenharmony_ci	int probed = 0;
144962306a36Sopenharmony_ci	int ret;
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	if (snd_soc_component_is_dummy(component))
145262306a36Sopenharmony_ci		return 0;
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	if (component->card) {
145562306a36Sopenharmony_ci		if (component->card != card) {
145662306a36Sopenharmony_ci			dev_err(component->dev,
145762306a36Sopenharmony_ci				"Trying to bind component \"%s\" to card \"%s\" but is already bound to card \"%s\"\n",
145862306a36Sopenharmony_ci				component->name, card->name, component->card->name);
145962306a36Sopenharmony_ci			return -ENODEV;
146062306a36Sopenharmony_ci		}
146162306a36Sopenharmony_ci		return 0;
146262306a36Sopenharmony_ci	}
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	ret = snd_soc_component_module_get_when_probe(component);
146562306a36Sopenharmony_ci	if (ret < 0)
146662306a36Sopenharmony_ci		return ret;
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	component->card = card;
146962306a36Sopenharmony_ci	soc_set_name_prefix(card, component);
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	soc_init_component_debugfs(component);
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	snd_soc_dapm_init(dapm, card, component);
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	ret = snd_soc_dapm_new_controls(dapm,
147662306a36Sopenharmony_ci					component->driver->dapm_widgets,
147762306a36Sopenharmony_ci					component->driver->num_dapm_widgets);
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	if (ret != 0) {
148062306a36Sopenharmony_ci		dev_err(component->dev,
148162306a36Sopenharmony_ci			"Failed to create new controls %d\n", ret);
148262306a36Sopenharmony_ci		goto err_probe;
148362306a36Sopenharmony_ci	}
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	for_each_component_dais(component, dai) {
148662306a36Sopenharmony_ci		ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
148762306a36Sopenharmony_ci		if (ret != 0) {
148862306a36Sopenharmony_ci			dev_err(component->dev,
148962306a36Sopenharmony_ci				"Failed to create DAI widgets %d\n", ret);
149062306a36Sopenharmony_ci			goto err_probe;
149162306a36Sopenharmony_ci		}
149262306a36Sopenharmony_ci	}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	ret = snd_soc_component_probe(component);
149562306a36Sopenharmony_ci	if (ret < 0)
149662306a36Sopenharmony_ci		goto err_probe;
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	WARN(dapm->idle_bias_off &&
149962306a36Sopenharmony_ci	     dapm->bias_level != SND_SOC_BIAS_OFF,
150062306a36Sopenharmony_ci	     "codec %s can not start from non-off bias with idle_bias_off==1\n",
150162306a36Sopenharmony_ci	     component->name);
150262306a36Sopenharmony_ci	probed = 1;
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	/*
150562306a36Sopenharmony_ci	 * machine specific init
150662306a36Sopenharmony_ci	 * see
150762306a36Sopenharmony_ci	 *	snd_soc_component_set_aux()
150862306a36Sopenharmony_ci	 */
150962306a36Sopenharmony_ci	ret = snd_soc_component_init(component);
151062306a36Sopenharmony_ci	if (ret < 0)
151162306a36Sopenharmony_ci		goto err_probe;
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	ret = snd_soc_add_component_controls(component,
151462306a36Sopenharmony_ci					     component->driver->controls,
151562306a36Sopenharmony_ci					     component->driver->num_controls);
151662306a36Sopenharmony_ci	if (ret < 0)
151762306a36Sopenharmony_ci		goto err_probe;
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	ret = snd_soc_dapm_add_routes(dapm,
152062306a36Sopenharmony_ci				      component->driver->dapm_routes,
152162306a36Sopenharmony_ci				      component->driver->num_dapm_routes);
152262306a36Sopenharmony_ci	if (ret < 0) {
152362306a36Sopenharmony_ci		if (card->disable_route_checks) {
152462306a36Sopenharmony_ci			dev_info(card->dev,
152562306a36Sopenharmony_ci				 "%s: disable_route_checks set, ignoring errors on add_routes\n",
152662306a36Sopenharmony_ci				 __func__);
152762306a36Sopenharmony_ci		} else {
152862306a36Sopenharmony_ci			dev_err(card->dev,
152962306a36Sopenharmony_ci				"%s: snd_soc_dapm_add_routes failed: %d\n",
153062306a36Sopenharmony_ci				__func__, ret);
153162306a36Sopenharmony_ci			goto err_probe;
153262306a36Sopenharmony_ci		}
153362306a36Sopenharmony_ci	}
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	/* see for_each_card_components */
153662306a36Sopenharmony_ci	list_add(&component->card_list, &card->component_dev_list);
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_cierr_probe:
153962306a36Sopenharmony_ci	if (ret < 0)
154062306a36Sopenharmony_ci		soc_remove_component(component, probed);
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	return ret;
154362306a36Sopenharmony_ci}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_cistatic void soc_remove_link_dais(struct snd_soc_card *card)
154662306a36Sopenharmony_ci{
154762306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd;
154862306a36Sopenharmony_ci	int order;
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	for_each_comp_order(order) {
155162306a36Sopenharmony_ci		for_each_card_rtds(card, rtd) {
155262306a36Sopenharmony_ci			/* remove all rtd connected DAIs in good order */
155362306a36Sopenharmony_ci			snd_soc_pcm_dai_remove(rtd, order);
155462306a36Sopenharmony_ci		}
155562306a36Sopenharmony_ci	}
155662306a36Sopenharmony_ci}
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_cistatic int soc_probe_link_dais(struct snd_soc_card *card)
155962306a36Sopenharmony_ci{
156062306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd;
156162306a36Sopenharmony_ci	int order, ret;
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	for_each_comp_order(order) {
156462306a36Sopenharmony_ci		for_each_card_rtds(card, rtd) {
156562306a36Sopenharmony_ci			/* probe all rtd connected DAIs in good order */
156662306a36Sopenharmony_ci			ret = snd_soc_pcm_dai_probe(rtd, order);
156762306a36Sopenharmony_ci			if (ret)
156862306a36Sopenharmony_ci				return ret;
156962306a36Sopenharmony_ci		}
157062306a36Sopenharmony_ci	}
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	return 0;
157362306a36Sopenharmony_ci}
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_cistatic void soc_remove_link_components(struct snd_soc_card *card)
157662306a36Sopenharmony_ci{
157762306a36Sopenharmony_ci	struct snd_soc_component *component;
157862306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd;
157962306a36Sopenharmony_ci	int i, order;
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	for_each_comp_order(order) {
158262306a36Sopenharmony_ci		for_each_card_rtds(card, rtd) {
158362306a36Sopenharmony_ci			for_each_rtd_components(rtd, i, component) {
158462306a36Sopenharmony_ci				if (component->driver->remove_order != order)
158562306a36Sopenharmony_ci					continue;
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci				soc_remove_component(component, 1);
158862306a36Sopenharmony_ci			}
158962306a36Sopenharmony_ci		}
159062306a36Sopenharmony_ci	}
159162306a36Sopenharmony_ci}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_cistatic int soc_probe_link_components(struct snd_soc_card *card)
159462306a36Sopenharmony_ci{
159562306a36Sopenharmony_ci	struct snd_soc_component *component;
159662306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd;
159762306a36Sopenharmony_ci	int i, ret, order;
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	for_each_comp_order(order) {
160062306a36Sopenharmony_ci		for_each_card_rtds(card, rtd) {
160162306a36Sopenharmony_ci			for_each_rtd_components(rtd, i, component) {
160262306a36Sopenharmony_ci				if (component->driver->probe_order != order)
160362306a36Sopenharmony_ci					continue;
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci				ret = soc_probe_component(card, component);
160662306a36Sopenharmony_ci				if (ret < 0)
160762306a36Sopenharmony_ci					return ret;
160862306a36Sopenharmony_ci			}
160962306a36Sopenharmony_ci		}
161062306a36Sopenharmony_ci	}
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	return 0;
161362306a36Sopenharmony_ci}
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_cistatic void soc_unbind_aux_dev(struct snd_soc_card *card)
161662306a36Sopenharmony_ci{
161762306a36Sopenharmony_ci	struct snd_soc_component *component, *_component;
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	for_each_card_auxs_safe(card, component, _component) {
162062306a36Sopenharmony_ci		/* for snd_soc_component_init() */
162162306a36Sopenharmony_ci		snd_soc_component_set_aux(component, NULL);
162262306a36Sopenharmony_ci		list_del(&component->card_aux_list);
162362306a36Sopenharmony_ci	}
162462306a36Sopenharmony_ci}
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_cistatic int soc_bind_aux_dev(struct snd_soc_card *card)
162762306a36Sopenharmony_ci{
162862306a36Sopenharmony_ci	struct snd_soc_component *component;
162962306a36Sopenharmony_ci	struct snd_soc_aux_dev *aux;
163062306a36Sopenharmony_ci	int i;
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	for_each_card_pre_auxs(card, i, aux) {
163362306a36Sopenharmony_ci		/* codecs, usually analog devices */
163462306a36Sopenharmony_ci		component = soc_find_component(&aux->dlc);
163562306a36Sopenharmony_ci		if (!component)
163662306a36Sopenharmony_ci			return -EPROBE_DEFER;
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci		/* for snd_soc_component_init() */
163962306a36Sopenharmony_ci		snd_soc_component_set_aux(component, aux);
164062306a36Sopenharmony_ci		/* see for_each_card_auxs */
164162306a36Sopenharmony_ci		list_add(&component->card_aux_list, &card->aux_comp_list);
164262306a36Sopenharmony_ci	}
164362306a36Sopenharmony_ci	return 0;
164462306a36Sopenharmony_ci}
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_cistatic int soc_probe_aux_devices(struct snd_soc_card *card)
164762306a36Sopenharmony_ci{
164862306a36Sopenharmony_ci	struct snd_soc_component *component;
164962306a36Sopenharmony_ci	int order;
165062306a36Sopenharmony_ci	int ret;
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	for_each_comp_order(order) {
165362306a36Sopenharmony_ci		for_each_card_auxs(card, component) {
165462306a36Sopenharmony_ci			if (component->driver->probe_order != order)
165562306a36Sopenharmony_ci				continue;
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci			ret = soc_probe_component(card,	component);
165862306a36Sopenharmony_ci			if (ret < 0)
165962306a36Sopenharmony_ci				return ret;
166062306a36Sopenharmony_ci		}
166162306a36Sopenharmony_ci	}
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	return 0;
166462306a36Sopenharmony_ci}
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_cistatic void soc_remove_aux_devices(struct snd_soc_card *card)
166762306a36Sopenharmony_ci{
166862306a36Sopenharmony_ci	struct snd_soc_component *comp, *_comp;
166962306a36Sopenharmony_ci	int order;
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	for_each_comp_order(order) {
167262306a36Sopenharmony_ci		for_each_card_auxs_safe(card, comp, _comp) {
167362306a36Sopenharmony_ci			if (comp->driver->remove_order == order)
167462306a36Sopenharmony_ci				soc_remove_component(comp, 1);
167562306a36Sopenharmony_ci		}
167662306a36Sopenharmony_ci	}
167762306a36Sopenharmony_ci}
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci#ifdef CONFIG_DMI
168062306a36Sopenharmony_ci/*
168162306a36Sopenharmony_ci * If a DMI filed contain strings in this blacklist (e.g.
168262306a36Sopenharmony_ci * "Type2 - Board Manufacturer" or "Type1 - TBD by OEM"), it will be taken
168362306a36Sopenharmony_ci * as invalid and dropped when setting the card long name from DMI info.
168462306a36Sopenharmony_ci */
168562306a36Sopenharmony_cistatic const char * const dmi_blacklist[] = {
168662306a36Sopenharmony_ci	"To be filled by OEM",
168762306a36Sopenharmony_ci	"TBD by OEM",
168862306a36Sopenharmony_ci	"Default String",
168962306a36Sopenharmony_ci	"Board Manufacturer",
169062306a36Sopenharmony_ci	"Board Vendor Name",
169162306a36Sopenharmony_ci	"Board Product Name",
169262306a36Sopenharmony_ci	NULL,	/* terminator */
169362306a36Sopenharmony_ci};
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci/*
169662306a36Sopenharmony_ci * Trim special characters, and replace '-' with '_' since '-' is used to
169762306a36Sopenharmony_ci * separate different DMI fields in the card long name. Only number and
169862306a36Sopenharmony_ci * alphabet characters and a few separator characters are kept.
169962306a36Sopenharmony_ci */
170062306a36Sopenharmony_cistatic void cleanup_dmi_name(char *name)
170162306a36Sopenharmony_ci{
170262306a36Sopenharmony_ci	int i, j = 0;
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	for (i = 0; name[i]; i++) {
170562306a36Sopenharmony_ci		if (isalnum(name[i]) || (name[i] == '.')
170662306a36Sopenharmony_ci		    || (name[i] == '_'))
170762306a36Sopenharmony_ci			name[j++] = name[i];
170862306a36Sopenharmony_ci		else if (name[i] == '-')
170962306a36Sopenharmony_ci			name[j++] = '_';
171062306a36Sopenharmony_ci	}
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	name[j] = '\0';
171362306a36Sopenharmony_ci}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci/*
171662306a36Sopenharmony_ci * Check if a DMI field is valid, i.e. not containing any string
171762306a36Sopenharmony_ci * in the black list.
171862306a36Sopenharmony_ci */
171962306a36Sopenharmony_cistatic int is_dmi_valid(const char *field)
172062306a36Sopenharmony_ci{
172162306a36Sopenharmony_ci	int i = 0;
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	while (dmi_blacklist[i]) {
172462306a36Sopenharmony_ci		if (strstr(field, dmi_blacklist[i]))
172562306a36Sopenharmony_ci			return 0;
172662306a36Sopenharmony_ci		i++;
172762306a36Sopenharmony_ci	}
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	return 1;
173062306a36Sopenharmony_ci}
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci/*
173362306a36Sopenharmony_ci * Append a string to card->dmi_longname with character cleanups.
173462306a36Sopenharmony_ci */
173562306a36Sopenharmony_cistatic void append_dmi_string(struct snd_soc_card *card, const char *str)
173662306a36Sopenharmony_ci{
173762306a36Sopenharmony_ci	char *dst = card->dmi_longname;
173862306a36Sopenharmony_ci	size_t dst_len = sizeof(card->dmi_longname);
173962306a36Sopenharmony_ci	size_t len;
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	len = strlen(dst);
174262306a36Sopenharmony_ci	snprintf(dst + len, dst_len - len, "-%s", str);
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	len++;	/* skip the separator "-" */
174562306a36Sopenharmony_ci	if (len < dst_len)
174662306a36Sopenharmony_ci		cleanup_dmi_name(dst + len);
174762306a36Sopenharmony_ci}
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci/**
175062306a36Sopenharmony_ci * snd_soc_set_dmi_name() - Register DMI names to card
175162306a36Sopenharmony_ci * @card: The card to register DMI names
175262306a36Sopenharmony_ci * @flavour: The flavour "differentiator" for the card amongst its peers.
175362306a36Sopenharmony_ci *
175462306a36Sopenharmony_ci * An Intel machine driver may be used by many different devices but are
175562306a36Sopenharmony_ci * difficult for userspace to differentiate, since machine drivers ususally
175662306a36Sopenharmony_ci * use their own name as the card short name and leave the card long name
175762306a36Sopenharmony_ci * blank. To differentiate such devices and fix bugs due to lack of
175862306a36Sopenharmony_ci * device-specific configurations, this function allows DMI info to be used
175962306a36Sopenharmony_ci * as the sound card long name, in the format of
176062306a36Sopenharmony_ci * "vendor-product-version-board"
176162306a36Sopenharmony_ci * (Character '-' is used to separate different DMI fields here).
176262306a36Sopenharmony_ci * This will help the user space to load the device-specific Use Case Manager
176362306a36Sopenharmony_ci * (UCM) configurations for the card.
176462306a36Sopenharmony_ci *
176562306a36Sopenharmony_ci * Possible card long names may be:
176662306a36Sopenharmony_ci * DellInc.-XPS139343-01-0310JH
176762306a36Sopenharmony_ci * ASUSTeKCOMPUTERINC.-T100TA-1.0-T100TA
176862306a36Sopenharmony_ci * Circuitco-MinnowboardMaxD0PLATFORM-D0-MinnowBoardMAX
176962306a36Sopenharmony_ci *
177062306a36Sopenharmony_ci * This function also supports flavoring the card longname to provide
177162306a36Sopenharmony_ci * the extra differentiation, like "vendor-product-version-board-flavor".
177262306a36Sopenharmony_ci *
177362306a36Sopenharmony_ci * We only keep number and alphabet characters and a few separator characters
177462306a36Sopenharmony_ci * in the card long name since UCM in the user space uses the card long names
177562306a36Sopenharmony_ci * as card configuration directory names and AudoConf cannot support special
177662306a36Sopenharmony_ci * charactors like SPACE.
177762306a36Sopenharmony_ci *
177862306a36Sopenharmony_ci * Returns 0 on success, otherwise a negative error code.
177962306a36Sopenharmony_ci */
178062306a36Sopenharmony_ciint snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour)
178162306a36Sopenharmony_ci{
178262306a36Sopenharmony_ci	const char *vendor, *product, *board;
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	if (card->long_name)
178562306a36Sopenharmony_ci		return 0; /* long name already set by driver or from DMI */
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci	if (!dmi_available)
178862306a36Sopenharmony_ci		return 0;
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	/* make up dmi long name as: vendor-product-version-board */
179162306a36Sopenharmony_ci	vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
179262306a36Sopenharmony_ci	if (!vendor || !is_dmi_valid(vendor)) {
179362306a36Sopenharmony_ci		dev_warn(card->dev, "ASoC: no DMI vendor name!\n");
179462306a36Sopenharmony_ci		return 0;
179562306a36Sopenharmony_ci	}
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	snprintf(card->dmi_longname, sizeof(card->dmi_longname), "%s", vendor);
179862306a36Sopenharmony_ci	cleanup_dmi_name(card->dmi_longname);
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	product = dmi_get_system_info(DMI_PRODUCT_NAME);
180162306a36Sopenharmony_ci	if (product && is_dmi_valid(product)) {
180262306a36Sopenharmony_ci		const char *product_version = dmi_get_system_info(DMI_PRODUCT_VERSION);
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci		append_dmi_string(card, product);
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci		/*
180762306a36Sopenharmony_ci		 * some vendors like Lenovo may only put a self-explanatory
180862306a36Sopenharmony_ci		 * name in the product version field
180962306a36Sopenharmony_ci		 */
181062306a36Sopenharmony_ci		if (product_version && is_dmi_valid(product_version))
181162306a36Sopenharmony_ci			append_dmi_string(card, product_version);
181262306a36Sopenharmony_ci	}
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	board = dmi_get_system_info(DMI_BOARD_NAME);
181562306a36Sopenharmony_ci	if (board && is_dmi_valid(board)) {
181662306a36Sopenharmony_ci		if (!product || strcasecmp(board, product))
181762306a36Sopenharmony_ci			append_dmi_string(card, board);
181862306a36Sopenharmony_ci	} else if (!product) {
181962306a36Sopenharmony_ci		/* fall back to using legacy name */
182062306a36Sopenharmony_ci		dev_warn(card->dev, "ASoC: no DMI board/product name!\n");
182162306a36Sopenharmony_ci		return 0;
182262306a36Sopenharmony_ci	}
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	/* Add flavour to dmi long name */
182562306a36Sopenharmony_ci	if (flavour)
182662306a36Sopenharmony_ci		append_dmi_string(card, flavour);
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	/* set the card long name */
182962306a36Sopenharmony_ci	card->long_name = card->dmi_longname;
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	return 0;
183262306a36Sopenharmony_ci}
183362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_set_dmi_name);
183462306a36Sopenharmony_ci#endif /* CONFIG_DMI */
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_cistatic void soc_check_tplg_fes(struct snd_soc_card *card)
183762306a36Sopenharmony_ci{
183862306a36Sopenharmony_ci	struct snd_soc_component *component;
183962306a36Sopenharmony_ci	const struct snd_soc_component_driver *comp_drv;
184062306a36Sopenharmony_ci	struct snd_soc_dai_link *dai_link;
184162306a36Sopenharmony_ci	int i;
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	for_each_component(component) {
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci		/* does this component override BEs ? */
184662306a36Sopenharmony_ci		if (!component->driver->ignore_machine)
184762306a36Sopenharmony_ci			continue;
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci		/* for this machine ? */
185062306a36Sopenharmony_ci		if (!strcmp(component->driver->ignore_machine,
185162306a36Sopenharmony_ci			    card->dev->driver->name))
185262306a36Sopenharmony_ci			goto match;
185362306a36Sopenharmony_ci		if (strcmp(component->driver->ignore_machine,
185462306a36Sopenharmony_ci			   dev_name(card->dev)))
185562306a36Sopenharmony_ci			continue;
185662306a36Sopenharmony_cimatch:
185762306a36Sopenharmony_ci		/* machine matches, so override the rtd data */
185862306a36Sopenharmony_ci		for_each_card_prelinks(card, i, dai_link) {
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci			/* ignore this FE */
186162306a36Sopenharmony_ci			if (dai_link->dynamic) {
186262306a36Sopenharmony_ci				dai_link->ignore = true;
186362306a36Sopenharmony_ci				continue;
186462306a36Sopenharmony_ci			}
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci			dev_dbg(card->dev, "info: override BE DAI link %s\n",
186762306a36Sopenharmony_ci				card->dai_link[i].name);
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci			/* override platform component */
187062306a36Sopenharmony_ci			if (!dai_link->platforms) {
187162306a36Sopenharmony_ci				dev_err(card->dev, "init platform error");
187262306a36Sopenharmony_ci				continue;
187362306a36Sopenharmony_ci			}
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci			if (component->dev->of_node)
187662306a36Sopenharmony_ci				dai_link->platforms->of_node = component->dev->of_node;
187762306a36Sopenharmony_ci			else
187862306a36Sopenharmony_ci				dai_link->platforms->name = component->name;
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci			/* convert non BE into BE */
188162306a36Sopenharmony_ci			if (!dai_link->no_pcm) {
188262306a36Sopenharmony_ci				dai_link->no_pcm = 1;
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci				if (dai_link->dpcm_playback)
188562306a36Sopenharmony_ci					dev_warn(card->dev,
188662306a36Sopenharmony_ci						 "invalid configuration, dailink %s has flags no_pcm=0 and dpcm_playback=1\n",
188762306a36Sopenharmony_ci						 dai_link->name);
188862306a36Sopenharmony_ci				if (dai_link->dpcm_capture)
188962306a36Sopenharmony_ci					dev_warn(card->dev,
189062306a36Sopenharmony_ci						 "invalid configuration, dailink %s has flags no_pcm=0 and dpcm_capture=1\n",
189162306a36Sopenharmony_ci						 dai_link->name);
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci				/* convert normal link into DPCM one */
189462306a36Sopenharmony_ci				if (!(dai_link->dpcm_playback ||
189562306a36Sopenharmony_ci				      dai_link->dpcm_capture)) {
189662306a36Sopenharmony_ci					dai_link->dpcm_playback = !dai_link->capture_only;
189762306a36Sopenharmony_ci					dai_link->dpcm_capture = !dai_link->playback_only;
189862306a36Sopenharmony_ci				}
189962306a36Sopenharmony_ci			}
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci			/*
190262306a36Sopenharmony_ci			 * override any BE fixups
190362306a36Sopenharmony_ci			 * see
190462306a36Sopenharmony_ci			 *	snd_soc_link_be_hw_params_fixup()
190562306a36Sopenharmony_ci			 */
190662306a36Sopenharmony_ci			dai_link->be_hw_params_fixup =
190762306a36Sopenharmony_ci				component->driver->be_hw_params_fixup;
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci			/*
191062306a36Sopenharmony_ci			 * most BE links don't set stream name, so set it to
191162306a36Sopenharmony_ci			 * dai link name if it's NULL to help bind widgets.
191262306a36Sopenharmony_ci			 */
191362306a36Sopenharmony_ci			if (!dai_link->stream_name)
191462306a36Sopenharmony_ci				dai_link->stream_name = dai_link->name;
191562306a36Sopenharmony_ci		}
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci		/* Inform userspace we are using alternate topology */
191862306a36Sopenharmony_ci		if (component->driver->topology_name_prefix) {
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci			/* topology shortname created? */
192162306a36Sopenharmony_ci			if (!card->topology_shortname_created) {
192262306a36Sopenharmony_ci				comp_drv = component->driver;
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci				snprintf(card->topology_shortname, 32, "%s-%s",
192562306a36Sopenharmony_ci					 comp_drv->topology_name_prefix,
192662306a36Sopenharmony_ci					 card->name);
192762306a36Sopenharmony_ci				card->topology_shortname_created = true;
192862306a36Sopenharmony_ci			}
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci			/* use topology shortname */
193162306a36Sopenharmony_ci			card->name = card->topology_shortname;
193262306a36Sopenharmony_ci		}
193362306a36Sopenharmony_ci	}
193462306a36Sopenharmony_ci}
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci#define soc_setup_card_name(card, name, name1, name2) \
193762306a36Sopenharmony_ci	__soc_setup_card_name(card, name, sizeof(name), name1, name2)
193862306a36Sopenharmony_cistatic void __soc_setup_card_name(struct snd_soc_card *card,
193962306a36Sopenharmony_ci				  char *name, int len,
194062306a36Sopenharmony_ci				  const char *name1, const char *name2)
194162306a36Sopenharmony_ci{
194262306a36Sopenharmony_ci	const char *src = name1 ? name1 : name2;
194362306a36Sopenharmony_ci	int i;
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	snprintf(name, len, "%s", src);
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	if (name != card->snd_card->driver)
194862306a36Sopenharmony_ci		return;
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	/*
195162306a36Sopenharmony_ci	 * Name normalization (driver field)
195262306a36Sopenharmony_ci	 *
195362306a36Sopenharmony_ci	 * The driver name is somewhat special, as it's used as a key for
195462306a36Sopenharmony_ci	 * searches in the user-space.
195562306a36Sopenharmony_ci	 *
195662306a36Sopenharmony_ci	 * ex)
195762306a36Sopenharmony_ci	 *	"abcd??efg" -> "abcd__efg"
195862306a36Sopenharmony_ci	 */
195962306a36Sopenharmony_ci	for (i = 0; i < len; i++) {
196062306a36Sopenharmony_ci		switch (name[i]) {
196162306a36Sopenharmony_ci		case '_':
196262306a36Sopenharmony_ci		case '-':
196362306a36Sopenharmony_ci		case '\0':
196462306a36Sopenharmony_ci			break;
196562306a36Sopenharmony_ci		default:
196662306a36Sopenharmony_ci			if (!isalnum(name[i]))
196762306a36Sopenharmony_ci				name[i] = '_';
196862306a36Sopenharmony_ci			break;
196962306a36Sopenharmony_ci		}
197062306a36Sopenharmony_ci	}
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	/*
197362306a36Sopenharmony_ci	 * The driver field should contain a valid string from the user view.
197462306a36Sopenharmony_ci	 * The wrapping usually does not work so well here. Set a smaller string
197562306a36Sopenharmony_ci	 * in the specific ASoC driver.
197662306a36Sopenharmony_ci	 */
197762306a36Sopenharmony_ci	if (strlen(src) > len - 1)
197862306a36Sopenharmony_ci		dev_err(card->dev, "ASoC: driver name too long '%s' -> '%s'\n", src, name);
197962306a36Sopenharmony_ci}
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_cistatic void soc_cleanup_card_resources(struct snd_soc_card *card)
198262306a36Sopenharmony_ci{
198362306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd, *n;
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	if (card->snd_card)
198662306a36Sopenharmony_ci		snd_card_disconnect_sync(card->snd_card);
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci	snd_soc_dapm_shutdown(card);
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	/* release machine specific resources */
199162306a36Sopenharmony_ci	for_each_card_rtds(card, rtd)
199262306a36Sopenharmony_ci		if (rtd->initialized)
199362306a36Sopenharmony_ci			snd_soc_link_exit(rtd);
199462306a36Sopenharmony_ci	/* remove and free each DAI */
199562306a36Sopenharmony_ci	soc_remove_link_dais(card);
199662306a36Sopenharmony_ci	soc_remove_link_components(card);
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci	for_each_card_rtds_safe(card, rtd, n)
199962306a36Sopenharmony_ci		snd_soc_remove_pcm_runtime(card, rtd);
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci	/* remove auxiliary devices */
200262306a36Sopenharmony_ci	soc_remove_aux_devices(card);
200362306a36Sopenharmony_ci	soc_unbind_aux_dev(card);
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci	snd_soc_dapm_free(&card->dapm);
200662306a36Sopenharmony_ci	soc_cleanup_card_debugfs(card);
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci	/* remove the card */
200962306a36Sopenharmony_ci	snd_soc_card_remove(card);
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci	if (card->snd_card) {
201262306a36Sopenharmony_ci		snd_card_free(card->snd_card);
201362306a36Sopenharmony_ci		card->snd_card = NULL;
201462306a36Sopenharmony_ci	}
201562306a36Sopenharmony_ci}
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_cistatic void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister)
201862306a36Sopenharmony_ci{
201962306a36Sopenharmony_ci	if (snd_soc_card_is_instantiated(card)) {
202062306a36Sopenharmony_ci		card->instantiated = false;
202162306a36Sopenharmony_ci		snd_soc_flush_all_delayed_work(card);
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci		soc_cleanup_card_resources(card);
202462306a36Sopenharmony_ci		if (!unregister)
202562306a36Sopenharmony_ci			list_add(&card->list, &unbind_card_list);
202662306a36Sopenharmony_ci	} else {
202762306a36Sopenharmony_ci		if (unregister)
202862306a36Sopenharmony_ci			list_del(&card->list);
202962306a36Sopenharmony_ci	}
203062306a36Sopenharmony_ci}
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_cistatic int snd_soc_bind_card(struct snd_soc_card *card)
203362306a36Sopenharmony_ci{
203462306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd;
203562306a36Sopenharmony_ci	struct snd_soc_component *component;
203662306a36Sopenharmony_ci	int ret;
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	mutex_lock(&client_mutex);
203962306a36Sopenharmony_ci	snd_soc_card_mutex_lock_root(card);
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_ci	snd_soc_dapm_init(&card->dapm, card, NULL);
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	/* check whether any platform is ignore machine FE and using topology */
204462306a36Sopenharmony_ci	soc_check_tplg_fes(card);
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	/* bind aux_devs too */
204762306a36Sopenharmony_ci	ret = soc_bind_aux_dev(card);
204862306a36Sopenharmony_ci	if (ret < 0)
204962306a36Sopenharmony_ci		goto probe_end;
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci	/* add predefined DAI links to the list */
205262306a36Sopenharmony_ci	card->num_rtd = 0;
205362306a36Sopenharmony_ci	ret = snd_soc_add_pcm_runtimes(card, card->dai_link, card->num_links);
205462306a36Sopenharmony_ci	if (ret < 0)
205562306a36Sopenharmony_ci		goto probe_end;
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	/* card bind complete so register a sound card */
205862306a36Sopenharmony_ci	ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
205962306a36Sopenharmony_ci			card->owner, 0, &card->snd_card);
206062306a36Sopenharmony_ci	if (ret < 0) {
206162306a36Sopenharmony_ci		dev_err(card->dev,
206262306a36Sopenharmony_ci			"ASoC: can't create sound card for card %s: %d\n",
206362306a36Sopenharmony_ci			card->name, ret);
206462306a36Sopenharmony_ci		goto probe_end;
206562306a36Sopenharmony_ci	}
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci	soc_init_card_debugfs(card);
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci	soc_resume_init(card);
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	ret = snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
207262306a36Sopenharmony_ci					card->num_dapm_widgets);
207362306a36Sopenharmony_ci	if (ret < 0)
207462306a36Sopenharmony_ci		goto probe_end;
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_ci	ret = snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets,
207762306a36Sopenharmony_ci					card->num_of_dapm_widgets);
207862306a36Sopenharmony_ci	if (ret < 0)
207962306a36Sopenharmony_ci		goto probe_end;
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci	/* initialise the sound card only once */
208262306a36Sopenharmony_ci	ret = snd_soc_card_probe(card);
208362306a36Sopenharmony_ci	if (ret < 0)
208462306a36Sopenharmony_ci		goto probe_end;
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	/* probe all components used by DAI links on this card */
208762306a36Sopenharmony_ci	ret = soc_probe_link_components(card);
208862306a36Sopenharmony_ci	if (ret < 0) {
208962306a36Sopenharmony_ci		if (ret != -EPROBE_DEFER) {
209062306a36Sopenharmony_ci			dev_err(card->dev,
209162306a36Sopenharmony_ci				"ASoC: failed to instantiate card %d\n", ret);
209262306a36Sopenharmony_ci		}
209362306a36Sopenharmony_ci		goto probe_end;
209462306a36Sopenharmony_ci	}
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci	/* probe auxiliary components */
209762306a36Sopenharmony_ci	ret = soc_probe_aux_devices(card);
209862306a36Sopenharmony_ci	if (ret < 0) {
209962306a36Sopenharmony_ci		dev_err(card->dev,
210062306a36Sopenharmony_ci			"ASoC: failed to probe aux component %d\n", ret);
210162306a36Sopenharmony_ci		goto probe_end;
210262306a36Sopenharmony_ci	}
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci	/* probe all DAI links on this card */
210562306a36Sopenharmony_ci	ret = soc_probe_link_dais(card);
210662306a36Sopenharmony_ci	if (ret < 0) {
210762306a36Sopenharmony_ci		dev_err(card->dev,
210862306a36Sopenharmony_ci			"ASoC: failed to instantiate card %d\n", ret);
210962306a36Sopenharmony_ci		goto probe_end;
211062306a36Sopenharmony_ci	}
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	for_each_card_rtds(card, rtd) {
211362306a36Sopenharmony_ci		ret = soc_init_pcm_runtime(card, rtd);
211462306a36Sopenharmony_ci		if (ret < 0)
211562306a36Sopenharmony_ci			goto probe_end;
211662306a36Sopenharmony_ci	}
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_ci	snd_soc_dapm_link_dai_widgets(card);
211962306a36Sopenharmony_ci	snd_soc_dapm_connect_dai_link_widgets(card);
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	ret = snd_soc_add_card_controls(card, card->controls,
212262306a36Sopenharmony_ci					card->num_controls);
212362306a36Sopenharmony_ci	if (ret < 0)
212462306a36Sopenharmony_ci		goto probe_end;
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	ret = snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
212762306a36Sopenharmony_ci				      card->num_dapm_routes);
212862306a36Sopenharmony_ci	if (ret < 0) {
212962306a36Sopenharmony_ci		if (card->disable_route_checks) {
213062306a36Sopenharmony_ci			dev_info(card->dev,
213162306a36Sopenharmony_ci				 "%s: disable_route_checks set, ignoring errors on add_routes\n",
213262306a36Sopenharmony_ci				 __func__);
213362306a36Sopenharmony_ci		} else {
213462306a36Sopenharmony_ci			dev_err(card->dev,
213562306a36Sopenharmony_ci				 "%s: snd_soc_dapm_add_routes failed: %d\n",
213662306a36Sopenharmony_ci				 __func__, ret);
213762306a36Sopenharmony_ci			goto probe_end;
213862306a36Sopenharmony_ci		}
213962306a36Sopenharmony_ci	}
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	ret = snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes,
214262306a36Sopenharmony_ci				      card->num_of_dapm_routes);
214362306a36Sopenharmony_ci	if (ret < 0)
214462306a36Sopenharmony_ci		goto probe_end;
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci	/* try to set some sane longname if DMI is available */
214762306a36Sopenharmony_ci	snd_soc_set_dmi_name(card, NULL);
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	soc_setup_card_name(card, card->snd_card->shortname,
215062306a36Sopenharmony_ci			    card->name, NULL);
215162306a36Sopenharmony_ci	soc_setup_card_name(card, card->snd_card->longname,
215262306a36Sopenharmony_ci			    card->long_name, card->name);
215362306a36Sopenharmony_ci	soc_setup_card_name(card, card->snd_card->driver,
215462306a36Sopenharmony_ci			    card->driver_name, card->name);
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	if (card->components) {
215762306a36Sopenharmony_ci		/* the current implementation of snd_component_add() accepts */
215862306a36Sopenharmony_ci		/* multiple components in the string separated by space, */
215962306a36Sopenharmony_ci		/* but the string collision (identical string) check might */
216062306a36Sopenharmony_ci		/* not work correctly */
216162306a36Sopenharmony_ci		ret = snd_component_add(card->snd_card, card->components);
216262306a36Sopenharmony_ci		if (ret < 0) {
216362306a36Sopenharmony_ci			dev_err(card->dev, "ASoC: %s snd_component_add() failed: %d\n",
216462306a36Sopenharmony_ci				card->name, ret);
216562306a36Sopenharmony_ci			goto probe_end;
216662306a36Sopenharmony_ci		}
216762306a36Sopenharmony_ci	}
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci	ret = snd_soc_card_late_probe(card);
217062306a36Sopenharmony_ci	if (ret < 0)
217162306a36Sopenharmony_ci		goto probe_end;
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	snd_soc_dapm_new_widgets(card);
217462306a36Sopenharmony_ci	snd_soc_card_fixup_controls(card);
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ci	ret = snd_card_register(card->snd_card);
217762306a36Sopenharmony_ci	if (ret < 0) {
217862306a36Sopenharmony_ci		dev_err(card->dev, "ASoC: failed to register soundcard %d\n",
217962306a36Sopenharmony_ci				ret);
218062306a36Sopenharmony_ci		goto probe_end;
218162306a36Sopenharmony_ci	}
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci	card->instantiated = 1;
218462306a36Sopenharmony_ci	dapm_mark_endpoints_dirty(card);
218562306a36Sopenharmony_ci	snd_soc_dapm_sync(&card->dapm);
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci	/* deactivate pins to sleep state */
218862306a36Sopenharmony_ci	for_each_card_components(card, component)
218962306a36Sopenharmony_ci		if (!snd_soc_component_active(component))
219062306a36Sopenharmony_ci			pinctrl_pm_select_sleep_state(component->dev);
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ciprobe_end:
219362306a36Sopenharmony_ci	if (ret < 0)
219462306a36Sopenharmony_ci		soc_cleanup_card_resources(card);
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	snd_soc_card_mutex_unlock(card);
219762306a36Sopenharmony_ci	mutex_unlock(&client_mutex);
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	return ret;
220062306a36Sopenharmony_ci}
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_ci/* probes a new socdev */
220362306a36Sopenharmony_cistatic int soc_probe(struct platform_device *pdev)
220462306a36Sopenharmony_ci{
220562306a36Sopenharmony_ci	struct snd_soc_card *card = platform_get_drvdata(pdev);
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci	/*
220862306a36Sopenharmony_ci	 * no card, so machine driver should be registering card
220962306a36Sopenharmony_ci	 * we should not be here in that case so ret error
221062306a36Sopenharmony_ci	 */
221162306a36Sopenharmony_ci	if (!card)
221262306a36Sopenharmony_ci		return -EINVAL;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	dev_warn(&pdev->dev,
221562306a36Sopenharmony_ci		 "ASoC: machine %s should use snd_soc_register_card()\n",
221662306a36Sopenharmony_ci		 card->name);
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci	/* Bodge while we unpick instantiation */
221962306a36Sopenharmony_ci	card->dev = &pdev->dev;
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_ci	return devm_snd_soc_register_card(&pdev->dev, card);
222262306a36Sopenharmony_ci}
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ciint snd_soc_poweroff(struct device *dev)
222562306a36Sopenharmony_ci{
222662306a36Sopenharmony_ci	struct snd_soc_card *card = dev_get_drvdata(dev);
222762306a36Sopenharmony_ci	struct snd_soc_component *component;
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_ci	if (!snd_soc_card_is_instantiated(card))
223062306a36Sopenharmony_ci		return 0;
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci	/*
223362306a36Sopenharmony_ci	 * Flush out pmdown_time work - we actually do want to run it
223462306a36Sopenharmony_ci	 * now, we're shutting down so no imminent restart.
223562306a36Sopenharmony_ci	 */
223662306a36Sopenharmony_ci	snd_soc_flush_all_delayed_work(card);
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci	snd_soc_dapm_shutdown(card);
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci	/* deactivate pins to sleep state */
224162306a36Sopenharmony_ci	for_each_card_components(card, component)
224262306a36Sopenharmony_ci		pinctrl_pm_select_sleep_state(component->dev);
224362306a36Sopenharmony_ci
224462306a36Sopenharmony_ci	return 0;
224562306a36Sopenharmony_ci}
224662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_poweroff);
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ciconst struct dev_pm_ops snd_soc_pm_ops = {
224962306a36Sopenharmony_ci	.suspend = snd_soc_suspend,
225062306a36Sopenharmony_ci	.resume = snd_soc_resume,
225162306a36Sopenharmony_ci	.freeze = snd_soc_suspend,
225262306a36Sopenharmony_ci	.thaw = snd_soc_resume,
225362306a36Sopenharmony_ci	.poweroff = snd_soc_poweroff,
225462306a36Sopenharmony_ci	.restore = snd_soc_resume,
225562306a36Sopenharmony_ci};
225662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_pm_ops);
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci/* ASoC platform driver */
225962306a36Sopenharmony_cistatic struct platform_driver soc_driver = {
226062306a36Sopenharmony_ci	.driver		= {
226162306a36Sopenharmony_ci		.name		= "soc-audio",
226262306a36Sopenharmony_ci		.pm		= &snd_soc_pm_ops,
226362306a36Sopenharmony_ci	},
226462306a36Sopenharmony_ci	.probe		= soc_probe,
226562306a36Sopenharmony_ci};
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci/**
226862306a36Sopenharmony_ci * snd_soc_cnew - create new control
226962306a36Sopenharmony_ci * @_template: control template
227062306a36Sopenharmony_ci * @data: control private data
227162306a36Sopenharmony_ci * @long_name: control long name
227262306a36Sopenharmony_ci * @prefix: control name prefix
227362306a36Sopenharmony_ci *
227462306a36Sopenharmony_ci * Create a new mixer control from a template control.
227562306a36Sopenharmony_ci *
227662306a36Sopenharmony_ci * Returns 0 for success, else error.
227762306a36Sopenharmony_ci */
227862306a36Sopenharmony_cistruct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
227962306a36Sopenharmony_ci				  void *data, const char *long_name,
228062306a36Sopenharmony_ci				  const char *prefix)
228162306a36Sopenharmony_ci{
228262306a36Sopenharmony_ci	struct snd_kcontrol_new template;
228362306a36Sopenharmony_ci	struct snd_kcontrol *kcontrol;
228462306a36Sopenharmony_ci	char *name = NULL;
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci	memcpy(&template, _template, sizeof(template));
228762306a36Sopenharmony_ci	template.index = 0;
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_ci	if (!long_name)
229062306a36Sopenharmony_ci		long_name = template.name;
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	if (prefix) {
229362306a36Sopenharmony_ci		name = kasprintf(GFP_KERNEL, "%s %s", prefix, long_name);
229462306a36Sopenharmony_ci		if (!name)
229562306a36Sopenharmony_ci			return NULL;
229662306a36Sopenharmony_ci
229762306a36Sopenharmony_ci		template.name = name;
229862306a36Sopenharmony_ci	} else {
229962306a36Sopenharmony_ci		template.name = long_name;
230062306a36Sopenharmony_ci	}
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci	kcontrol = snd_ctl_new1(&template, data);
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_ci	kfree(name);
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci	return kcontrol;
230762306a36Sopenharmony_ci}
230862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_cnew);
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_cistatic int snd_soc_add_controls(struct snd_card *card, struct device *dev,
231162306a36Sopenharmony_ci	const struct snd_kcontrol_new *controls, int num_controls,
231262306a36Sopenharmony_ci	const char *prefix, void *data)
231362306a36Sopenharmony_ci{
231462306a36Sopenharmony_ci	int i;
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	for (i = 0; i < num_controls; i++) {
231762306a36Sopenharmony_ci		const struct snd_kcontrol_new *control = &controls[i];
231862306a36Sopenharmony_ci		int err = snd_ctl_add(card, snd_soc_cnew(control, data,
231962306a36Sopenharmony_ci							 control->name, prefix));
232062306a36Sopenharmony_ci		if (err < 0) {
232162306a36Sopenharmony_ci			dev_err(dev, "ASoC: Failed to add %s: %d\n",
232262306a36Sopenharmony_ci				control->name, err);
232362306a36Sopenharmony_ci			return err;
232462306a36Sopenharmony_ci		}
232562306a36Sopenharmony_ci	}
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci	return 0;
232862306a36Sopenharmony_ci}
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci/**
233162306a36Sopenharmony_ci * snd_soc_add_component_controls - Add an array of controls to a component.
233262306a36Sopenharmony_ci *
233362306a36Sopenharmony_ci * @component: Component to add controls to
233462306a36Sopenharmony_ci * @controls: Array of controls to add
233562306a36Sopenharmony_ci * @num_controls: Number of elements in the array
233662306a36Sopenharmony_ci *
233762306a36Sopenharmony_ci * Return: 0 for success, else error.
233862306a36Sopenharmony_ci */
233962306a36Sopenharmony_ciint snd_soc_add_component_controls(struct snd_soc_component *component,
234062306a36Sopenharmony_ci	const struct snd_kcontrol_new *controls, unsigned int num_controls)
234162306a36Sopenharmony_ci{
234262306a36Sopenharmony_ci	struct snd_card *card = component->card->snd_card;
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci	return snd_soc_add_controls(card, component->dev, controls,
234562306a36Sopenharmony_ci			num_controls, component->name_prefix, component);
234662306a36Sopenharmony_ci}
234762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_add_component_controls);
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_ci/**
235062306a36Sopenharmony_ci * snd_soc_add_card_controls - add an array of controls to a SoC card.
235162306a36Sopenharmony_ci * Convenience function to add a list of controls.
235262306a36Sopenharmony_ci *
235362306a36Sopenharmony_ci * @soc_card: SoC card to add controls to
235462306a36Sopenharmony_ci * @controls: array of controls to add
235562306a36Sopenharmony_ci * @num_controls: number of elements in the array
235662306a36Sopenharmony_ci *
235762306a36Sopenharmony_ci * Return 0 for success, else error.
235862306a36Sopenharmony_ci */
235962306a36Sopenharmony_ciint snd_soc_add_card_controls(struct snd_soc_card *soc_card,
236062306a36Sopenharmony_ci	const struct snd_kcontrol_new *controls, int num_controls)
236162306a36Sopenharmony_ci{
236262306a36Sopenharmony_ci	struct snd_card *card = soc_card->snd_card;
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci	return snd_soc_add_controls(card, soc_card->dev, controls, num_controls,
236562306a36Sopenharmony_ci			NULL, soc_card);
236662306a36Sopenharmony_ci}
236762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_add_card_controls);
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci/**
237062306a36Sopenharmony_ci * snd_soc_add_dai_controls - add an array of controls to a DAI.
237162306a36Sopenharmony_ci * Convienience function to add a list of controls.
237262306a36Sopenharmony_ci *
237362306a36Sopenharmony_ci * @dai: DAI to add controls to
237462306a36Sopenharmony_ci * @controls: array of controls to add
237562306a36Sopenharmony_ci * @num_controls: number of elements in the array
237662306a36Sopenharmony_ci *
237762306a36Sopenharmony_ci * Return 0 for success, else error.
237862306a36Sopenharmony_ci */
237962306a36Sopenharmony_ciint snd_soc_add_dai_controls(struct snd_soc_dai *dai,
238062306a36Sopenharmony_ci	const struct snd_kcontrol_new *controls, int num_controls)
238162306a36Sopenharmony_ci{
238262306a36Sopenharmony_ci	struct snd_card *card = dai->component->card->snd_card;
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci	return snd_soc_add_controls(card, dai->dev, controls, num_controls,
238562306a36Sopenharmony_ci			NULL, dai);
238662306a36Sopenharmony_ci}
238762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_add_dai_controls);
238862306a36Sopenharmony_ci
238962306a36Sopenharmony_ci/**
239062306a36Sopenharmony_ci * snd_soc_register_card - Register a card with the ASoC core
239162306a36Sopenharmony_ci *
239262306a36Sopenharmony_ci * @card: Card to register
239362306a36Sopenharmony_ci *
239462306a36Sopenharmony_ci */
239562306a36Sopenharmony_ciint snd_soc_register_card(struct snd_soc_card *card)
239662306a36Sopenharmony_ci{
239762306a36Sopenharmony_ci	if (!card->name || !card->dev)
239862306a36Sopenharmony_ci		return -EINVAL;
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci	dev_set_drvdata(card->dev, card);
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci	INIT_LIST_HEAD(&card->widgets);
240362306a36Sopenharmony_ci	INIT_LIST_HEAD(&card->paths);
240462306a36Sopenharmony_ci	INIT_LIST_HEAD(&card->dapm_list);
240562306a36Sopenharmony_ci	INIT_LIST_HEAD(&card->aux_comp_list);
240662306a36Sopenharmony_ci	INIT_LIST_HEAD(&card->component_dev_list);
240762306a36Sopenharmony_ci	INIT_LIST_HEAD(&card->list);
240862306a36Sopenharmony_ci	INIT_LIST_HEAD(&card->rtd_list);
240962306a36Sopenharmony_ci	INIT_LIST_HEAD(&card->dapm_dirty);
241062306a36Sopenharmony_ci	INIT_LIST_HEAD(&card->dobj_list);
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci	card->instantiated = 0;
241362306a36Sopenharmony_ci	mutex_init(&card->mutex);
241462306a36Sopenharmony_ci	mutex_init(&card->dapm_mutex);
241562306a36Sopenharmony_ci	mutex_init(&card->pcm_mutex);
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ci	return snd_soc_bind_card(card);
241862306a36Sopenharmony_ci}
241962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_register_card);
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci/**
242262306a36Sopenharmony_ci * snd_soc_unregister_card - Unregister a card with the ASoC core
242362306a36Sopenharmony_ci *
242462306a36Sopenharmony_ci * @card: Card to unregister
242562306a36Sopenharmony_ci *
242662306a36Sopenharmony_ci */
242762306a36Sopenharmony_civoid snd_soc_unregister_card(struct snd_soc_card *card)
242862306a36Sopenharmony_ci{
242962306a36Sopenharmony_ci	mutex_lock(&client_mutex);
243062306a36Sopenharmony_ci	snd_soc_unbind_card(card, true);
243162306a36Sopenharmony_ci	mutex_unlock(&client_mutex);
243262306a36Sopenharmony_ci	dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name);
243362306a36Sopenharmony_ci}
243462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_unregister_card);
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci/*
243762306a36Sopenharmony_ci * Simplify DAI link configuration by removing ".-1" from device names
243862306a36Sopenharmony_ci * and sanitizing names.
243962306a36Sopenharmony_ci */
244062306a36Sopenharmony_cistatic char *fmt_single_name(struct device *dev, int *id)
244162306a36Sopenharmony_ci{
244262306a36Sopenharmony_ci	const char *devname = dev_name(dev);
244362306a36Sopenharmony_ci	char *found, *name;
244462306a36Sopenharmony_ci	unsigned int id1, id2;
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci	if (devname == NULL)
244762306a36Sopenharmony_ci		return NULL;
244862306a36Sopenharmony_ci
244962306a36Sopenharmony_ci	name = devm_kstrdup(dev, devname, GFP_KERNEL);
245062306a36Sopenharmony_ci	if (!name)
245162306a36Sopenharmony_ci		return NULL;
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci	/* are we a "%s.%d" name (platform and SPI components) */
245462306a36Sopenharmony_ci	found = strstr(name, dev->driver->name);
245562306a36Sopenharmony_ci	if (found) {
245662306a36Sopenharmony_ci		/* get ID */
245762306a36Sopenharmony_ci		if (sscanf(&found[strlen(dev->driver->name)], ".%d", id) == 1) {
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci			/* discard ID from name if ID == -1 */
246062306a36Sopenharmony_ci			if (*id == -1)
246162306a36Sopenharmony_ci				found[strlen(dev->driver->name)] = '\0';
246262306a36Sopenharmony_ci		}
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ci	/* I2C component devices are named "bus-addr" */
246562306a36Sopenharmony_ci	} else if (sscanf(name, "%x-%x", &id1, &id2) == 2) {
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci		/* create unique ID number from I2C addr and bus */
246862306a36Sopenharmony_ci		*id = ((id1 & 0xffff) << 16) + id2;
246962306a36Sopenharmony_ci
247062306a36Sopenharmony_ci		devm_kfree(dev, name);
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ci		/* sanitize component name for DAI link creation */
247362306a36Sopenharmony_ci		name = devm_kasprintf(dev, GFP_KERNEL, "%s.%s", dev->driver->name, devname);
247462306a36Sopenharmony_ci	} else {
247562306a36Sopenharmony_ci		*id = 0;
247662306a36Sopenharmony_ci	}
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_ci	return name;
247962306a36Sopenharmony_ci}
248062306a36Sopenharmony_ci
248162306a36Sopenharmony_ci/*
248262306a36Sopenharmony_ci * Simplify DAI link naming for single devices with multiple DAIs by removing
248362306a36Sopenharmony_ci * any ".-1" and using the DAI name (instead of device name).
248462306a36Sopenharmony_ci */
248562306a36Sopenharmony_cistatic inline char *fmt_multiple_name(struct device *dev,
248662306a36Sopenharmony_ci		struct snd_soc_dai_driver *dai_drv)
248762306a36Sopenharmony_ci{
248862306a36Sopenharmony_ci	if (dai_drv->name == NULL) {
248962306a36Sopenharmony_ci		dev_err(dev,
249062306a36Sopenharmony_ci			"ASoC: error - multiple DAI %s registered with no name\n",
249162306a36Sopenharmony_ci			dev_name(dev));
249262306a36Sopenharmony_ci		return NULL;
249362306a36Sopenharmony_ci	}
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_ci	return devm_kstrdup(dev, dai_drv->name, GFP_KERNEL);
249662306a36Sopenharmony_ci}
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_civoid snd_soc_unregister_dai(struct snd_soc_dai *dai)
249962306a36Sopenharmony_ci{
250062306a36Sopenharmony_ci	dev_dbg(dai->dev, "ASoC: Unregistered DAI '%s'\n", dai->name);
250162306a36Sopenharmony_ci	list_del(&dai->list);
250262306a36Sopenharmony_ci}
250362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci/**
250662306a36Sopenharmony_ci * snd_soc_register_dai - Register a DAI dynamically & create its widgets
250762306a36Sopenharmony_ci *
250862306a36Sopenharmony_ci * @component: The component the DAIs are registered for
250962306a36Sopenharmony_ci * @dai_drv: DAI driver to use for the DAI
251062306a36Sopenharmony_ci * @legacy_dai_naming: if %true, use legacy single-name format;
251162306a36Sopenharmony_ci * 	if %false, use multiple-name format;
251262306a36Sopenharmony_ci *
251362306a36Sopenharmony_ci * Topology can use this API to register DAIs when probing a component.
251462306a36Sopenharmony_ci * These DAIs's widgets will be freed in the card cleanup and the DAIs
251562306a36Sopenharmony_ci * will be freed in the component cleanup.
251662306a36Sopenharmony_ci */
251762306a36Sopenharmony_cistruct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component,
251862306a36Sopenharmony_ci					 struct snd_soc_dai_driver *dai_drv,
251962306a36Sopenharmony_ci					 bool legacy_dai_naming)
252062306a36Sopenharmony_ci{
252162306a36Sopenharmony_ci	struct device *dev = component->dev;
252262306a36Sopenharmony_ci	struct snd_soc_dai *dai;
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_ci	lockdep_assert_held(&client_mutex);
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_ci	dai = devm_kzalloc(dev, sizeof(*dai), GFP_KERNEL);
252762306a36Sopenharmony_ci	if (dai == NULL)
252862306a36Sopenharmony_ci		return NULL;
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci	/*
253162306a36Sopenharmony_ci	 * Back in the old days when we still had component-less DAIs,
253262306a36Sopenharmony_ci	 * instead of having a static name, component-less DAIs would
253362306a36Sopenharmony_ci	 * inherit the name of the parent device so it is possible to
253462306a36Sopenharmony_ci	 * register multiple instances of the DAI. We still need to keep
253562306a36Sopenharmony_ci	 * the same naming style even though those DAIs are not
253662306a36Sopenharmony_ci	 * component-less anymore.
253762306a36Sopenharmony_ci	 */
253862306a36Sopenharmony_ci	if (legacy_dai_naming &&
253962306a36Sopenharmony_ci	    (dai_drv->id == 0 || dai_drv->name == NULL)) {
254062306a36Sopenharmony_ci		dai->name = fmt_single_name(dev, &dai->id);
254162306a36Sopenharmony_ci	} else {
254262306a36Sopenharmony_ci		dai->name = fmt_multiple_name(dev, dai_drv);
254362306a36Sopenharmony_ci		if (dai_drv->id)
254462306a36Sopenharmony_ci			dai->id = dai_drv->id;
254562306a36Sopenharmony_ci		else
254662306a36Sopenharmony_ci			dai->id = component->num_dai;
254762306a36Sopenharmony_ci	}
254862306a36Sopenharmony_ci	if (!dai->name)
254962306a36Sopenharmony_ci		return NULL;
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ci	dai->component = component;
255262306a36Sopenharmony_ci	dai->dev = dev;
255362306a36Sopenharmony_ci	dai->driver = dai_drv;
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci	/* see for_each_component_dais */
255662306a36Sopenharmony_ci	list_add_tail(&dai->list, &component->dai_list);
255762306a36Sopenharmony_ci	component->num_dai++;
255862306a36Sopenharmony_ci
255962306a36Sopenharmony_ci	dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
256062306a36Sopenharmony_ci	return dai;
256162306a36Sopenharmony_ci}
256262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_register_dai);
256362306a36Sopenharmony_ci
256462306a36Sopenharmony_ci/**
256562306a36Sopenharmony_ci * snd_soc_unregister_dais - Unregister DAIs from the ASoC core
256662306a36Sopenharmony_ci *
256762306a36Sopenharmony_ci * @component: The component for which the DAIs should be unregistered
256862306a36Sopenharmony_ci */
256962306a36Sopenharmony_cistatic void snd_soc_unregister_dais(struct snd_soc_component *component)
257062306a36Sopenharmony_ci{
257162306a36Sopenharmony_ci	struct snd_soc_dai *dai, *_dai;
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	for_each_component_dais_safe(component, dai, _dai)
257462306a36Sopenharmony_ci		snd_soc_unregister_dai(dai);
257562306a36Sopenharmony_ci}
257662306a36Sopenharmony_ci
257762306a36Sopenharmony_ci/**
257862306a36Sopenharmony_ci * snd_soc_register_dais - Register a DAI with the ASoC core
257962306a36Sopenharmony_ci *
258062306a36Sopenharmony_ci * @component: The component the DAIs are registered for
258162306a36Sopenharmony_ci * @dai_drv: DAI driver to use for the DAIs
258262306a36Sopenharmony_ci * @count: Number of DAIs
258362306a36Sopenharmony_ci */
258462306a36Sopenharmony_cistatic int snd_soc_register_dais(struct snd_soc_component *component,
258562306a36Sopenharmony_ci				 struct snd_soc_dai_driver *dai_drv,
258662306a36Sopenharmony_ci				 size_t count)
258762306a36Sopenharmony_ci{
258862306a36Sopenharmony_ci	struct snd_soc_dai *dai;
258962306a36Sopenharmony_ci	unsigned int i;
259062306a36Sopenharmony_ci	int ret;
259162306a36Sopenharmony_ci
259262306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
259362306a36Sopenharmony_ci		dai = snd_soc_register_dai(component, dai_drv + i, count == 1 &&
259462306a36Sopenharmony_ci					   component->driver->legacy_dai_naming);
259562306a36Sopenharmony_ci		if (dai == NULL) {
259662306a36Sopenharmony_ci			ret = -ENOMEM;
259762306a36Sopenharmony_ci			goto err;
259862306a36Sopenharmony_ci		}
259962306a36Sopenharmony_ci	}
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_ci	return 0;
260262306a36Sopenharmony_ci
260362306a36Sopenharmony_cierr:
260462306a36Sopenharmony_ci	snd_soc_unregister_dais(component);
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_ci	return ret;
260762306a36Sopenharmony_ci}
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci#define ENDIANNESS_MAP(name) \
261062306a36Sopenharmony_ci	(SNDRV_PCM_FMTBIT_##name##LE | SNDRV_PCM_FMTBIT_##name##BE)
261162306a36Sopenharmony_cistatic u64 endianness_format_map[] = {
261262306a36Sopenharmony_ci	ENDIANNESS_MAP(S16_),
261362306a36Sopenharmony_ci	ENDIANNESS_MAP(U16_),
261462306a36Sopenharmony_ci	ENDIANNESS_MAP(S24_),
261562306a36Sopenharmony_ci	ENDIANNESS_MAP(U24_),
261662306a36Sopenharmony_ci	ENDIANNESS_MAP(S32_),
261762306a36Sopenharmony_ci	ENDIANNESS_MAP(U32_),
261862306a36Sopenharmony_ci	ENDIANNESS_MAP(S24_3),
261962306a36Sopenharmony_ci	ENDIANNESS_MAP(U24_3),
262062306a36Sopenharmony_ci	ENDIANNESS_MAP(S20_3),
262162306a36Sopenharmony_ci	ENDIANNESS_MAP(U20_3),
262262306a36Sopenharmony_ci	ENDIANNESS_MAP(S18_3),
262362306a36Sopenharmony_ci	ENDIANNESS_MAP(U18_3),
262462306a36Sopenharmony_ci	ENDIANNESS_MAP(FLOAT_),
262562306a36Sopenharmony_ci	ENDIANNESS_MAP(FLOAT64_),
262662306a36Sopenharmony_ci	ENDIANNESS_MAP(IEC958_SUBFRAME_),
262762306a36Sopenharmony_ci};
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci/*
263062306a36Sopenharmony_ci * Fix up the DAI formats for endianness: codecs don't actually see
263162306a36Sopenharmony_ci * the endianness of the data but we're using the CPU format
263262306a36Sopenharmony_ci * definitions which do need to include endianness so we ensure that
263362306a36Sopenharmony_ci * codec DAIs always have both big and little endian variants set.
263462306a36Sopenharmony_ci */
263562306a36Sopenharmony_cistatic void convert_endianness_formats(struct snd_soc_pcm_stream *stream)
263662306a36Sopenharmony_ci{
263762306a36Sopenharmony_ci	int i;
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(endianness_format_map); i++)
264062306a36Sopenharmony_ci		if (stream->formats & endianness_format_map[i])
264162306a36Sopenharmony_ci			stream->formats |= endianness_format_map[i];
264262306a36Sopenharmony_ci}
264362306a36Sopenharmony_ci
264462306a36Sopenharmony_cistatic void snd_soc_try_rebind_card(void)
264562306a36Sopenharmony_ci{
264662306a36Sopenharmony_ci	struct snd_soc_card *card, *c;
264762306a36Sopenharmony_ci
264862306a36Sopenharmony_ci	list_for_each_entry_safe(card, c, &unbind_card_list, list)
264962306a36Sopenharmony_ci		if (!snd_soc_bind_card(card))
265062306a36Sopenharmony_ci			list_del(&card->list);
265162306a36Sopenharmony_ci}
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_cistatic void snd_soc_del_component_unlocked(struct snd_soc_component *component)
265462306a36Sopenharmony_ci{
265562306a36Sopenharmony_ci	struct snd_soc_card *card = component->card;
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_ci	snd_soc_unregister_dais(component);
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_ci	if (card)
266062306a36Sopenharmony_ci		snd_soc_unbind_card(card, false);
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ci	list_del(&component->list);
266362306a36Sopenharmony_ci}
266462306a36Sopenharmony_ci
266562306a36Sopenharmony_ciint snd_soc_component_initialize(struct snd_soc_component *component,
266662306a36Sopenharmony_ci				 const struct snd_soc_component_driver *driver,
266762306a36Sopenharmony_ci				 struct device *dev)
266862306a36Sopenharmony_ci{
266962306a36Sopenharmony_ci	INIT_LIST_HEAD(&component->dai_list);
267062306a36Sopenharmony_ci	INIT_LIST_HEAD(&component->dobj_list);
267162306a36Sopenharmony_ci	INIT_LIST_HEAD(&component->card_list);
267262306a36Sopenharmony_ci	INIT_LIST_HEAD(&component->list);
267362306a36Sopenharmony_ci	mutex_init(&component->io_mutex);
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_ci	component->name = fmt_single_name(dev, &component->id);
267662306a36Sopenharmony_ci	if (!component->name) {
267762306a36Sopenharmony_ci		dev_err(dev, "ASoC: Failed to allocate name\n");
267862306a36Sopenharmony_ci		return -ENOMEM;
267962306a36Sopenharmony_ci	}
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_ci	component->dev		= dev;
268262306a36Sopenharmony_ci	component->driver	= driver;
268362306a36Sopenharmony_ci
268462306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
268562306a36Sopenharmony_ci	if (!component->debugfs_prefix)
268662306a36Sopenharmony_ci		component->debugfs_prefix = driver->debugfs_prefix;
268762306a36Sopenharmony_ci#endif
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_ci	return 0;
269062306a36Sopenharmony_ci}
269162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_component_initialize);
269262306a36Sopenharmony_ci
269362306a36Sopenharmony_ciint snd_soc_add_component(struct snd_soc_component *component,
269462306a36Sopenharmony_ci			  struct snd_soc_dai_driver *dai_drv,
269562306a36Sopenharmony_ci			  int num_dai)
269662306a36Sopenharmony_ci{
269762306a36Sopenharmony_ci	int ret;
269862306a36Sopenharmony_ci	int i;
269962306a36Sopenharmony_ci
270062306a36Sopenharmony_ci	mutex_lock(&client_mutex);
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_ci	if (component->driver->endianness) {
270362306a36Sopenharmony_ci		for (i = 0; i < num_dai; i++) {
270462306a36Sopenharmony_ci			convert_endianness_formats(&dai_drv[i].playback);
270562306a36Sopenharmony_ci			convert_endianness_formats(&dai_drv[i].capture);
270662306a36Sopenharmony_ci		}
270762306a36Sopenharmony_ci	}
270862306a36Sopenharmony_ci
270962306a36Sopenharmony_ci	ret = snd_soc_register_dais(component, dai_drv, num_dai);
271062306a36Sopenharmony_ci	if (ret < 0) {
271162306a36Sopenharmony_ci		dev_err(component->dev, "ASoC: Failed to register DAIs: %d\n",
271262306a36Sopenharmony_ci			ret);
271362306a36Sopenharmony_ci		goto err_cleanup;
271462306a36Sopenharmony_ci	}
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_ci	if (!component->driver->write && !component->driver->read) {
271762306a36Sopenharmony_ci		if (!component->regmap)
271862306a36Sopenharmony_ci			component->regmap = dev_get_regmap(component->dev,
271962306a36Sopenharmony_ci							   NULL);
272062306a36Sopenharmony_ci		if (component->regmap)
272162306a36Sopenharmony_ci			snd_soc_component_setup_regmap(component);
272262306a36Sopenharmony_ci	}
272362306a36Sopenharmony_ci
272462306a36Sopenharmony_ci	/* see for_each_component */
272562306a36Sopenharmony_ci	list_add(&component->list, &component_list);
272662306a36Sopenharmony_ci
272762306a36Sopenharmony_cierr_cleanup:
272862306a36Sopenharmony_ci	if (ret < 0)
272962306a36Sopenharmony_ci		snd_soc_del_component_unlocked(component);
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_ci	mutex_unlock(&client_mutex);
273262306a36Sopenharmony_ci
273362306a36Sopenharmony_ci	if (ret == 0)
273462306a36Sopenharmony_ci		snd_soc_try_rebind_card();
273562306a36Sopenharmony_ci
273662306a36Sopenharmony_ci	return ret;
273762306a36Sopenharmony_ci}
273862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_add_component);
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ciint snd_soc_register_component(struct device *dev,
274162306a36Sopenharmony_ci			const struct snd_soc_component_driver *component_driver,
274262306a36Sopenharmony_ci			struct snd_soc_dai_driver *dai_drv,
274362306a36Sopenharmony_ci			int num_dai)
274462306a36Sopenharmony_ci{
274562306a36Sopenharmony_ci	struct snd_soc_component *component;
274662306a36Sopenharmony_ci	int ret;
274762306a36Sopenharmony_ci
274862306a36Sopenharmony_ci	component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL);
274962306a36Sopenharmony_ci	if (!component)
275062306a36Sopenharmony_ci		return -ENOMEM;
275162306a36Sopenharmony_ci
275262306a36Sopenharmony_ci	ret = snd_soc_component_initialize(component, component_driver, dev);
275362306a36Sopenharmony_ci	if (ret < 0)
275462306a36Sopenharmony_ci		return ret;
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_ci	return snd_soc_add_component(component, dai_drv, num_dai);
275762306a36Sopenharmony_ci}
275862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_register_component);
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_ci/**
276162306a36Sopenharmony_ci * snd_soc_unregister_component_by_driver - Unregister component using a given driver
276262306a36Sopenharmony_ci * from the ASoC core
276362306a36Sopenharmony_ci *
276462306a36Sopenharmony_ci * @dev: The device to unregister
276562306a36Sopenharmony_ci * @component_driver: The component driver to unregister
276662306a36Sopenharmony_ci */
276762306a36Sopenharmony_civoid snd_soc_unregister_component_by_driver(struct device *dev,
276862306a36Sopenharmony_ci					    const struct snd_soc_component_driver *component_driver)
276962306a36Sopenharmony_ci{
277062306a36Sopenharmony_ci	struct snd_soc_component *component;
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_ci	if (!component_driver)
277362306a36Sopenharmony_ci		return;
277462306a36Sopenharmony_ci
277562306a36Sopenharmony_ci	mutex_lock(&client_mutex);
277662306a36Sopenharmony_ci	component = snd_soc_lookup_component_nolocked(dev, component_driver->name);
277762306a36Sopenharmony_ci	if (!component)
277862306a36Sopenharmony_ci		goto out;
277962306a36Sopenharmony_ci
278062306a36Sopenharmony_ci	snd_soc_del_component_unlocked(component);
278162306a36Sopenharmony_ci
278262306a36Sopenharmony_ciout:
278362306a36Sopenharmony_ci	mutex_unlock(&client_mutex);
278462306a36Sopenharmony_ci}
278562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_unregister_component_by_driver);
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci/**
278862306a36Sopenharmony_ci * snd_soc_unregister_component - Unregister all related component
278962306a36Sopenharmony_ci * from the ASoC core
279062306a36Sopenharmony_ci *
279162306a36Sopenharmony_ci * @dev: The device to unregister
279262306a36Sopenharmony_ci */
279362306a36Sopenharmony_civoid snd_soc_unregister_component(struct device *dev)
279462306a36Sopenharmony_ci{
279562306a36Sopenharmony_ci	mutex_lock(&client_mutex);
279662306a36Sopenharmony_ci	while (1) {
279762306a36Sopenharmony_ci		struct snd_soc_component *component = snd_soc_lookup_component_nolocked(dev, NULL);
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci		if (!component)
280062306a36Sopenharmony_ci			break;
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci		snd_soc_del_component_unlocked(component);
280362306a36Sopenharmony_ci	}
280462306a36Sopenharmony_ci	mutex_unlock(&client_mutex);
280562306a36Sopenharmony_ci}
280662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_unregister_component);
280762306a36Sopenharmony_ci
280862306a36Sopenharmony_ci/* Retrieve a card's name from device tree */
280962306a36Sopenharmony_ciint snd_soc_of_parse_card_name(struct snd_soc_card *card,
281062306a36Sopenharmony_ci			       const char *propname)
281162306a36Sopenharmony_ci{
281262306a36Sopenharmony_ci	struct device_node *np;
281362306a36Sopenharmony_ci	int ret;
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_ci	if (!card->dev) {
281662306a36Sopenharmony_ci		pr_err("card->dev is not set before calling %s\n", __func__);
281762306a36Sopenharmony_ci		return -EINVAL;
281862306a36Sopenharmony_ci	}
281962306a36Sopenharmony_ci
282062306a36Sopenharmony_ci	np = card->dev->of_node;
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_ci	ret = of_property_read_string_index(np, propname, 0, &card->name);
282362306a36Sopenharmony_ci	/*
282462306a36Sopenharmony_ci	 * EINVAL means the property does not exist. This is fine providing
282562306a36Sopenharmony_ci	 * card->name was previously set, which is checked later in
282662306a36Sopenharmony_ci	 * snd_soc_register_card.
282762306a36Sopenharmony_ci	 */
282862306a36Sopenharmony_ci	if (ret < 0 && ret != -EINVAL) {
282962306a36Sopenharmony_ci		dev_err(card->dev,
283062306a36Sopenharmony_ci			"ASoC: Property '%s' could not be read: %d\n",
283162306a36Sopenharmony_ci			propname, ret);
283262306a36Sopenharmony_ci		return ret;
283362306a36Sopenharmony_ci	}
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_ci	return 0;
283662306a36Sopenharmony_ci}
283762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name);
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget simple_widgets[] = {
284062306a36Sopenharmony_ci	SND_SOC_DAPM_MIC("Microphone", NULL),
284162306a36Sopenharmony_ci	SND_SOC_DAPM_LINE("Line", NULL),
284262306a36Sopenharmony_ci	SND_SOC_DAPM_HP("Headphone", NULL),
284362306a36Sopenharmony_ci	SND_SOC_DAPM_SPK("Speaker", NULL),
284462306a36Sopenharmony_ci};
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ciint snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
284762306a36Sopenharmony_ci					  const char *propname)
284862306a36Sopenharmony_ci{
284962306a36Sopenharmony_ci	struct device_node *np = card->dev->of_node;
285062306a36Sopenharmony_ci	struct snd_soc_dapm_widget *widgets;
285162306a36Sopenharmony_ci	const char *template, *wname;
285262306a36Sopenharmony_ci	int i, j, num_widgets;
285362306a36Sopenharmony_ci
285462306a36Sopenharmony_ci	num_widgets = of_property_count_strings(np, propname);
285562306a36Sopenharmony_ci	if (num_widgets < 0) {
285662306a36Sopenharmony_ci		dev_err(card->dev,
285762306a36Sopenharmony_ci			"ASoC: Property '%s' does not exist\n",	propname);
285862306a36Sopenharmony_ci		return -EINVAL;
285962306a36Sopenharmony_ci	}
286062306a36Sopenharmony_ci	if (!num_widgets) {
286162306a36Sopenharmony_ci		dev_err(card->dev, "ASoC: Property '%s's length is zero\n",
286262306a36Sopenharmony_ci			propname);
286362306a36Sopenharmony_ci		return -EINVAL;
286462306a36Sopenharmony_ci	}
286562306a36Sopenharmony_ci	if (num_widgets & 1) {
286662306a36Sopenharmony_ci		dev_err(card->dev,
286762306a36Sopenharmony_ci			"ASoC: Property '%s' length is not even\n", propname);
286862306a36Sopenharmony_ci		return -EINVAL;
286962306a36Sopenharmony_ci	}
287062306a36Sopenharmony_ci
287162306a36Sopenharmony_ci	num_widgets /= 2;
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci	widgets = devm_kcalloc(card->dev, num_widgets, sizeof(*widgets),
287462306a36Sopenharmony_ci			       GFP_KERNEL);
287562306a36Sopenharmony_ci	if (!widgets) {
287662306a36Sopenharmony_ci		dev_err(card->dev,
287762306a36Sopenharmony_ci			"ASoC: Could not allocate memory for widgets\n");
287862306a36Sopenharmony_ci		return -ENOMEM;
287962306a36Sopenharmony_ci	}
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_ci	for (i = 0; i < num_widgets; i++) {
288262306a36Sopenharmony_ci		int ret = of_property_read_string_index(np, propname,
288362306a36Sopenharmony_ci							2 * i, &template);
288462306a36Sopenharmony_ci		if (ret) {
288562306a36Sopenharmony_ci			dev_err(card->dev,
288662306a36Sopenharmony_ci				"ASoC: Property '%s' index %d read error:%d\n",
288762306a36Sopenharmony_ci				propname, 2 * i, ret);
288862306a36Sopenharmony_ci			return -EINVAL;
288962306a36Sopenharmony_ci		}
289062306a36Sopenharmony_ci
289162306a36Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(simple_widgets); j++) {
289262306a36Sopenharmony_ci			if (!strncmp(template, simple_widgets[j].name,
289362306a36Sopenharmony_ci				     strlen(simple_widgets[j].name))) {
289462306a36Sopenharmony_ci				widgets[i] = simple_widgets[j];
289562306a36Sopenharmony_ci				break;
289662306a36Sopenharmony_ci			}
289762306a36Sopenharmony_ci		}
289862306a36Sopenharmony_ci
289962306a36Sopenharmony_ci		if (j >= ARRAY_SIZE(simple_widgets)) {
290062306a36Sopenharmony_ci			dev_err(card->dev,
290162306a36Sopenharmony_ci				"ASoC: DAPM widget '%s' is not supported\n",
290262306a36Sopenharmony_ci				template);
290362306a36Sopenharmony_ci			return -EINVAL;
290462306a36Sopenharmony_ci		}
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci		ret = of_property_read_string_index(np, propname,
290762306a36Sopenharmony_ci						    (2 * i) + 1,
290862306a36Sopenharmony_ci						    &wname);
290962306a36Sopenharmony_ci		if (ret) {
291062306a36Sopenharmony_ci			dev_err(card->dev,
291162306a36Sopenharmony_ci				"ASoC: Property '%s' index %d read error:%d\n",
291262306a36Sopenharmony_ci				propname, (2 * i) + 1, ret);
291362306a36Sopenharmony_ci			return -EINVAL;
291462306a36Sopenharmony_ci		}
291562306a36Sopenharmony_ci
291662306a36Sopenharmony_ci		widgets[i].name = wname;
291762306a36Sopenharmony_ci	}
291862306a36Sopenharmony_ci
291962306a36Sopenharmony_ci	card->of_dapm_widgets = widgets;
292062306a36Sopenharmony_ci	card->num_of_dapm_widgets = num_widgets;
292162306a36Sopenharmony_ci
292262306a36Sopenharmony_ci	return 0;
292362306a36Sopenharmony_ci}
292462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets);
292562306a36Sopenharmony_ci
292662306a36Sopenharmony_ciint snd_soc_of_parse_pin_switches(struct snd_soc_card *card, const char *prop)
292762306a36Sopenharmony_ci{
292862306a36Sopenharmony_ci	const unsigned int nb_controls_max = 16;
292962306a36Sopenharmony_ci	const char **strings, *control_name;
293062306a36Sopenharmony_ci	struct snd_kcontrol_new *controls;
293162306a36Sopenharmony_ci	struct device *dev = card->dev;
293262306a36Sopenharmony_ci	unsigned int i, nb_controls;
293362306a36Sopenharmony_ci	int ret;
293462306a36Sopenharmony_ci
293562306a36Sopenharmony_ci	if (!of_property_read_bool(dev->of_node, prop))
293662306a36Sopenharmony_ci		return 0;
293762306a36Sopenharmony_ci
293862306a36Sopenharmony_ci	strings = devm_kcalloc(dev, nb_controls_max,
293962306a36Sopenharmony_ci			       sizeof(*strings), GFP_KERNEL);
294062306a36Sopenharmony_ci	if (!strings)
294162306a36Sopenharmony_ci		return -ENOMEM;
294262306a36Sopenharmony_ci
294362306a36Sopenharmony_ci	ret = of_property_read_string_array(dev->of_node, prop,
294462306a36Sopenharmony_ci					    strings, nb_controls_max);
294562306a36Sopenharmony_ci	if (ret < 0)
294662306a36Sopenharmony_ci		return ret;
294762306a36Sopenharmony_ci
294862306a36Sopenharmony_ci	nb_controls = (unsigned int)ret;
294962306a36Sopenharmony_ci
295062306a36Sopenharmony_ci	controls = devm_kcalloc(dev, nb_controls,
295162306a36Sopenharmony_ci				sizeof(*controls), GFP_KERNEL);
295262306a36Sopenharmony_ci	if (!controls)
295362306a36Sopenharmony_ci		return -ENOMEM;
295462306a36Sopenharmony_ci
295562306a36Sopenharmony_ci	for (i = 0; i < nb_controls; i++) {
295662306a36Sopenharmony_ci		control_name = devm_kasprintf(dev, GFP_KERNEL,
295762306a36Sopenharmony_ci					      "%s Switch", strings[i]);
295862306a36Sopenharmony_ci		if (!control_name)
295962306a36Sopenharmony_ci			return -ENOMEM;
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci		controls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
296262306a36Sopenharmony_ci		controls[i].name = control_name;
296362306a36Sopenharmony_ci		controls[i].info = snd_soc_dapm_info_pin_switch;
296462306a36Sopenharmony_ci		controls[i].get = snd_soc_dapm_get_pin_switch;
296562306a36Sopenharmony_ci		controls[i].put = snd_soc_dapm_put_pin_switch;
296662306a36Sopenharmony_ci		controls[i].private_value = (unsigned long)strings[i];
296762306a36Sopenharmony_ci	}
296862306a36Sopenharmony_ci
296962306a36Sopenharmony_ci	card->controls = controls;
297062306a36Sopenharmony_ci	card->num_controls = nb_controls;
297162306a36Sopenharmony_ci
297262306a36Sopenharmony_ci	return 0;
297362306a36Sopenharmony_ci}
297462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_of_parse_pin_switches);
297562306a36Sopenharmony_ci
297662306a36Sopenharmony_ciint snd_soc_of_get_slot_mask(struct device_node *np,
297762306a36Sopenharmony_ci			     const char *prop_name,
297862306a36Sopenharmony_ci			     unsigned int *mask)
297962306a36Sopenharmony_ci{
298062306a36Sopenharmony_ci	u32 val;
298162306a36Sopenharmony_ci	const __be32 *of_slot_mask = of_get_property(np, prop_name, &val);
298262306a36Sopenharmony_ci	int i;
298362306a36Sopenharmony_ci
298462306a36Sopenharmony_ci	if (!of_slot_mask)
298562306a36Sopenharmony_ci		return 0;
298662306a36Sopenharmony_ci	val /= sizeof(u32);
298762306a36Sopenharmony_ci	for (i = 0; i < val; i++)
298862306a36Sopenharmony_ci		if (be32_to_cpup(&of_slot_mask[i]))
298962306a36Sopenharmony_ci			*mask |= (1 << i);
299062306a36Sopenharmony_ci
299162306a36Sopenharmony_ci	return val;
299262306a36Sopenharmony_ci}
299362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_of_get_slot_mask);
299462306a36Sopenharmony_ci
299562306a36Sopenharmony_ciint snd_soc_of_parse_tdm_slot(struct device_node *np,
299662306a36Sopenharmony_ci			      unsigned int *tx_mask,
299762306a36Sopenharmony_ci			      unsigned int *rx_mask,
299862306a36Sopenharmony_ci			      unsigned int *slots,
299962306a36Sopenharmony_ci			      unsigned int *slot_width)
300062306a36Sopenharmony_ci{
300162306a36Sopenharmony_ci	u32 val;
300262306a36Sopenharmony_ci	int ret;
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci	if (tx_mask)
300562306a36Sopenharmony_ci		snd_soc_of_get_slot_mask(np, "dai-tdm-slot-tx-mask", tx_mask);
300662306a36Sopenharmony_ci	if (rx_mask)
300762306a36Sopenharmony_ci		snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", rx_mask);
300862306a36Sopenharmony_ci
300962306a36Sopenharmony_ci	if (of_property_read_bool(np, "dai-tdm-slot-num")) {
301062306a36Sopenharmony_ci		ret = of_property_read_u32(np, "dai-tdm-slot-num", &val);
301162306a36Sopenharmony_ci		if (ret)
301262306a36Sopenharmony_ci			return ret;
301362306a36Sopenharmony_ci
301462306a36Sopenharmony_ci		if (slots)
301562306a36Sopenharmony_ci			*slots = val;
301662306a36Sopenharmony_ci	}
301762306a36Sopenharmony_ci
301862306a36Sopenharmony_ci	if (of_property_read_bool(np, "dai-tdm-slot-width")) {
301962306a36Sopenharmony_ci		ret = of_property_read_u32(np, "dai-tdm-slot-width", &val);
302062306a36Sopenharmony_ci		if (ret)
302162306a36Sopenharmony_ci			return ret;
302262306a36Sopenharmony_ci
302362306a36Sopenharmony_ci		if (slot_width)
302462306a36Sopenharmony_ci			*slot_width = val;
302562306a36Sopenharmony_ci	}
302662306a36Sopenharmony_ci
302762306a36Sopenharmony_ci	return 0;
302862306a36Sopenharmony_ci}
302962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot);
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_civoid snd_soc_dlc_use_cpu_as_platform(struct snd_soc_dai_link_component *platforms,
303262306a36Sopenharmony_ci				     struct snd_soc_dai_link_component *cpus)
303362306a36Sopenharmony_ci{
303462306a36Sopenharmony_ci	platforms->of_node	= cpus->of_node;
303562306a36Sopenharmony_ci	platforms->dai_args	= cpus->dai_args;
303662306a36Sopenharmony_ci}
303762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dlc_use_cpu_as_platform);
303862306a36Sopenharmony_ci
303962306a36Sopenharmony_civoid snd_soc_of_parse_node_prefix(struct device_node *np,
304062306a36Sopenharmony_ci				  struct snd_soc_codec_conf *codec_conf,
304162306a36Sopenharmony_ci				  struct device_node *of_node,
304262306a36Sopenharmony_ci				  const char *propname)
304362306a36Sopenharmony_ci{
304462306a36Sopenharmony_ci	const char *str;
304562306a36Sopenharmony_ci	int ret;
304662306a36Sopenharmony_ci
304762306a36Sopenharmony_ci	ret = of_property_read_string(np, propname, &str);
304862306a36Sopenharmony_ci	if (ret < 0) {
304962306a36Sopenharmony_ci		/* no prefix is not error */
305062306a36Sopenharmony_ci		return;
305162306a36Sopenharmony_ci	}
305262306a36Sopenharmony_ci
305362306a36Sopenharmony_ci	codec_conf->dlc.of_node	= of_node;
305462306a36Sopenharmony_ci	codec_conf->name_prefix	= str;
305562306a36Sopenharmony_ci}
305662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_of_parse_node_prefix);
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_ciint snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
305962306a36Sopenharmony_ci				   const char *propname)
306062306a36Sopenharmony_ci{
306162306a36Sopenharmony_ci	struct device_node *np = card->dev->of_node;
306262306a36Sopenharmony_ci	int num_routes;
306362306a36Sopenharmony_ci	struct snd_soc_dapm_route *routes;
306462306a36Sopenharmony_ci	int i;
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_ci	num_routes = of_property_count_strings(np, propname);
306762306a36Sopenharmony_ci	if (num_routes < 0 || num_routes & 1) {
306862306a36Sopenharmony_ci		dev_err(card->dev,
306962306a36Sopenharmony_ci			"ASoC: Property '%s' does not exist or its length is not even\n",
307062306a36Sopenharmony_ci			propname);
307162306a36Sopenharmony_ci		return -EINVAL;
307262306a36Sopenharmony_ci	}
307362306a36Sopenharmony_ci	num_routes /= 2;
307462306a36Sopenharmony_ci
307562306a36Sopenharmony_ci	routes = devm_kcalloc(card->dev, num_routes, sizeof(*routes),
307662306a36Sopenharmony_ci			      GFP_KERNEL);
307762306a36Sopenharmony_ci	if (!routes) {
307862306a36Sopenharmony_ci		dev_err(card->dev,
307962306a36Sopenharmony_ci			"ASoC: Could not allocate DAPM route table\n");
308062306a36Sopenharmony_ci		return -ENOMEM;
308162306a36Sopenharmony_ci	}
308262306a36Sopenharmony_ci
308362306a36Sopenharmony_ci	for (i = 0; i < num_routes; i++) {
308462306a36Sopenharmony_ci		int ret = of_property_read_string_index(np, propname,
308562306a36Sopenharmony_ci							2 * i, &routes[i].sink);
308662306a36Sopenharmony_ci		if (ret) {
308762306a36Sopenharmony_ci			dev_err(card->dev,
308862306a36Sopenharmony_ci				"ASoC: Property '%s' index %d could not be read: %d\n",
308962306a36Sopenharmony_ci				propname, 2 * i, ret);
309062306a36Sopenharmony_ci			return -EINVAL;
309162306a36Sopenharmony_ci		}
309262306a36Sopenharmony_ci		ret = of_property_read_string_index(np, propname,
309362306a36Sopenharmony_ci			(2 * i) + 1, &routes[i].source);
309462306a36Sopenharmony_ci		if (ret) {
309562306a36Sopenharmony_ci			dev_err(card->dev,
309662306a36Sopenharmony_ci				"ASoC: Property '%s' index %d could not be read: %d\n",
309762306a36Sopenharmony_ci				propname, (2 * i) + 1, ret);
309862306a36Sopenharmony_ci			return -EINVAL;
309962306a36Sopenharmony_ci		}
310062306a36Sopenharmony_ci	}
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ci	card->num_of_dapm_routes = num_routes;
310362306a36Sopenharmony_ci	card->of_dapm_routes = routes;
310462306a36Sopenharmony_ci
310562306a36Sopenharmony_ci	return 0;
310662306a36Sopenharmony_ci}
310762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing);
310862306a36Sopenharmony_ci
310962306a36Sopenharmony_ciint snd_soc_of_parse_aux_devs(struct snd_soc_card *card, const char *propname)
311062306a36Sopenharmony_ci{
311162306a36Sopenharmony_ci	struct device_node *node = card->dev->of_node;
311262306a36Sopenharmony_ci	struct snd_soc_aux_dev *aux;
311362306a36Sopenharmony_ci	int num, i;
311462306a36Sopenharmony_ci
311562306a36Sopenharmony_ci	num = of_count_phandle_with_args(node, propname, NULL);
311662306a36Sopenharmony_ci	if (num == -ENOENT) {
311762306a36Sopenharmony_ci		return 0;
311862306a36Sopenharmony_ci	} else if (num < 0) {
311962306a36Sopenharmony_ci		dev_err(card->dev, "ASOC: Property '%s' could not be read: %d\n",
312062306a36Sopenharmony_ci			propname, num);
312162306a36Sopenharmony_ci		return num;
312262306a36Sopenharmony_ci	}
312362306a36Sopenharmony_ci
312462306a36Sopenharmony_ci	aux = devm_kcalloc(card->dev, num, sizeof(*aux), GFP_KERNEL);
312562306a36Sopenharmony_ci	if (!aux)
312662306a36Sopenharmony_ci		return -ENOMEM;
312762306a36Sopenharmony_ci	card->aux_dev = aux;
312862306a36Sopenharmony_ci	card->num_aux_devs = num;
312962306a36Sopenharmony_ci
313062306a36Sopenharmony_ci	for_each_card_pre_auxs(card, i, aux) {
313162306a36Sopenharmony_ci		aux->dlc.of_node = of_parse_phandle(node, propname, i);
313262306a36Sopenharmony_ci		if (!aux->dlc.of_node)
313362306a36Sopenharmony_ci			return -EINVAL;
313462306a36Sopenharmony_ci	}
313562306a36Sopenharmony_ci
313662306a36Sopenharmony_ci	return 0;
313762306a36Sopenharmony_ci}
313862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_of_parse_aux_devs);
313962306a36Sopenharmony_ci
314062306a36Sopenharmony_ciunsigned int snd_soc_daifmt_clock_provider_flipped(unsigned int dai_fmt)
314162306a36Sopenharmony_ci{
314262306a36Sopenharmony_ci	unsigned int inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
314362306a36Sopenharmony_ci
314462306a36Sopenharmony_ci	switch (dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
314562306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBP_CFP:
314662306a36Sopenharmony_ci		inv_dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
314762306a36Sopenharmony_ci		break;
314862306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBP_CFC:
314962306a36Sopenharmony_ci		inv_dai_fmt |= SND_SOC_DAIFMT_CBC_CFP;
315062306a36Sopenharmony_ci		break;
315162306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBC_CFP:
315262306a36Sopenharmony_ci		inv_dai_fmt |= SND_SOC_DAIFMT_CBP_CFC;
315362306a36Sopenharmony_ci		break;
315462306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBC_CFC:
315562306a36Sopenharmony_ci		inv_dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
315662306a36Sopenharmony_ci		break;
315762306a36Sopenharmony_ci	}
315862306a36Sopenharmony_ci
315962306a36Sopenharmony_ci	return inv_dai_fmt;
316062306a36Sopenharmony_ci}
316162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_daifmt_clock_provider_flipped);
316262306a36Sopenharmony_ci
316362306a36Sopenharmony_ciunsigned int snd_soc_daifmt_clock_provider_from_bitmap(unsigned int bit_frame)
316462306a36Sopenharmony_ci{
316562306a36Sopenharmony_ci	/*
316662306a36Sopenharmony_ci	 * bit_frame is return value from
316762306a36Sopenharmony_ci	 *	snd_soc_daifmt_parse_clock_provider_raw()
316862306a36Sopenharmony_ci	 */
316962306a36Sopenharmony_ci
317062306a36Sopenharmony_ci	/* Codec base */
317162306a36Sopenharmony_ci	switch (bit_frame) {
317262306a36Sopenharmony_ci	case 0x11:
317362306a36Sopenharmony_ci		return SND_SOC_DAIFMT_CBP_CFP;
317462306a36Sopenharmony_ci	case 0x10:
317562306a36Sopenharmony_ci		return SND_SOC_DAIFMT_CBP_CFC;
317662306a36Sopenharmony_ci	case 0x01:
317762306a36Sopenharmony_ci		return SND_SOC_DAIFMT_CBC_CFP;
317862306a36Sopenharmony_ci	default:
317962306a36Sopenharmony_ci		return SND_SOC_DAIFMT_CBC_CFC;
318062306a36Sopenharmony_ci	}
318162306a36Sopenharmony_ci
318262306a36Sopenharmony_ci	return 0;
318362306a36Sopenharmony_ci}
318462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_daifmt_clock_provider_from_bitmap);
318562306a36Sopenharmony_ci
318662306a36Sopenharmony_ciunsigned int snd_soc_daifmt_parse_format(struct device_node *np,
318762306a36Sopenharmony_ci					 const char *prefix)
318862306a36Sopenharmony_ci{
318962306a36Sopenharmony_ci	int ret;
319062306a36Sopenharmony_ci	char prop[128];
319162306a36Sopenharmony_ci	unsigned int format = 0;
319262306a36Sopenharmony_ci	int bit, frame;
319362306a36Sopenharmony_ci	const char *str;
319462306a36Sopenharmony_ci	struct {
319562306a36Sopenharmony_ci		char *name;
319662306a36Sopenharmony_ci		unsigned int val;
319762306a36Sopenharmony_ci	} of_fmt_table[] = {
319862306a36Sopenharmony_ci		{ "i2s",	SND_SOC_DAIFMT_I2S },
319962306a36Sopenharmony_ci		{ "right_j",	SND_SOC_DAIFMT_RIGHT_J },
320062306a36Sopenharmony_ci		{ "left_j",	SND_SOC_DAIFMT_LEFT_J },
320162306a36Sopenharmony_ci		{ "dsp_a",	SND_SOC_DAIFMT_DSP_A },
320262306a36Sopenharmony_ci		{ "dsp_b",	SND_SOC_DAIFMT_DSP_B },
320362306a36Sopenharmony_ci		{ "ac97",	SND_SOC_DAIFMT_AC97 },
320462306a36Sopenharmony_ci		{ "pdm",	SND_SOC_DAIFMT_PDM},
320562306a36Sopenharmony_ci		{ "msb",	SND_SOC_DAIFMT_MSB },
320662306a36Sopenharmony_ci		{ "lsb",	SND_SOC_DAIFMT_LSB },
320762306a36Sopenharmony_ci	};
320862306a36Sopenharmony_ci
320962306a36Sopenharmony_ci	if (!prefix)
321062306a36Sopenharmony_ci		prefix = "";
321162306a36Sopenharmony_ci
321262306a36Sopenharmony_ci	/*
321362306a36Sopenharmony_ci	 * check "dai-format = xxx"
321462306a36Sopenharmony_ci	 * or    "[prefix]format = xxx"
321562306a36Sopenharmony_ci	 * SND_SOC_DAIFMT_FORMAT_MASK area
321662306a36Sopenharmony_ci	 */
321762306a36Sopenharmony_ci	ret = of_property_read_string(np, "dai-format", &str);
321862306a36Sopenharmony_ci	if (ret < 0) {
321962306a36Sopenharmony_ci		snprintf(prop, sizeof(prop), "%sformat", prefix);
322062306a36Sopenharmony_ci		ret = of_property_read_string(np, prop, &str);
322162306a36Sopenharmony_ci	}
322262306a36Sopenharmony_ci	if (ret == 0) {
322362306a36Sopenharmony_ci		int i;
322462306a36Sopenharmony_ci
322562306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(of_fmt_table); i++) {
322662306a36Sopenharmony_ci			if (strcmp(str, of_fmt_table[i].name) == 0) {
322762306a36Sopenharmony_ci				format |= of_fmt_table[i].val;
322862306a36Sopenharmony_ci				break;
322962306a36Sopenharmony_ci			}
323062306a36Sopenharmony_ci		}
323162306a36Sopenharmony_ci	}
323262306a36Sopenharmony_ci
323362306a36Sopenharmony_ci	/*
323462306a36Sopenharmony_ci	 * check "[prefix]continuous-clock"
323562306a36Sopenharmony_ci	 * SND_SOC_DAIFMT_CLOCK_MASK area
323662306a36Sopenharmony_ci	 */
323762306a36Sopenharmony_ci	snprintf(prop, sizeof(prop), "%scontinuous-clock", prefix);
323862306a36Sopenharmony_ci	if (of_property_read_bool(np, prop))
323962306a36Sopenharmony_ci		format |= SND_SOC_DAIFMT_CONT;
324062306a36Sopenharmony_ci	else
324162306a36Sopenharmony_ci		format |= SND_SOC_DAIFMT_GATED;
324262306a36Sopenharmony_ci
324362306a36Sopenharmony_ci	/*
324462306a36Sopenharmony_ci	 * check "[prefix]bitclock-inversion"
324562306a36Sopenharmony_ci	 * check "[prefix]frame-inversion"
324662306a36Sopenharmony_ci	 * SND_SOC_DAIFMT_INV_MASK area
324762306a36Sopenharmony_ci	 */
324862306a36Sopenharmony_ci	snprintf(prop, sizeof(prop), "%sbitclock-inversion", prefix);
324962306a36Sopenharmony_ci	bit = !!of_get_property(np, prop, NULL);
325062306a36Sopenharmony_ci
325162306a36Sopenharmony_ci	snprintf(prop, sizeof(prop), "%sframe-inversion", prefix);
325262306a36Sopenharmony_ci	frame = !!of_get_property(np, prop, NULL);
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci	switch ((bit << 4) + frame) {
325562306a36Sopenharmony_ci	case 0x11:
325662306a36Sopenharmony_ci		format |= SND_SOC_DAIFMT_IB_IF;
325762306a36Sopenharmony_ci		break;
325862306a36Sopenharmony_ci	case 0x10:
325962306a36Sopenharmony_ci		format |= SND_SOC_DAIFMT_IB_NF;
326062306a36Sopenharmony_ci		break;
326162306a36Sopenharmony_ci	case 0x01:
326262306a36Sopenharmony_ci		format |= SND_SOC_DAIFMT_NB_IF;
326362306a36Sopenharmony_ci		break;
326462306a36Sopenharmony_ci	default:
326562306a36Sopenharmony_ci		/* SND_SOC_DAIFMT_NB_NF is default */
326662306a36Sopenharmony_ci		break;
326762306a36Sopenharmony_ci	}
326862306a36Sopenharmony_ci
326962306a36Sopenharmony_ci	return format;
327062306a36Sopenharmony_ci}
327162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_daifmt_parse_format);
327262306a36Sopenharmony_ci
327362306a36Sopenharmony_ciunsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np,
327462306a36Sopenharmony_ci						     const char *prefix,
327562306a36Sopenharmony_ci						     struct device_node **bitclkmaster,
327662306a36Sopenharmony_ci						     struct device_node **framemaster)
327762306a36Sopenharmony_ci{
327862306a36Sopenharmony_ci	char prop[128];
327962306a36Sopenharmony_ci	unsigned int bit, frame;
328062306a36Sopenharmony_ci
328162306a36Sopenharmony_ci	if (!prefix)
328262306a36Sopenharmony_ci		prefix = "";
328362306a36Sopenharmony_ci
328462306a36Sopenharmony_ci	/*
328562306a36Sopenharmony_ci	 * check "[prefix]bitclock-master"
328662306a36Sopenharmony_ci	 * check "[prefix]frame-master"
328762306a36Sopenharmony_ci	 */
328862306a36Sopenharmony_ci	snprintf(prop, sizeof(prop), "%sbitclock-master", prefix);
328962306a36Sopenharmony_ci	bit = !!of_get_property(np, prop, NULL);
329062306a36Sopenharmony_ci	if (bit && bitclkmaster)
329162306a36Sopenharmony_ci		*bitclkmaster = of_parse_phandle(np, prop, 0);
329262306a36Sopenharmony_ci
329362306a36Sopenharmony_ci	snprintf(prop, sizeof(prop), "%sframe-master", prefix);
329462306a36Sopenharmony_ci	frame = !!of_get_property(np, prop, NULL);
329562306a36Sopenharmony_ci	if (frame && framemaster)
329662306a36Sopenharmony_ci		*framemaster = of_parse_phandle(np, prop, 0);
329762306a36Sopenharmony_ci
329862306a36Sopenharmony_ci	/*
329962306a36Sopenharmony_ci	 * return bitmap.
330062306a36Sopenharmony_ci	 * It will be parameter of
330162306a36Sopenharmony_ci	 *	snd_soc_daifmt_clock_provider_from_bitmap()
330262306a36Sopenharmony_ci	 */
330362306a36Sopenharmony_ci	return (bit << 4) + frame;
330462306a36Sopenharmony_ci}
330562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_daifmt_parse_clock_provider_raw);
330662306a36Sopenharmony_ci
330762306a36Sopenharmony_ciint snd_soc_get_stream_cpu(struct snd_soc_dai_link *dai_link, int stream)
330862306a36Sopenharmony_ci{
330962306a36Sopenharmony_ci	/*
331062306a36Sopenharmony_ci	 * [Normal]
331162306a36Sopenharmony_ci	 *
331262306a36Sopenharmony_ci	 * Playback
331362306a36Sopenharmony_ci	 *	CPU  : SNDRV_PCM_STREAM_PLAYBACK
331462306a36Sopenharmony_ci	 *	Codec: SNDRV_PCM_STREAM_PLAYBACK
331562306a36Sopenharmony_ci	 *
331662306a36Sopenharmony_ci	 * Capture
331762306a36Sopenharmony_ci	 *	CPU  : SNDRV_PCM_STREAM_CAPTURE
331862306a36Sopenharmony_ci	 *	Codec: SNDRV_PCM_STREAM_CAPTURE
331962306a36Sopenharmony_ci	 */
332062306a36Sopenharmony_ci	if (!dai_link->c2c_params)
332162306a36Sopenharmony_ci		return stream;
332262306a36Sopenharmony_ci
332362306a36Sopenharmony_ci	/*
332462306a36Sopenharmony_ci	 * [Codec2Codec]
332562306a36Sopenharmony_ci	 *
332662306a36Sopenharmony_ci	 * Playback
332762306a36Sopenharmony_ci	 *	CPU  : SNDRV_PCM_STREAM_CAPTURE
332862306a36Sopenharmony_ci	 *	Codec: SNDRV_PCM_STREAM_PLAYBACK
332962306a36Sopenharmony_ci	 *
333062306a36Sopenharmony_ci	 * Capture
333162306a36Sopenharmony_ci	 *	CPU  : SNDRV_PCM_STREAM_PLAYBACK
333262306a36Sopenharmony_ci	 *	Codec: SNDRV_PCM_STREAM_CAPTURE
333362306a36Sopenharmony_ci	 */
333462306a36Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_CAPTURE)
333562306a36Sopenharmony_ci		return SNDRV_PCM_STREAM_PLAYBACK;
333662306a36Sopenharmony_ci
333762306a36Sopenharmony_ci	return SNDRV_PCM_STREAM_CAPTURE;
333862306a36Sopenharmony_ci}
333962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_get_stream_cpu);
334062306a36Sopenharmony_ci
334162306a36Sopenharmony_ciint snd_soc_get_dai_id(struct device_node *ep)
334262306a36Sopenharmony_ci{
334362306a36Sopenharmony_ci	struct snd_soc_component *component;
334462306a36Sopenharmony_ci	struct snd_soc_dai_link_component dlc = {
334562306a36Sopenharmony_ci		.of_node = of_graph_get_port_parent(ep),
334662306a36Sopenharmony_ci	};
334762306a36Sopenharmony_ci	int ret;
334862306a36Sopenharmony_ci
334962306a36Sopenharmony_ci
335062306a36Sopenharmony_ci	/*
335162306a36Sopenharmony_ci	 * For example HDMI case, HDMI has video/sound port,
335262306a36Sopenharmony_ci	 * but ALSA SoC needs sound port number only.
335362306a36Sopenharmony_ci	 * Thus counting HDMI DT port/endpoint doesn't work.
335462306a36Sopenharmony_ci	 * Then, it should have .of_xlate_dai_id
335562306a36Sopenharmony_ci	 */
335662306a36Sopenharmony_ci	ret = -ENOTSUPP;
335762306a36Sopenharmony_ci	mutex_lock(&client_mutex);
335862306a36Sopenharmony_ci	component = soc_find_component(&dlc);
335962306a36Sopenharmony_ci	if (component)
336062306a36Sopenharmony_ci		ret = snd_soc_component_of_xlate_dai_id(component, ep);
336162306a36Sopenharmony_ci	mutex_unlock(&client_mutex);
336262306a36Sopenharmony_ci
336362306a36Sopenharmony_ci	of_node_put(dlc.of_node);
336462306a36Sopenharmony_ci
336562306a36Sopenharmony_ci	return ret;
336662306a36Sopenharmony_ci}
336762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_get_dai_id);
336862306a36Sopenharmony_ci
336962306a36Sopenharmony_ciint snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_component *dlc)
337062306a36Sopenharmony_ci{
337162306a36Sopenharmony_ci	struct snd_soc_component *pos;
337262306a36Sopenharmony_ci	int ret = -EPROBE_DEFER;
337362306a36Sopenharmony_ci
337462306a36Sopenharmony_ci	mutex_lock(&client_mutex);
337562306a36Sopenharmony_ci	for_each_component(pos) {
337662306a36Sopenharmony_ci		struct device_node *component_of_node = soc_component_to_node(pos);
337762306a36Sopenharmony_ci
337862306a36Sopenharmony_ci		if (component_of_node != args->np || !pos->num_dai)
337962306a36Sopenharmony_ci			continue;
338062306a36Sopenharmony_ci
338162306a36Sopenharmony_ci		ret = snd_soc_component_of_xlate_dai_name(pos, args, &dlc->dai_name);
338262306a36Sopenharmony_ci		if (ret == -ENOTSUPP) {
338362306a36Sopenharmony_ci			struct snd_soc_dai *dai;
338462306a36Sopenharmony_ci			int id = -1;
338562306a36Sopenharmony_ci
338662306a36Sopenharmony_ci			switch (args->args_count) {
338762306a36Sopenharmony_ci			case 0:
338862306a36Sopenharmony_ci				id = 0; /* same as dai_drv[0] */
338962306a36Sopenharmony_ci				break;
339062306a36Sopenharmony_ci			case 1:
339162306a36Sopenharmony_ci				id = args->args[0];
339262306a36Sopenharmony_ci				break;
339362306a36Sopenharmony_ci			default:
339462306a36Sopenharmony_ci				/* not supported */
339562306a36Sopenharmony_ci				break;
339662306a36Sopenharmony_ci			}
339762306a36Sopenharmony_ci
339862306a36Sopenharmony_ci			if (id < 0 || id >= pos->num_dai) {
339962306a36Sopenharmony_ci				ret = -EINVAL;
340062306a36Sopenharmony_ci				continue;
340162306a36Sopenharmony_ci			}
340262306a36Sopenharmony_ci
340362306a36Sopenharmony_ci			ret = 0;
340462306a36Sopenharmony_ci
340562306a36Sopenharmony_ci			/* find target DAI */
340662306a36Sopenharmony_ci			for_each_component_dais(pos, dai) {
340762306a36Sopenharmony_ci				if (id == 0)
340862306a36Sopenharmony_ci					break;
340962306a36Sopenharmony_ci				id--;
341062306a36Sopenharmony_ci			}
341162306a36Sopenharmony_ci
341262306a36Sopenharmony_ci			dlc->dai_name	= snd_soc_dai_name_get(dai);
341362306a36Sopenharmony_ci		} else if (ret) {
341462306a36Sopenharmony_ci			/*
341562306a36Sopenharmony_ci			 * if another error than ENOTSUPP is returned go on and
341662306a36Sopenharmony_ci			 * check if another component is provided with the same
341762306a36Sopenharmony_ci			 * node. This may happen if a device provides several
341862306a36Sopenharmony_ci			 * components
341962306a36Sopenharmony_ci			 */
342062306a36Sopenharmony_ci			continue;
342162306a36Sopenharmony_ci		}
342262306a36Sopenharmony_ci
342362306a36Sopenharmony_ci		break;
342462306a36Sopenharmony_ci	}
342562306a36Sopenharmony_ci
342662306a36Sopenharmony_ci	if (ret == 0)
342762306a36Sopenharmony_ci		dlc->of_node = args->np;
342862306a36Sopenharmony_ci
342962306a36Sopenharmony_ci	mutex_unlock(&client_mutex);
343062306a36Sopenharmony_ci	return ret;
343162306a36Sopenharmony_ci}
343262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_get_dlc);
343362306a36Sopenharmony_ci
343462306a36Sopenharmony_ciint snd_soc_of_get_dlc(struct device_node *of_node,
343562306a36Sopenharmony_ci		       struct of_phandle_args *args,
343662306a36Sopenharmony_ci		       struct snd_soc_dai_link_component *dlc,
343762306a36Sopenharmony_ci		       int index)
343862306a36Sopenharmony_ci{
343962306a36Sopenharmony_ci	struct of_phandle_args __args;
344062306a36Sopenharmony_ci	int ret;
344162306a36Sopenharmony_ci
344262306a36Sopenharmony_ci	if (!args)
344362306a36Sopenharmony_ci		args = &__args;
344462306a36Sopenharmony_ci
344562306a36Sopenharmony_ci	ret = of_parse_phandle_with_args(of_node, "sound-dai",
344662306a36Sopenharmony_ci					 "#sound-dai-cells", index, args);
344762306a36Sopenharmony_ci	if (ret)
344862306a36Sopenharmony_ci		return ret;
344962306a36Sopenharmony_ci
345062306a36Sopenharmony_ci	return snd_soc_get_dlc(args, dlc);
345162306a36Sopenharmony_ci}
345262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_of_get_dlc);
345362306a36Sopenharmony_ci
345462306a36Sopenharmony_ciint snd_soc_get_dai_name(const struct of_phandle_args *args,
345562306a36Sopenharmony_ci			 const char **dai_name)
345662306a36Sopenharmony_ci{
345762306a36Sopenharmony_ci	struct snd_soc_dai_link_component dlc;
345862306a36Sopenharmony_ci	int ret = snd_soc_get_dlc(args, &dlc);
345962306a36Sopenharmony_ci
346062306a36Sopenharmony_ci	if (ret == 0)
346162306a36Sopenharmony_ci		*dai_name = dlc.dai_name;
346262306a36Sopenharmony_ci
346362306a36Sopenharmony_ci	return ret;
346462306a36Sopenharmony_ci}
346562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_get_dai_name);
346662306a36Sopenharmony_ci
346762306a36Sopenharmony_ciint snd_soc_of_get_dai_name(struct device_node *of_node,
346862306a36Sopenharmony_ci			    const char **dai_name, int index)
346962306a36Sopenharmony_ci{
347062306a36Sopenharmony_ci	struct snd_soc_dai_link_component dlc;
347162306a36Sopenharmony_ci	int ret = snd_soc_of_get_dlc(of_node, NULL, &dlc, index);
347262306a36Sopenharmony_ci
347362306a36Sopenharmony_ci	if (ret == 0)
347462306a36Sopenharmony_ci		*dai_name = dlc.dai_name;
347562306a36Sopenharmony_ci
347662306a36Sopenharmony_ci	return ret;
347762306a36Sopenharmony_ci}
347862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name);
347962306a36Sopenharmony_ci
348062306a36Sopenharmony_cistruct snd_soc_dai *snd_soc_get_dai_via_args(struct of_phandle_args *dai_args)
348162306a36Sopenharmony_ci{
348262306a36Sopenharmony_ci	struct snd_soc_dai *dai;
348362306a36Sopenharmony_ci	struct snd_soc_component *component;
348462306a36Sopenharmony_ci
348562306a36Sopenharmony_ci	mutex_lock(&client_mutex);
348662306a36Sopenharmony_ci	for_each_component(component) {
348762306a36Sopenharmony_ci		for_each_component_dais(component, dai)
348862306a36Sopenharmony_ci			if (snd_soc_is_match_dai_args(dai->driver->dai_args, dai_args))
348962306a36Sopenharmony_ci				goto found;
349062306a36Sopenharmony_ci	}
349162306a36Sopenharmony_ci	dai = NULL;
349262306a36Sopenharmony_cifound:
349362306a36Sopenharmony_ci	mutex_unlock(&client_mutex);
349462306a36Sopenharmony_ci	return dai;
349562306a36Sopenharmony_ci}
349662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_get_dai_via_args);
349762306a36Sopenharmony_ci
349862306a36Sopenharmony_cistatic void __snd_soc_of_put_component(struct snd_soc_dai_link_component *component)
349962306a36Sopenharmony_ci{
350062306a36Sopenharmony_ci	if (component->of_node) {
350162306a36Sopenharmony_ci		of_node_put(component->of_node);
350262306a36Sopenharmony_ci		component->of_node = NULL;
350362306a36Sopenharmony_ci	}
350462306a36Sopenharmony_ci}
350562306a36Sopenharmony_ci
350662306a36Sopenharmony_cistatic int __snd_soc_of_get_dai_link_component_alloc(
350762306a36Sopenharmony_ci	struct device *dev, struct device_node *of_node,
350862306a36Sopenharmony_ci	struct snd_soc_dai_link_component **ret_component,
350962306a36Sopenharmony_ci	int *ret_num)
351062306a36Sopenharmony_ci{
351162306a36Sopenharmony_ci	struct snd_soc_dai_link_component *component;
351262306a36Sopenharmony_ci	int num;
351362306a36Sopenharmony_ci
351462306a36Sopenharmony_ci	/* Count the number of CPUs/CODECs */
351562306a36Sopenharmony_ci	num = of_count_phandle_with_args(of_node, "sound-dai", "#sound-dai-cells");
351662306a36Sopenharmony_ci	if (num <= 0) {
351762306a36Sopenharmony_ci		if (num == -ENOENT)
351862306a36Sopenharmony_ci			dev_err(dev, "No 'sound-dai' property\n");
351962306a36Sopenharmony_ci		else
352062306a36Sopenharmony_ci			dev_err(dev, "Bad phandle in 'sound-dai'\n");
352162306a36Sopenharmony_ci		return num;
352262306a36Sopenharmony_ci	}
352362306a36Sopenharmony_ci	component = devm_kcalloc(dev, num, sizeof(*component), GFP_KERNEL);
352462306a36Sopenharmony_ci	if (!component)
352562306a36Sopenharmony_ci		return -ENOMEM;
352662306a36Sopenharmony_ci
352762306a36Sopenharmony_ci	*ret_component	= component;
352862306a36Sopenharmony_ci	*ret_num	= num;
352962306a36Sopenharmony_ci
353062306a36Sopenharmony_ci	return 0;
353162306a36Sopenharmony_ci}
353262306a36Sopenharmony_ci
353362306a36Sopenharmony_ci/*
353462306a36Sopenharmony_ci * snd_soc_of_put_dai_link_codecs - Dereference device nodes in the codecs array
353562306a36Sopenharmony_ci * @dai_link: DAI link
353662306a36Sopenharmony_ci *
353762306a36Sopenharmony_ci * Dereference device nodes acquired by snd_soc_of_get_dai_link_codecs().
353862306a36Sopenharmony_ci */
353962306a36Sopenharmony_civoid snd_soc_of_put_dai_link_codecs(struct snd_soc_dai_link *dai_link)
354062306a36Sopenharmony_ci{
354162306a36Sopenharmony_ci	struct snd_soc_dai_link_component *component;
354262306a36Sopenharmony_ci	int index;
354362306a36Sopenharmony_ci
354462306a36Sopenharmony_ci	for_each_link_codecs(dai_link, index, component)
354562306a36Sopenharmony_ci		__snd_soc_of_put_component(component);
354662306a36Sopenharmony_ci}
354762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_of_put_dai_link_codecs);
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_ci/*
355062306a36Sopenharmony_ci * snd_soc_of_get_dai_link_codecs - Parse a list of CODECs in the devicetree
355162306a36Sopenharmony_ci * @dev: Card device
355262306a36Sopenharmony_ci * @of_node: Device node
355362306a36Sopenharmony_ci * @dai_link: DAI link
355462306a36Sopenharmony_ci *
355562306a36Sopenharmony_ci * Builds an array of CODEC DAI components from the DAI link property
355662306a36Sopenharmony_ci * 'sound-dai'.
355762306a36Sopenharmony_ci * The array is set in the DAI link and the number of DAIs is set accordingly.
355862306a36Sopenharmony_ci * The device nodes in the array (of_node) must be dereferenced by calling
355962306a36Sopenharmony_ci * snd_soc_of_put_dai_link_codecs() on @dai_link.
356062306a36Sopenharmony_ci *
356162306a36Sopenharmony_ci * Returns 0 for success
356262306a36Sopenharmony_ci */
356362306a36Sopenharmony_ciint snd_soc_of_get_dai_link_codecs(struct device *dev,
356462306a36Sopenharmony_ci				   struct device_node *of_node,
356562306a36Sopenharmony_ci				   struct snd_soc_dai_link *dai_link)
356662306a36Sopenharmony_ci{
356762306a36Sopenharmony_ci	struct snd_soc_dai_link_component *component;
356862306a36Sopenharmony_ci	int index, ret;
356962306a36Sopenharmony_ci
357062306a36Sopenharmony_ci	ret = __snd_soc_of_get_dai_link_component_alloc(dev, of_node,
357162306a36Sopenharmony_ci					 &dai_link->codecs, &dai_link->num_codecs);
357262306a36Sopenharmony_ci	if (ret < 0)
357362306a36Sopenharmony_ci		return ret;
357462306a36Sopenharmony_ci
357562306a36Sopenharmony_ci	/* Parse the list */
357662306a36Sopenharmony_ci	for_each_link_codecs(dai_link, index, component) {
357762306a36Sopenharmony_ci		ret = snd_soc_of_get_dlc(of_node, NULL, component, index);
357862306a36Sopenharmony_ci		if (ret)
357962306a36Sopenharmony_ci			goto err;
358062306a36Sopenharmony_ci	}
358162306a36Sopenharmony_ci	return 0;
358262306a36Sopenharmony_cierr:
358362306a36Sopenharmony_ci	snd_soc_of_put_dai_link_codecs(dai_link);
358462306a36Sopenharmony_ci	dai_link->codecs = NULL;
358562306a36Sopenharmony_ci	dai_link->num_codecs = 0;
358662306a36Sopenharmony_ci	return ret;
358762306a36Sopenharmony_ci}
358862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_of_get_dai_link_codecs);
358962306a36Sopenharmony_ci
359062306a36Sopenharmony_ci/*
359162306a36Sopenharmony_ci * snd_soc_of_put_dai_link_cpus - Dereference device nodes in the codecs array
359262306a36Sopenharmony_ci * @dai_link: DAI link
359362306a36Sopenharmony_ci *
359462306a36Sopenharmony_ci * Dereference device nodes acquired by snd_soc_of_get_dai_link_cpus().
359562306a36Sopenharmony_ci */
359662306a36Sopenharmony_civoid snd_soc_of_put_dai_link_cpus(struct snd_soc_dai_link *dai_link)
359762306a36Sopenharmony_ci{
359862306a36Sopenharmony_ci	struct snd_soc_dai_link_component *component;
359962306a36Sopenharmony_ci	int index;
360062306a36Sopenharmony_ci
360162306a36Sopenharmony_ci	for_each_link_cpus(dai_link, index, component)
360262306a36Sopenharmony_ci		__snd_soc_of_put_component(component);
360362306a36Sopenharmony_ci}
360462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_of_put_dai_link_cpus);
360562306a36Sopenharmony_ci
360662306a36Sopenharmony_ci/*
360762306a36Sopenharmony_ci * snd_soc_of_get_dai_link_cpus - Parse a list of CPU DAIs in the devicetree
360862306a36Sopenharmony_ci * @dev: Card device
360962306a36Sopenharmony_ci * @of_node: Device node
361062306a36Sopenharmony_ci * @dai_link: DAI link
361162306a36Sopenharmony_ci *
361262306a36Sopenharmony_ci * Is analogous to snd_soc_of_get_dai_link_codecs but parses a list of CPU DAIs
361362306a36Sopenharmony_ci * instead.
361462306a36Sopenharmony_ci *
361562306a36Sopenharmony_ci * Returns 0 for success
361662306a36Sopenharmony_ci */
361762306a36Sopenharmony_ciint snd_soc_of_get_dai_link_cpus(struct device *dev,
361862306a36Sopenharmony_ci				 struct device_node *of_node,
361962306a36Sopenharmony_ci				 struct snd_soc_dai_link *dai_link)
362062306a36Sopenharmony_ci{
362162306a36Sopenharmony_ci	struct snd_soc_dai_link_component *component;
362262306a36Sopenharmony_ci	int index, ret;
362362306a36Sopenharmony_ci
362462306a36Sopenharmony_ci	/* Count the number of CPUs */
362562306a36Sopenharmony_ci	ret = __snd_soc_of_get_dai_link_component_alloc(dev, of_node,
362662306a36Sopenharmony_ci					 &dai_link->cpus, &dai_link->num_cpus);
362762306a36Sopenharmony_ci	if (ret < 0)
362862306a36Sopenharmony_ci		return ret;
362962306a36Sopenharmony_ci
363062306a36Sopenharmony_ci	/* Parse the list */
363162306a36Sopenharmony_ci	for_each_link_cpus(dai_link, index, component) {
363262306a36Sopenharmony_ci		ret = snd_soc_of_get_dlc(of_node, NULL, component, index);
363362306a36Sopenharmony_ci		if (ret)
363462306a36Sopenharmony_ci			goto err;
363562306a36Sopenharmony_ci	}
363662306a36Sopenharmony_ci	return 0;
363762306a36Sopenharmony_cierr:
363862306a36Sopenharmony_ci	snd_soc_of_put_dai_link_cpus(dai_link);
363962306a36Sopenharmony_ci	dai_link->cpus = NULL;
364062306a36Sopenharmony_ci	dai_link->num_cpus = 0;
364162306a36Sopenharmony_ci	return ret;
364262306a36Sopenharmony_ci}
364362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_of_get_dai_link_cpus);
364462306a36Sopenharmony_ci
364562306a36Sopenharmony_cistatic int __init snd_soc_init(void)
364662306a36Sopenharmony_ci{
364762306a36Sopenharmony_ci	int ret;
364862306a36Sopenharmony_ci
364962306a36Sopenharmony_ci	snd_soc_debugfs_init();
365062306a36Sopenharmony_ci	ret = snd_soc_util_init();
365162306a36Sopenharmony_ci	if (ret)
365262306a36Sopenharmony_ci		goto err_util_init;
365362306a36Sopenharmony_ci
365462306a36Sopenharmony_ci	ret = platform_driver_register(&soc_driver);
365562306a36Sopenharmony_ci	if (ret)
365662306a36Sopenharmony_ci		goto err_register;
365762306a36Sopenharmony_ci	return 0;
365862306a36Sopenharmony_ci
365962306a36Sopenharmony_cierr_register:
366062306a36Sopenharmony_ci	snd_soc_util_exit();
366162306a36Sopenharmony_cierr_util_init:
366262306a36Sopenharmony_ci	snd_soc_debugfs_exit();
366362306a36Sopenharmony_ci	return ret;
366462306a36Sopenharmony_ci}
366562306a36Sopenharmony_cimodule_init(snd_soc_init);
366662306a36Sopenharmony_ci
366762306a36Sopenharmony_cistatic void __exit snd_soc_exit(void)
366862306a36Sopenharmony_ci{
366962306a36Sopenharmony_ci	snd_soc_util_exit();
367062306a36Sopenharmony_ci	snd_soc_debugfs_exit();
367162306a36Sopenharmony_ci
367262306a36Sopenharmony_ci	platform_driver_unregister(&soc_driver);
367362306a36Sopenharmony_ci}
367462306a36Sopenharmony_cimodule_exit(snd_soc_exit);
367562306a36Sopenharmony_ci
367662306a36Sopenharmony_ci/* Module information */
367762306a36Sopenharmony_ciMODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
367862306a36Sopenharmony_ciMODULE_DESCRIPTION("ALSA SoC Core");
367962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
368062306a36Sopenharmony_ciMODULE_ALIAS("platform:soc-audio");
3681