xref: /openbmc/linux/sound/soc/soc-core.c (revision b24c539b4dc58f7d6283b8d06e240ac87d4966d7)
1db2a4165SFrank Mandarino /*
2db2a4165SFrank Mandarino  * soc-core.c  --  ALSA SoC Audio Layer
3db2a4165SFrank Mandarino  *
4db2a4165SFrank Mandarino  * Copyright 2005 Wolfson Microelectronics PLC.
50664d888SLiam Girdwood  * Copyright 2005 Openedhand Ltd.
6f0fba2adSLiam Girdwood  * Copyright (C) 2010 Slimlogic Ltd.
7f0fba2adSLiam Girdwood  * Copyright (C) 2010 Texas Instruments Inc.
80664d888SLiam Girdwood  *
9d331124dSLiam Girdwood  * Author: Liam Girdwood <lrg@slimlogic.co.uk>
100664d888SLiam Girdwood  *         with code, comments and ideas from :-
110664d888SLiam Girdwood  *         Richard Purdie <richard@openedhand.com>
12db2a4165SFrank Mandarino  *
13db2a4165SFrank Mandarino  *  This program is free software; you can redistribute  it and/or modify it
14db2a4165SFrank Mandarino  *  under  the terms of  the GNU General  Public License as published by the
15db2a4165SFrank Mandarino  *  Free Software Foundation;  either version 2 of the  License, or (at your
16db2a4165SFrank Mandarino  *  option) any later version.
17db2a4165SFrank Mandarino  *
18db2a4165SFrank Mandarino  *  TODO:
19db2a4165SFrank Mandarino  *   o Add hw rules to enforce rates, etc.
20db2a4165SFrank Mandarino  *   o More testing with other codecs/machines.
21db2a4165SFrank Mandarino  *   o Add more codecs and platforms to ensure good API coverage.
22db2a4165SFrank Mandarino  *   o Support TDM on PCM and I2S
23db2a4165SFrank Mandarino  */
24db2a4165SFrank Mandarino 
25db2a4165SFrank Mandarino #include <linux/module.h>
26db2a4165SFrank Mandarino #include <linux/moduleparam.h>
27db2a4165SFrank Mandarino #include <linux/init.h>
28db2a4165SFrank Mandarino #include <linux/delay.h>
29db2a4165SFrank Mandarino #include <linux/pm.h>
30db2a4165SFrank Mandarino #include <linux/bitops.h>
3112ef193dSTroy Kisky #include <linux/debugfs.h>
32db2a4165SFrank Mandarino #include <linux/platform_device.h>
33741a509fSMarkus Pargmann #include <linux/pinctrl/consumer.h>
34f0e8ed85SMark Brown #include <linux/ctype.h>
355a0e3ad6STejun Heo #include <linux/slab.h>
36bec4fa05SStephen Warren #include <linux/of.h>
37a180e8b9SKuninori Morimoto #include <linux/of_graph.h>
38345233d7SLiam Girdwood #include <linux/dmi.h>
39db2a4165SFrank Mandarino #include <sound/core.h>
403028eb8cSMark Brown #include <sound/jack.h>
41db2a4165SFrank Mandarino #include <sound/pcm.h>
42db2a4165SFrank Mandarino #include <sound/pcm_params.h>
43db2a4165SFrank Mandarino #include <sound/soc.h>
4401d7584cSLiam Girdwood #include <sound/soc-dpcm.h>
458a978234SLiam Girdwood #include <sound/soc-topology.h>
46db2a4165SFrank Mandarino #include <sound/initval.h>
47db2a4165SFrank Mandarino 
48a8b1d34fSMark Brown #define CREATE_TRACE_POINTS
49a8b1d34fSMark Brown #include <trace/events/asoc.h>
50a8b1d34fSMark Brown 
51f0fba2adSLiam Girdwood #define NAME_SIZE	32
52f0fba2adSLiam Girdwood 
53384c89e2SMark Brown #ifdef CONFIG_DEBUG_FS
548a9dab1aSMark Brown struct dentry *snd_soc_debugfs_root;
558a9dab1aSMark Brown EXPORT_SYMBOL_GPL(snd_soc_debugfs_root);
56384c89e2SMark Brown #endif
57384c89e2SMark Brown 
58c5af3a2eSMark Brown static DEFINE_MUTEX(client_mutex);
590d0cf00aSMark Brown static LIST_HEAD(codec_list);
60030e79f6SKuninori Morimoto static LIST_HEAD(component_list);
61c5af3a2eSMark Brown 
62db2a4165SFrank Mandarino /*
63db2a4165SFrank Mandarino  * This is a timeout to do a DAPM powerdown after a stream is closed().
64db2a4165SFrank Mandarino  * It can be used to eliminate pops between different playback streams, e.g.
65db2a4165SFrank Mandarino  * between two audio tracks.
66db2a4165SFrank Mandarino  */
67db2a4165SFrank Mandarino static int pmdown_time = 5000;
68db2a4165SFrank Mandarino module_param(pmdown_time, int, 0);
69db2a4165SFrank Mandarino MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)");
70db2a4165SFrank Mandarino 
7198faf436SMengdong Lin /* If a DMI filed contain strings in this blacklist (e.g.
7298faf436SMengdong Lin  * "Type2 - Board Manufacturer" or  "Type1 - TBD by OEM"), it will be taken
7398faf436SMengdong Lin  * as invalid and dropped when setting the card long name from DMI info.
7498faf436SMengdong Lin  */
7598faf436SMengdong Lin static const char * const dmi_blacklist[] = {
7698faf436SMengdong Lin 	"To be filled by OEM",
7798faf436SMengdong Lin 	"TBD by OEM",
7898faf436SMengdong Lin 	"Default String",
7998faf436SMengdong Lin 	"Board Manufacturer",
8098faf436SMengdong Lin 	"Board Vendor Name",
8198faf436SMengdong Lin 	"Board Product Name",
8298faf436SMengdong Lin 	NULL,	/* terminator */
8398faf436SMengdong Lin };
8498faf436SMengdong Lin 
852bc9a81eSDimitris Papastamos /* returns the minimum number of bytes needed to represent
862bc9a81eSDimitris Papastamos  * a particular given value */
872bc9a81eSDimitris Papastamos static int min_bytes_needed(unsigned long val)
882bc9a81eSDimitris Papastamos {
892bc9a81eSDimitris Papastamos 	int c = 0;
902bc9a81eSDimitris Papastamos 	int i;
912bc9a81eSDimitris Papastamos 
922bc9a81eSDimitris Papastamos 	for (i = (sizeof val * 8) - 1; i >= 0; --i, ++c)
932bc9a81eSDimitris Papastamos 		if (val & (1UL << i))
942bc9a81eSDimitris Papastamos 			break;
952bc9a81eSDimitris Papastamos 	c = (sizeof val * 8) - c;
962bc9a81eSDimitris Papastamos 	if (!c || (c % 8))
972bc9a81eSDimitris Papastamos 		c = (c + 8) / 8;
982bc9a81eSDimitris Papastamos 	else
992bc9a81eSDimitris Papastamos 		c /= 8;
1002bc9a81eSDimitris Papastamos 	return c;
1012bc9a81eSDimitris Papastamos }
1022bc9a81eSDimitris Papastamos 
10313fd179fSDimitris Papastamos /* fill buf which is 'len' bytes with a formatted
10413fd179fSDimitris Papastamos  * string of the form 'reg: value\n' */
10513fd179fSDimitris Papastamos static int format_register_str(struct snd_soc_codec *codec,
10613fd179fSDimitris Papastamos 			       unsigned int reg, char *buf, size_t len)
1072624d5faSMark Brown {
10800b317a4SStephen Warren 	int wordsize = min_bytes_needed(codec->driver->reg_cache_size) * 2;
10900b317a4SStephen Warren 	int regsize = codec->driver->reg_word_size * 2;
11013fd179fSDimitris Papastamos 	int ret;
11113fd179fSDimitris Papastamos 
11213fd179fSDimitris Papastamos 	/* +2 for ': ' and + 1 for '\n' */
11313fd179fSDimitris Papastamos 	if (wordsize + regsize + 2 + 1 != len)
11413fd179fSDimitris Papastamos 		return -EINVAL;
11513fd179fSDimitris Papastamos 
116d6b6c2caSTakashi Iwai 	sprintf(buf, "%.*x: ", wordsize, reg);
117d6b6c2caSTakashi Iwai 	buf += wordsize + 2;
118d6b6c2caSTakashi Iwai 
11913fd179fSDimitris Papastamos 	ret = snd_soc_read(codec, reg);
120d6b6c2caSTakashi Iwai 	if (ret < 0)
121d6b6c2caSTakashi Iwai 		memset(buf, 'X', regsize);
122d6b6c2caSTakashi Iwai 	else
123d6b6c2caSTakashi Iwai 		sprintf(buf, "%.*x", regsize, ret);
124d6b6c2caSTakashi Iwai 	buf[regsize] = '\n';
125d6b6c2caSTakashi Iwai 	/* no NUL-termination needed */
12613fd179fSDimitris Papastamos 	return 0;
12713fd179fSDimitris Papastamos }
12813fd179fSDimitris Papastamos 
12913fd179fSDimitris Papastamos /* codec register dump */
13013fd179fSDimitris Papastamos static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf,
13113fd179fSDimitris Papastamos 				  size_t count, loff_t pos)
13213fd179fSDimitris Papastamos {
13313fd179fSDimitris Papastamos 	int i, step = 1;
1342bc9a81eSDimitris Papastamos 	int wordsize, regsize;
13513fd179fSDimitris Papastamos 	int len;
13613fd179fSDimitris Papastamos 	size_t total = 0;
13713fd179fSDimitris Papastamos 	loff_t p = 0;
1382bc9a81eSDimitris Papastamos 
13900b317a4SStephen Warren 	wordsize = min_bytes_needed(codec->driver->reg_cache_size) * 2;
14000b317a4SStephen Warren 	regsize = codec->driver->reg_word_size * 2;
1412624d5faSMark Brown 
14213fd179fSDimitris Papastamos 	len = wordsize + regsize + 2 + 1;
14313fd179fSDimitris Papastamos 
144f0fba2adSLiam Girdwood 	if (!codec->driver->reg_cache_size)
1452624d5faSMark Brown 		return 0;
1462624d5faSMark Brown 
147f0fba2adSLiam Girdwood 	if (codec->driver->reg_cache_step)
148f0fba2adSLiam Girdwood 		step = codec->driver->reg_cache_step;
1492624d5faSMark Brown 
150f0fba2adSLiam Girdwood 	for (i = 0; i < codec->driver->reg_cache_size; i += step) {
15113fd179fSDimitris Papastamos 		/* only support larger than PAGE_SIZE bytes debugfs
15213fd179fSDimitris Papastamos 		 * entries for the default case */
15313fd179fSDimitris Papastamos 		if (p >= pos) {
15413fd179fSDimitris Papastamos 			if (total + len >= count - 1)
1552624d5faSMark Brown 				break;
15613fd179fSDimitris Papastamos 			format_register_str(codec, i, buf + total, len);
15713fd179fSDimitris Papastamos 			total += len;
15813fd179fSDimitris Papastamos 		}
15913fd179fSDimitris Papastamos 		p += len;
16013fd179fSDimitris Papastamos 	}
1612624d5faSMark Brown 
16213fd179fSDimitris Papastamos 	total = min(total, count - 1);
1632624d5faSMark Brown 
16413fd179fSDimitris Papastamos 	return total;
1652624d5faSMark Brown }
16613fd179fSDimitris Papastamos 
1672624d5faSMark Brown static ssize_t codec_reg_show(struct device *dev,
1682624d5faSMark Brown 	struct device_attribute *attr, char *buf)
1692624d5faSMark Brown {
17036ae1a96SMark Brown 	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
171f0fba2adSLiam Girdwood 
17213fd179fSDimitris Papastamos 	return soc_codec_reg_show(rtd->codec, buf, PAGE_SIZE, 0);
1732624d5faSMark Brown }
1742624d5faSMark Brown 
175c828a892SJoe Perches static DEVICE_ATTR_RO(codec_reg);
1762624d5faSMark Brown 
177dbe21408SMark Brown static ssize_t pmdown_time_show(struct device *dev,
178dbe21408SMark Brown 				struct device_attribute *attr, char *buf)
179dbe21408SMark Brown {
18036ae1a96SMark Brown 	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
181dbe21408SMark Brown 
182f0fba2adSLiam Girdwood 	return sprintf(buf, "%ld\n", rtd->pmdown_time);
183dbe21408SMark Brown }
184dbe21408SMark Brown 
185dbe21408SMark Brown static ssize_t pmdown_time_set(struct device *dev,
186dbe21408SMark Brown 			       struct device_attribute *attr,
187dbe21408SMark Brown 			       const char *buf, size_t count)
188dbe21408SMark Brown {
18936ae1a96SMark Brown 	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
190c593b520SMark Brown 	int ret;
191dbe21408SMark Brown 
192b785a492SJingoo Han 	ret = kstrtol(buf, 10, &rtd->pmdown_time);
193c593b520SMark Brown 	if (ret)
194c593b520SMark Brown 		return ret;
195dbe21408SMark Brown 
196dbe21408SMark Brown 	return count;
197dbe21408SMark Brown }
198dbe21408SMark Brown 
199dbe21408SMark Brown static DEVICE_ATTR(pmdown_time, 0644, pmdown_time_show, pmdown_time_set);
200dbe21408SMark Brown 
201d29697dcSTakashi Iwai static struct attribute *soc_dev_attrs[] = {
202d29697dcSTakashi Iwai 	&dev_attr_codec_reg.attr,
203d29697dcSTakashi Iwai 	&dev_attr_pmdown_time.attr,
204d29697dcSTakashi Iwai 	NULL
205d29697dcSTakashi Iwai };
206d29697dcSTakashi Iwai 
207d29697dcSTakashi Iwai static umode_t soc_dev_attr_is_visible(struct kobject *kobj,
208d29697dcSTakashi Iwai 				       struct attribute *attr, int idx)
209d29697dcSTakashi Iwai {
210d29697dcSTakashi Iwai 	struct device *dev = kobj_to_dev(kobj);
211d29697dcSTakashi Iwai 	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
212d29697dcSTakashi Iwai 
213d29697dcSTakashi Iwai 	if (attr == &dev_attr_pmdown_time.attr)
214d29697dcSTakashi Iwai 		return attr->mode; /* always visible */
2153b6eed8dSKuninori Morimoto 	return rtd->num_codecs ? attr->mode : 0; /* enabled only with codec */
216d29697dcSTakashi Iwai }
217d29697dcSTakashi Iwai 
218d29697dcSTakashi Iwai static const struct attribute_group soc_dapm_dev_group = {
219d29697dcSTakashi Iwai 	.attrs = soc_dapm_dev_attrs,
220d29697dcSTakashi Iwai 	.is_visible = soc_dev_attr_is_visible,
221d29697dcSTakashi Iwai };
222d29697dcSTakashi Iwai 
223f7e73b26SMark Brown static const struct attribute_group soc_dev_group = {
224d29697dcSTakashi Iwai 	.attrs = soc_dev_attrs,
225d29697dcSTakashi Iwai 	.is_visible = soc_dev_attr_is_visible,
226d29697dcSTakashi Iwai };
227d29697dcSTakashi Iwai 
228d29697dcSTakashi Iwai static const struct attribute_group *soc_dev_attr_groups[] = {
229d29697dcSTakashi Iwai 	&soc_dapm_dev_group,
230f7e73b26SMark Brown 	&soc_dev_group,
231d29697dcSTakashi Iwai 	NULL
232d29697dcSTakashi Iwai };
233d29697dcSTakashi Iwai 
2342624d5faSMark Brown #ifdef CONFIG_DEBUG_FS
2352624d5faSMark Brown static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf,
2362624d5faSMark Brown 				   size_t count, loff_t *ppos)
2372624d5faSMark Brown {
2382624d5faSMark Brown 	ssize_t ret;
2392624d5faSMark Brown 	struct snd_soc_codec *codec = file->private_data;
24013fd179fSDimitris Papastamos 	char *buf;
24113fd179fSDimitris Papastamos 
24213fd179fSDimitris Papastamos 	if (*ppos < 0 || !count)
24313fd179fSDimitris Papastamos 		return -EINVAL;
24413fd179fSDimitris Papastamos 
24513fd179fSDimitris Papastamos 	buf = kmalloc(count, GFP_KERNEL);
2462624d5faSMark Brown 	if (!buf)
2472624d5faSMark Brown 		return -ENOMEM;
24813fd179fSDimitris Papastamos 
24913fd179fSDimitris Papastamos 	ret = soc_codec_reg_show(codec, buf, count, *ppos);
25013fd179fSDimitris Papastamos 	if (ret >= 0) {
25113fd179fSDimitris Papastamos 		if (copy_to_user(user_buf, buf, ret)) {
25213fd179fSDimitris Papastamos 			kfree(buf);
25313fd179fSDimitris Papastamos 			return -EFAULT;
25413fd179fSDimitris Papastamos 		}
25513fd179fSDimitris Papastamos 		*ppos += ret;
25613fd179fSDimitris Papastamos 	}
25713fd179fSDimitris Papastamos 
2582624d5faSMark Brown 	kfree(buf);
2592624d5faSMark Brown 	return ret;
2602624d5faSMark Brown }
2612624d5faSMark Brown 
2622624d5faSMark Brown static ssize_t codec_reg_write_file(struct file *file,
2632624d5faSMark Brown 		const char __user *user_buf, size_t count, loff_t *ppos)
2642624d5faSMark Brown {
2652624d5faSMark Brown 	char buf[32];
26634e268d8SStephen Boyd 	size_t buf_size;
2672624d5faSMark Brown 	char *start = buf;
2682624d5faSMark Brown 	unsigned long reg, value;
2692624d5faSMark Brown 	struct snd_soc_codec *codec = file->private_data;
270b785a492SJingoo Han 	int ret;
2712624d5faSMark Brown 
2722624d5faSMark Brown 	buf_size = min(count, (sizeof(buf)-1));
2732624d5faSMark Brown 	if (copy_from_user(buf, user_buf, buf_size))
2742624d5faSMark Brown 		return -EFAULT;
2752624d5faSMark Brown 	buf[buf_size] = 0;
2762624d5faSMark Brown 
2772624d5faSMark Brown 	while (*start == ' ')
2782624d5faSMark Brown 		start++;
2792624d5faSMark Brown 	reg = simple_strtoul(start, &start, 16);
2802624d5faSMark Brown 	while (*start == ' ')
2812624d5faSMark Brown 		start++;
282b785a492SJingoo Han 	ret = kstrtoul(start, 16, &value);
283b785a492SJingoo Han 	if (ret)
284b785a492SJingoo Han 		return ret;
2850d51a9cbSMark Brown 
2860d51a9cbSMark Brown 	/* Userspace has been fiddling around behind the kernel's back */
287373d4d09SRusty Russell 	add_taint(TAINT_USER, LOCKDEP_NOW_UNRELIABLE);
2880d51a9cbSMark Brown 
289e4f078d8SDimitris Papastamos 	snd_soc_write(codec, reg, value);
2902624d5faSMark Brown 	return buf_size;
2912624d5faSMark Brown }
2922624d5faSMark Brown 
2932624d5faSMark Brown static const struct file_operations codec_reg_fops = {
294234e3405SStephen Boyd 	.open = simple_open,
2952624d5faSMark Brown 	.read = codec_reg_read_file,
2962624d5faSMark Brown 	.write = codec_reg_write_file,
2976038f373SArnd Bergmann 	.llseek = default_llseek,
2982624d5faSMark Brown };
2992624d5faSMark Brown 
30081c7cfd1SLars-Peter Clausen static void soc_init_component_debugfs(struct snd_soc_component *component)
301e73f3de5SRussell King {
3026553bf06SLars-Peter Clausen 	if (!component->card->debugfs_card_root)
3036553bf06SLars-Peter Clausen 		return;
3046553bf06SLars-Peter Clausen 
30581c7cfd1SLars-Peter Clausen 	if (component->debugfs_prefix) {
30681c7cfd1SLars-Peter Clausen 		char *name;
307e73f3de5SRussell King 
30881c7cfd1SLars-Peter Clausen 		name = kasprintf(GFP_KERNEL, "%s:%s",
30981c7cfd1SLars-Peter Clausen 			component->debugfs_prefix, component->name);
31081c7cfd1SLars-Peter Clausen 		if (name) {
31181c7cfd1SLars-Peter Clausen 			component->debugfs_root = debugfs_create_dir(name,
31281c7cfd1SLars-Peter Clausen 				component->card->debugfs_card_root);
31381c7cfd1SLars-Peter Clausen 			kfree(name);
31481c7cfd1SLars-Peter Clausen 		}
31581c7cfd1SLars-Peter Clausen 	} else {
31681c7cfd1SLars-Peter Clausen 		component->debugfs_root = debugfs_create_dir(component->name,
31781c7cfd1SLars-Peter Clausen 				component->card->debugfs_card_root);
318e73f3de5SRussell King 	}
319e73f3de5SRussell King 
32081c7cfd1SLars-Peter Clausen 	if (!component->debugfs_root) {
32181c7cfd1SLars-Peter Clausen 		dev_warn(component->dev,
32281c7cfd1SLars-Peter Clausen 			"ASoC: Failed to create component debugfs directory\n");
3232624d5faSMark Brown 		return;
3242624d5faSMark Brown 	}
3252624d5faSMark Brown 
32681c7cfd1SLars-Peter Clausen 	snd_soc_dapm_debugfs_init(snd_soc_component_get_dapm(component),
32781c7cfd1SLars-Peter Clausen 		component->debugfs_root);
32881c7cfd1SLars-Peter Clausen 
32981c7cfd1SLars-Peter Clausen 	if (component->init_debugfs)
33081c7cfd1SLars-Peter Clausen 		component->init_debugfs(component);
33181c7cfd1SLars-Peter Clausen }
33281c7cfd1SLars-Peter Clausen 
33381c7cfd1SLars-Peter Clausen static void soc_cleanup_component_debugfs(struct snd_soc_component *component)
33481c7cfd1SLars-Peter Clausen {
33581c7cfd1SLars-Peter Clausen 	debugfs_remove_recursive(component->debugfs_root);
33681c7cfd1SLars-Peter Clausen }
33781c7cfd1SLars-Peter Clausen 
33881c7cfd1SLars-Peter Clausen static void soc_init_codec_debugfs(struct snd_soc_component *component)
33981c7cfd1SLars-Peter Clausen {
34081c7cfd1SLars-Peter Clausen 	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
341353c64ddSFabio Estevam 	struct dentry *debugfs_reg;
34281c7cfd1SLars-Peter Clausen 
343353c64ddSFabio Estevam 	debugfs_reg = debugfs_create_file("codec_reg", 0644,
34481c7cfd1SLars-Peter Clausen 					  codec->component.debugfs_root,
3452624d5faSMark Brown 					  codec, &codec_reg_fops);
346353c64ddSFabio Estevam 	if (!debugfs_reg)
34710e8aa9aSMichał Mirosław 		dev_warn(codec->dev,
34810e8aa9aSMichał Mirosław 			"ASoC: Failed to create codec register debugfs file\n");
349731f1ab2SSebastien Guiriec }
350731f1ab2SSebastien Guiriec 
351c15b2a1dSPeng Donglin static int codec_list_show(struct seq_file *m, void *v)
352c3c5a19aSMark Brown {
353c3c5a19aSMark Brown 	struct snd_soc_codec *codec;
354c3c5a19aSMark Brown 
35534e81ab4SLars-Peter Clausen 	mutex_lock(&client_mutex);
35634e81ab4SLars-Peter Clausen 
357700c17caSDonglin Peng 	list_for_each_entry(codec, &codec_list, list)
358700c17caSDonglin Peng 		seq_printf(m, "%s\n", codec->component.name);
359c3c5a19aSMark Brown 
36034e81ab4SLars-Peter Clausen 	mutex_unlock(&client_mutex);
36134e81ab4SLars-Peter Clausen 
362700c17caSDonglin Peng 	return 0;
363700c17caSDonglin Peng }
364c15b2a1dSPeng Donglin DEFINE_SHOW_ATTRIBUTE(codec_list);
365c3c5a19aSMark Brown 
366c15b2a1dSPeng Donglin static int dai_list_show(struct seq_file *m, void *v)
367f3208780SMark Brown {
3681438c2f6SLars-Peter Clausen 	struct snd_soc_component *component;
369f3208780SMark Brown 	struct snd_soc_dai *dai;
370f3208780SMark Brown 
37134e81ab4SLars-Peter Clausen 	mutex_lock(&client_mutex);
37234e81ab4SLars-Peter Clausen 
373700c17caSDonglin Peng 	list_for_each_entry(component, &component_list, list)
374700c17caSDonglin Peng 		list_for_each_entry(dai, &component->dai_list, list)
375700c17caSDonglin Peng 			seq_printf(m, "%s\n", dai->name);
376f3208780SMark Brown 
37734e81ab4SLars-Peter Clausen 	mutex_unlock(&client_mutex);
37834e81ab4SLars-Peter Clausen 
379700c17caSDonglin Peng 	return 0;
380700c17caSDonglin Peng }
381c15b2a1dSPeng Donglin DEFINE_SHOW_ATTRIBUTE(dai_list);
382f3208780SMark Brown 
383a6052154SJarkko Nikula static void soc_init_card_debugfs(struct snd_soc_card *card)
384a6052154SJarkko Nikula {
3856553bf06SLars-Peter Clausen 	if (!snd_soc_debugfs_root)
3866553bf06SLars-Peter Clausen 		return;
3876553bf06SLars-Peter Clausen 
388a6052154SJarkko Nikula 	card->debugfs_card_root = debugfs_create_dir(card->name,
3898a9dab1aSMark Brown 						     snd_soc_debugfs_root);
3903a45b867SJarkko Nikula 	if (!card->debugfs_card_root) {
391a6052154SJarkko Nikula 		dev_warn(card->dev,
3927c08be84SLothar Waßmann 			 "ASoC: Failed to create card debugfs directory\n");
3933a45b867SJarkko Nikula 		return;
3943a45b867SJarkko Nikula 	}
3953a45b867SJarkko Nikula 
3963a45b867SJarkko Nikula 	card->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0644,
3973a45b867SJarkko Nikula 						    card->debugfs_card_root,
3983a45b867SJarkko Nikula 						    &card->pop_time);
3993a45b867SJarkko Nikula 	if (!card->debugfs_pop_time)
4003a45b867SJarkko Nikula 		dev_warn(card->dev,
401f110bfc7SLiam Girdwood 		       "ASoC: Failed to create pop time debugfs file\n");
402a6052154SJarkko Nikula }
403a6052154SJarkko Nikula 
404a6052154SJarkko Nikula static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
405a6052154SJarkko Nikula {
406a6052154SJarkko Nikula 	debugfs_remove_recursive(card->debugfs_card_root);
407a6052154SJarkko Nikula }
408a6052154SJarkko Nikula 
4096553bf06SLars-Peter Clausen static void snd_soc_debugfs_init(void)
4106553bf06SLars-Peter Clausen {
4116553bf06SLars-Peter Clausen 	snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL);
412d9a02c55SFabio Estevam 	if (IS_ERR_OR_NULL(snd_soc_debugfs_root)) {
4136553bf06SLars-Peter Clausen 		pr_warn("ASoC: Failed to create debugfs directory\n");
4146553bf06SLars-Peter Clausen 		snd_soc_debugfs_root = NULL;
4156553bf06SLars-Peter Clausen 		return;
4166553bf06SLars-Peter Clausen 	}
4176553bf06SLars-Peter Clausen 
4186553bf06SLars-Peter Clausen 	if (!debugfs_create_file("codecs", 0444, snd_soc_debugfs_root, NULL,
4196553bf06SLars-Peter Clausen 				 &codec_list_fops))
4206553bf06SLars-Peter Clausen 		pr_warn("ASoC: Failed to create CODEC list debugfs file\n");
4216553bf06SLars-Peter Clausen 
4226553bf06SLars-Peter Clausen 	if (!debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL,
4236553bf06SLars-Peter Clausen 				 &dai_list_fops))
4246553bf06SLars-Peter Clausen 		pr_warn("ASoC: Failed to create DAI list debugfs file\n");
4256553bf06SLars-Peter Clausen }
4266553bf06SLars-Peter Clausen 
4276553bf06SLars-Peter Clausen static void snd_soc_debugfs_exit(void)
4286553bf06SLars-Peter Clausen {
4296553bf06SLars-Peter Clausen 	debugfs_remove_recursive(snd_soc_debugfs_root);
4306553bf06SLars-Peter Clausen }
4316553bf06SLars-Peter Clausen 
4322624d5faSMark Brown #else
4332624d5faSMark Brown 
43481c7cfd1SLars-Peter Clausen #define soc_init_codec_debugfs NULL
43581c7cfd1SLars-Peter Clausen 
43681c7cfd1SLars-Peter Clausen static inline void soc_init_component_debugfs(
43781c7cfd1SLars-Peter Clausen 	struct snd_soc_component *component)
4382624d5faSMark Brown {
4392624d5faSMark Brown }
4402624d5faSMark Brown 
44181c7cfd1SLars-Peter Clausen static inline void soc_cleanup_component_debugfs(
44281c7cfd1SLars-Peter Clausen 	struct snd_soc_component *component)
443731f1ab2SSebastien Guiriec {
444731f1ab2SSebastien Guiriec }
445731f1ab2SSebastien Guiriec 
446b95fccbcSAxel Lin static inline void soc_init_card_debugfs(struct snd_soc_card *card)
447b95fccbcSAxel Lin {
448b95fccbcSAxel Lin }
449b95fccbcSAxel Lin 
450b95fccbcSAxel Lin static inline void soc_cleanup_card_debugfs(struct snd_soc_card *card)
451b95fccbcSAxel Lin {
452b95fccbcSAxel Lin }
4536553bf06SLars-Peter Clausen 
4546553bf06SLars-Peter Clausen static inline void snd_soc_debugfs_init(void)
4556553bf06SLars-Peter Clausen {
4566553bf06SLars-Peter Clausen }
4576553bf06SLars-Peter Clausen 
4586553bf06SLars-Peter Clausen static inline void snd_soc_debugfs_exit(void)
4596553bf06SLars-Peter Clausen {
4606553bf06SLars-Peter Clausen }
4616553bf06SLars-Peter Clausen 
4622624d5faSMark Brown #endif
4632624d5faSMark Brown 
464a0ac4411SKuninori Morimoto static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd,
465a0ac4411SKuninori Morimoto 			      struct snd_soc_component *component)
466a0ac4411SKuninori Morimoto {
467a0ac4411SKuninori Morimoto 	struct snd_soc_rtdcom_list *rtdcom;
468a0ac4411SKuninori Morimoto 	struct snd_soc_rtdcom_list *new_rtdcom;
469a0ac4411SKuninori Morimoto 
470a0ac4411SKuninori Morimoto 	for_each_rtdcom(rtd, rtdcom) {
471a0ac4411SKuninori Morimoto 		/* already connected */
472a0ac4411SKuninori Morimoto 		if (rtdcom->component == component)
473a0ac4411SKuninori Morimoto 			return 0;
474a0ac4411SKuninori Morimoto 	}
475a0ac4411SKuninori Morimoto 
476a0ac4411SKuninori Morimoto 	new_rtdcom = kmalloc(sizeof(*new_rtdcom), GFP_KERNEL);
477a0ac4411SKuninori Morimoto 	if (!new_rtdcom)
478a0ac4411SKuninori Morimoto 		return -ENOMEM;
479a0ac4411SKuninori Morimoto 
480a0ac4411SKuninori Morimoto 	new_rtdcom->component = component;
481a0ac4411SKuninori Morimoto 	INIT_LIST_HEAD(&new_rtdcom->list);
482a0ac4411SKuninori Morimoto 
483a0ac4411SKuninori Morimoto 	list_add_tail(&new_rtdcom->list, &rtd->component_list);
484a0ac4411SKuninori Morimoto 
485a0ac4411SKuninori Morimoto 	return 0;
486a0ac4411SKuninori Morimoto }
487a0ac4411SKuninori Morimoto 
488a0ac4411SKuninori Morimoto static void snd_soc_rtdcom_del_all(struct snd_soc_pcm_runtime *rtd)
489a0ac4411SKuninori Morimoto {
490a0ac4411SKuninori Morimoto 	struct snd_soc_rtdcom_list *rtdcom1, *rtdcom2;
491a0ac4411SKuninori Morimoto 
492a0ac4411SKuninori Morimoto 	for_each_rtdcom_safe(rtd, rtdcom1, rtdcom2)
493a0ac4411SKuninori Morimoto 		kfree(rtdcom1);
494a0ac4411SKuninori Morimoto 
495a0ac4411SKuninori Morimoto 	INIT_LIST_HEAD(&rtd->component_list);
496a0ac4411SKuninori Morimoto }
497a0ac4411SKuninori Morimoto 
498a0ac4411SKuninori Morimoto struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd,
499a0ac4411SKuninori Morimoto 						const char *driver_name)
500a0ac4411SKuninori Morimoto {
501a0ac4411SKuninori Morimoto 	struct snd_soc_rtdcom_list *rtdcom;
502a0ac4411SKuninori Morimoto 
503971da24cSKuninori Morimoto 	if (!driver_name)
504971da24cSKuninori Morimoto 		return NULL;
505971da24cSKuninori Morimoto 
506a0ac4411SKuninori Morimoto 	for_each_rtdcom(rtd, rtdcom) {
507971da24cSKuninori Morimoto 		const char *component_name = rtdcom->component->driver->name;
508971da24cSKuninori Morimoto 
509971da24cSKuninori Morimoto 		if (!component_name)
510971da24cSKuninori Morimoto 			continue;
511971da24cSKuninori Morimoto 
512971da24cSKuninori Morimoto 		if ((component_name == driver_name) ||
513971da24cSKuninori Morimoto 		    strcmp(component_name, driver_name) == 0)
514a0ac4411SKuninori Morimoto 			return rtdcom->component;
515a0ac4411SKuninori Morimoto 	}
516a0ac4411SKuninori Morimoto 
517a0ac4411SKuninori Morimoto 	return NULL;
518a0ac4411SKuninori Morimoto }
519031734b7SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_rtdcom_lookup);
520a0ac4411SKuninori Morimoto 
52147c88fffSLiam Girdwood struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
52247c88fffSLiam Girdwood 		const char *dai_link, int stream)
52347c88fffSLiam Girdwood {
5241a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
52547c88fffSLiam Girdwood 
5261a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
5271a497983SMengdong Lin 		if (rtd->dai_link->no_pcm &&
5281a497983SMengdong Lin 			!strcmp(rtd->dai_link->name, dai_link))
5291a497983SMengdong Lin 			return rtd->pcm->streams[stream].substream;
53047c88fffSLiam Girdwood 	}
531f110bfc7SLiam Girdwood 	dev_dbg(card->dev, "ASoC: failed to find dai link %s\n", dai_link);
53247c88fffSLiam Girdwood 	return NULL;
53347c88fffSLiam Girdwood }
53447c88fffSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream);
53547c88fffSLiam Girdwood 
53675ab9eb6SKuninori Morimoto static const struct snd_soc_ops null_snd_soc_ops;
53775ab9eb6SKuninori Morimoto 
5381a497983SMengdong Lin static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
5391a497983SMengdong Lin 	struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
5401a497983SMengdong Lin {
5411a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
5421a497983SMengdong Lin 
5431a497983SMengdong Lin 	rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL);
5441a497983SMengdong Lin 	if (!rtd)
5451a497983SMengdong Lin 		return NULL;
5461a497983SMengdong Lin 
547a0ac4411SKuninori Morimoto 	INIT_LIST_HEAD(&rtd->component_list);
5481a497983SMengdong Lin 	rtd->card = card;
5491a497983SMengdong Lin 	rtd->dai_link = dai_link;
55075ab9eb6SKuninori Morimoto 	if (!rtd->dai_link->ops)
55175ab9eb6SKuninori Morimoto 		rtd->dai_link->ops = &null_snd_soc_ops;
55275ab9eb6SKuninori Morimoto 
5531a497983SMengdong Lin 	rtd->codec_dais = kzalloc(sizeof(struct snd_soc_dai *) *
5541a497983SMengdong Lin 					dai_link->num_codecs,
5551a497983SMengdong Lin 					GFP_KERNEL);
5561a497983SMengdong Lin 	if (!rtd->codec_dais) {
5571a497983SMengdong Lin 		kfree(rtd);
5581a497983SMengdong Lin 		return NULL;
5591a497983SMengdong Lin 	}
5601a497983SMengdong Lin 
5611a497983SMengdong Lin 	return rtd;
5621a497983SMengdong Lin }
5631a497983SMengdong Lin 
5641a497983SMengdong Lin static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd)
5651a497983SMengdong Lin {
5661a497983SMengdong Lin 	kfree(rtd->codec_dais);
567a0ac4411SKuninori Morimoto 	snd_soc_rtdcom_del_all(rtd);
5681a497983SMengdong Lin 	kfree(rtd);
5691a497983SMengdong Lin }
5701a497983SMengdong Lin 
5711a497983SMengdong Lin static void soc_add_pcm_runtime(struct snd_soc_card *card,
5721a497983SMengdong Lin 		struct snd_soc_pcm_runtime *rtd)
5731a497983SMengdong Lin {
5741a497983SMengdong Lin 	list_add_tail(&rtd->list, &card->rtd_list);
5751a497983SMengdong Lin 	rtd->num = card->num_rtd;
5761a497983SMengdong Lin 	card->num_rtd++;
5771a497983SMengdong Lin }
5781a497983SMengdong Lin 
5791a497983SMengdong Lin static void soc_remove_pcm_runtimes(struct snd_soc_card *card)
5801a497983SMengdong Lin {
5811a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd, *_rtd;
5821a497983SMengdong Lin 
5831a497983SMengdong Lin 	list_for_each_entry_safe(rtd, _rtd, &card->rtd_list, list) {
5841a497983SMengdong Lin 		list_del(&rtd->list);
5851a497983SMengdong Lin 		soc_free_pcm_runtime(rtd);
5861a497983SMengdong Lin 	}
5871a497983SMengdong Lin 
5881a497983SMengdong Lin 	card->num_rtd = 0;
5891a497983SMengdong Lin }
5901a497983SMengdong Lin 
59147c88fffSLiam Girdwood struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
59247c88fffSLiam Girdwood 		const char *dai_link)
59347c88fffSLiam Girdwood {
5941a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
59547c88fffSLiam Girdwood 
5961a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
5971a497983SMengdong Lin 		if (!strcmp(rtd->dai_link->name, dai_link))
5981a497983SMengdong Lin 			return rtd;
59947c88fffSLiam Girdwood 	}
600f110bfc7SLiam Girdwood 	dev_dbg(card->dev, "ASoC: failed to find rtd %s\n", dai_link);
60147c88fffSLiam Girdwood 	return NULL;
60247c88fffSLiam Girdwood }
60347c88fffSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime);
60447c88fffSLiam Girdwood 
6059d58a077SRichard Fitzgerald static void codec2codec_close_delayed_work(struct work_struct *work)
6069d58a077SRichard Fitzgerald {
6079d58a077SRichard Fitzgerald 	/* Currently nothing to do for c2c links
6089d58a077SRichard Fitzgerald 	 * Since c2c links are internal nodes in the DAPM graph and
6099d58a077SRichard Fitzgerald 	 * don't interface with the outside world or application layer
6109d58a077SRichard Fitzgerald 	 * we don't have to do any special handling on close.
6119d58a077SRichard Fitzgerald 	 */
6129d58a077SRichard Fitzgerald }
6139d58a077SRichard Fitzgerald 
6146f8ab4acSMark Brown #ifdef CONFIG_PM_SLEEP
615db2a4165SFrank Mandarino /* powers down audio subsystem for suspend */
6166f8ab4acSMark Brown int snd_soc_suspend(struct device *dev)
617db2a4165SFrank Mandarino {
6186f8ab4acSMark Brown 	struct snd_soc_card *card = dev_get_drvdata(dev);
619d9fc4063SKuninori Morimoto 	struct snd_soc_component *component;
6201a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
6211a497983SMengdong Lin 	int i;
622db2a4165SFrank Mandarino 
623c5599b87SLars-Peter Clausen 	/* If the card is not initialized yet there is nothing to do */
624c5599b87SLars-Peter Clausen 	if (!card->instantiated)
625e3509ff0SDaniel Mack 		return 0;
626e3509ff0SDaniel Mack 
6276ed25978SAndy Green 	/* Due to the resume being scheduled into a workqueue we could
6286ed25978SAndy Green 	* suspend before that's finished - wait for it to complete.
6296ed25978SAndy Green 	 */
630f0fba2adSLiam Girdwood 	snd_power_wait(card->snd_card, SNDRV_CTL_POWER_D0);
6316ed25978SAndy Green 
6326ed25978SAndy Green 	/* we're going to block userspace touching us until resume completes */
633f0fba2adSLiam Girdwood 	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
6346ed25978SAndy Green 
635a00f90f9SMark Brown 	/* mute any active DACs */
6361a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
6373efab7dcSMark Brown 
6381a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
6393efab7dcSMark Brown 			continue;
6403efab7dcSMark Brown 
6411a497983SMengdong Lin 		for (i = 0; i < rtd->num_codecs; i++) {
6421a497983SMengdong Lin 			struct snd_soc_dai *dai = rtd->codec_dais[i];
64388bd870fSBenoit Cousson 			struct snd_soc_dai_driver *drv = dai->driver;
64488bd870fSBenoit Cousson 
645f0fba2adSLiam Girdwood 			if (drv->ops->digital_mute && dai->playback_active)
646f0fba2adSLiam Girdwood 				drv->ops->digital_mute(dai, 1);
647db2a4165SFrank Mandarino 		}
64888bd870fSBenoit Cousson 	}
649db2a4165SFrank Mandarino 
6504ccab3e7SLiam Girdwood 	/* suspend all pcms */
6511a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
6521a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
6533efab7dcSMark Brown 			continue;
6543efab7dcSMark Brown 
6551a497983SMengdong Lin 		snd_pcm_suspend_all(rtd->pcm);
6563efab7dcSMark Brown 	}
6574ccab3e7SLiam Girdwood 
65887506549SMark Brown 	if (card->suspend_pre)
65970b2ac12SMark Brown 		card->suspend_pre(card);
660db2a4165SFrank Mandarino 
6611a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
6621a497983SMengdong Lin 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
6633efab7dcSMark Brown 
6641a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
6653efab7dcSMark Brown 			continue;
6663efab7dcSMark Brown 
667bc263214SLars-Peter Clausen 		if (cpu_dai->driver->suspend && !cpu_dai->driver->bus_control)
668f0fba2adSLiam Girdwood 			cpu_dai->driver->suspend(cpu_dai);
669db2a4165SFrank Mandarino 	}
670db2a4165SFrank Mandarino 
67137660b6dSLars-Peter Clausen 	/* close any waiting streams */
6721a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list)
6731a497983SMengdong Lin 		flush_delayed_work(&rtd->delayed_work);
674db2a4165SFrank Mandarino 
6751a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
6763efab7dcSMark Brown 
6771a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
6783efab7dcSMark Brown 			continue;
6793efab7dcSMark Brown 
6801a497983SMengdong Lin 		snd_soc_dapm_stream_event(rtd,
6817bd3a6f3SMark Brown 					  SNDRV_PCM_STREAM_PLAYBACK,
682db2a4165SFrank Mandarino 					  SND_SOC_DAPM_STREAM_SUSPEND);
683f0fba2adSLiam Girdwood 
6841a497983SMengdong Lin 		snd_soc_dapm_stream_event(rtd,
6857bd3a6f3SMark Brown 					  SNDRV_PCM_STREAM_CAPTURE,
686db2a4165SFrank Mandarino 					  SND_SOC_DAPM_STREAM_SUSPEND);
687db2a4165SFrank Mandarino 	}
688db2a4165SFrank Mandarino 
6898be4da29SLars-Peter Clausen 	/* Recheck all endpoints too, their state is affected by suspend */
6908be4da29SLars-Peter Clausen 	dapm_mark_endpoints_dirty(card);
691e2d32ff6SMark Brown 	snd_soc_dapm_sync(&card->dapm);
692e2d32ff6SMark Brown 
6939178feb4SKuninori Morimoto 	/* suspend all COMPONENTs */
694d9fc4063SKuninori Morimoto 	list_for_each_entry(component, &card->component_dev_list, card_list) {
695d9fc4063SKuninori Morimoto 		struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
696d9fc4063SKuninori Morimoto 
6979178feb4SKuninori Morimoto 		/* If there are paths active then the COMPONENT will be held with
6981547aba9SMark Brown 		 * bias _ON and should not be suspended. */
6999178feb4SKuninori Morimoto 		if (!component->suspended) {
7004890140fSLars-Peter Clausen 			switch (snd_soc_dapm_get_bias_level(dapm)) {
7011547aba9SMark Brown 			case SND_SOC_BIAS_STANDBY:
702125a25daSMark Brown 				/*
7039178feb4SKuninori Morimoto 				 * If the COMPONENT is capable of idle
704125a25daSMark Brown 				 * bias off then being in STANDBY
705125a25daSMark Brown 				 * means it's doing something,
706125a25daSMark Brown 				 * otherwise fall through.
707125a25daSMark Brown 				 */
7084890140fSLars-Peter Clausen 				if (dapm->idle_bias_off) {
7099178feb4SKuninori Morimoto 					dev_dbg(component->dev,
71010e8aa9aSMichał Mirosław 						"ASoC: idle_bias_off CODEC on over suspend\n");
711125a25daSMark Brown 					break;
712125a25daSMark Brown 				}
713a8093297SLars-Peter Clausen 
7141547aba9SMark Brown 			case SND_SOC_BIAS_OFF:
7159178feb4SKuninori Morimoto 				if (component->suspend)
7169178feb4SKuninori Morimoto 					component->suspend(component);
7179178feb4SKuninori Morimoto 				component->suspended = 1;
7189178feb4SKuninori Morimoto 				if (component->regmap)
7199178feb4SKuninori Morimoto 					regcache_mark_dirty(component->regmap);
720988e8cc4SNicolin Chen 				/* deactivate pins to sleep state */
7219178feb4SKuninori Morimoto 				pinctrl_pm_select_sleep_state(component->dev);
7221547aba9SMark Brown 				break;
7231547aba9SMark Brown 			default:
7249178feb4SKuninori Morimoto 				dev_dbg(component->dev,
7259178feb4SKuninori Morimoto 					"ASoC: COMPONENT is on over suspend\n");
7261547aba9SMark Brown 				break;
7271547aba9SMark Brown 			}
7281547aba9SMark Brown 		}
729f0fba2adSLiam Girdwood 	}
730db2a4165SFrank Mandarino 
7311a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
7321a497983SMengdong Lin 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
7333efab7dcSMark Brown 
7341a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
7353efab7dcSMark Brown 			continue;
7363efab7dcSMark Brown 
737bc263214SLars-Peter Clausen 		if (cpu_dai->driver->suspend && cpu_dai->driver->bus_control)
738f0fba2adSLiam Girdwood 			cpu_dai->driver->suspend(cpu_dai);
739988e8cc4SNicolin Chen 
740988e8cc4SNicolin Chen 		/* deactivate pins to sleep state */
741988e8cc4SNicolin Chen 		pinctrl_pm_select_sleep_state(cpu_dai->dev);
742db2a4165SFrank Mandarino 	}
743db2a4165SFrank Mandarino 
74487506549SMark Brown 	if (card->suspend_post)
74570b2ac12SMark Brown 		card->suspend_post(card);
746db2a4165SFrank Mandarino 
747db2a4165SFrank Mandarino 	return 0;
748db2a4165SFrank Mandarino }
7496f8ab4acSMark Brown EXPORT_SYMBOL_GPL(snd_soc_suspend);
750db2a4165SFrank Mandarino 
7516ed25978SAndy Green /* deferred resume work, so resume can complete before we finished
7526ed25978SAndy Green  * setting our codec back up, which can be very slow on I2C
7536ed25978SAndy Green  */
7546ed25978SAndy Green static void soc_resume_deferred(struct work_struct *work)
755db2a4165SFrank Mandarino {
756f0fba2adSLiam Girdwood 	struct snd_soc_card *card =
757f0fba2adSLiam Girdwood 			container_of(work, struct snd_soc_card, deferred_resume_work);
7581a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
759d9fc4063SKuninori Morimoto 	struct snd_soc_component *component;
7601a497983SMengdong Lin 	int i;
761db2a4165SFrank Mandarino 
7626ed25978SAndy Green 	/* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
7636ed25978SAndy Green 	 * so userspace apps are blocked from touching us
7646ed25978SAndy Green 	 */
7656ed25978SAndy Green 
766f110bfc7SLiam Girdwood 	dev_dbg(card->dev, "ASoC: starting resume work\n");
7676ed25978SAndy Green 
7689949788bSMark Brown 	/* Bring us up into D2 so that DAPM starts enabling things */
769f0fba2adSLiam Girdwood 	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D2);
7709949788bSMark Brown 
77187506549SMark Brown 	if (card->resume_pre)
77270b2ac12SMark Brown 		card->resume_pre(card);
773db2a4165SFrank Mandarino 
774bc263214SLars-Peter Clausen 	/* resume control bus DAIs */
7751a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
7761a497983SMengdong Lin 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
7773efab7dcSMark Brown 
7781a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
7793efab7dcSMark Brown 			continue;
7803efab7dcSMark Brown 
781bc263214SLars-Peter Clausen 		if (cpu_dai->driver->resume && cpu_dai->driver->bus_control)
782f0fba2adSLiam Girdwood 			cpu_dai->driver->resume(cpu_dai);
783db2a4165SFrank Mandarino 	}
784db2a4165SFrank Mandarino 
785d9fc4063SKuninori Morimoto 	list_for_each_entry(component, &card->component_dev_list, card_list) {
7869178feb4SKuninori Morimoto 		if (component->suspended) {
7879178feb4SKuninori Morimoto 			if (component->resume)
7889178feb4SKuninori Morimoto 				component->resume(component);
7899178feb4SKuninori Morimoto 			component->suspended = 0;
7901547aba9SMark Brown 		}
791f0fba2adSLiam Girdwood 	}
792db2a4165SFrank Mandarino 
7931a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
7943efab7dcSMark Brown 
7951a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
7963efab7dcSMark Brown 			continue;
7973efab7dcSMark Brown 
7981a497983SMengdong Lin 		snd_soc_dapm_stream_event(rtd,
799d9b0951bSLiam Girdwood 					  SNDRV_PCM_STREAM_PLAYBACK,
800db2a4165SFrank Mandarino 					  SND_SOC_DAPM_STREAM_RESUME);
801f0fba2adSLiam Girdwood 
8021a497983SMengdong Lin 		snd_soc_dapm_stream_event(rtd,
803d9b0951bSLiam Girdwood 					  SNDRV_PCM_STREAM_CAPTURE,
804db2a4165SFrank Mandarino 					  SND_SOC_DAPM_STREAM_RESUME);
805db2a4165SFrank Mandarino 	}
806db2a4165SFrank Mandarino 
8073ff3f64bSMark Brown 	/* unmute any active DACs */
8081a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
8093efab7dcSMark Brown 
8101a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
8113efab7dcSMark Brown 			continue;
8123efab7dcSMark Brown 
8131a497983SMengdong Lin 		for (i = 0; i < rtd->num_codecs; i++) {
8141a497983SMengdong Lin 			struct snd_soc_dai *dai = rtd->codec_dais[i];
81588bd870fSBenoit Cousson 			struct snd_soc_dai_driver *drv = dai->driver;
81688bd870fSBenoit Cousson 
817f0fba2adSLiam Girdwood 			if (drv->ops->digital_mute && dai->playback_active)
818f0fba2adSLiam Girdwood 				drv->ops->digital_mute(dai, 0);
819db2a4165SFrank Mandarino 		}
82088bd870fSBenoit Cousson 	}
821db2a4165SFrank Mandarino 
8221a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
8231a497983SMengdong Lin 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
8243efab7dcSMark Brown 
8251a497983SMengdong Lin 		if (rtd->dai_link->ignore_suspend)
8263efab7dcSMark Brown 			continue;
8273efab7dcSMark Brown 
828bc263214SLars-Peter Clausen 		if (cpu_dai->driver->resume && !cpu_dai->driver->bus_control)
829f0fba2adSLiam Girdwood 			cpu_dai->driver->resume(cpu_dai);
830db2a4165SFrank Mandarino 	}
831db2a4165SFrank Mandarino 
83287506549SMark Brown 	if (card->resume_post)
83370b2ac12SMark Brown 		card->resume_post(card);
834db2a4165SFrank Mandarino 
835f110bfc7SLiam Girdwood 	dev_dbg(card->dev, "ASoC: resume work completed\n");
8366ed25978SAndy Green 
8378be4da29SLars-Peter Clausen 	/* Recheck all endpoints too, their state is affected by suspend */
8388be4da29SLars-Peter Clausen 	dapm_mark_endpoints_dirty(card);
839e2d32ff6SMark Brown 	snd_soc_dapm_sync(&card->dapm);
8401a7aaa58SJeeja KP 
8411a7aaa58SJeeja KP 	/* userspace can access us now we are back as we were before */
8421a7aaa58SJeeja KP 	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0);
8436ed25978SAndy Green }
8446ed25978SAndy Green 
8456ed25978SAndy Green /* powers up audio subsystem after a suspend */
8466f8ab4acSMark Brown int snd_soc_resume(struct device *dev)
8476ed25978SAndy Green {
8486f8ab4acSMark Brown 	struct snd_soc_card *card = dev_get_drvdata(dev);
849bc263214SLars-Peter Clausen 	bool bus_control = false;
8501a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
851b9dd94a8SPeter Ujfalusi 
852c5599b87SLars-Peter Clausen 	/* If the card is not initialized yet there is nothing to do */
853c5599b87SLars-Peter Clausen 	if (!card->instantiated)
8545ff1ddf2SEric Miao 		return 0;
8555ff1ddf2SEric Miao 
856988e8cc4SNicolin Chen 	/* activate pins from sleep state */
8571a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
85888bd870fSBenoit Cousson 		struct snd_soc_dai **codec_dais = rtd->codec_dais;
85988bd870fSBenoit Cousson 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
86088bd870fSBenoit Cousson 		int j;
86188bd870fSBenoit Cousson 
862988e8cc4SNicolin Chen 		if (cpu_dai->active)
863988e8cc4SNicolin Chen 			pinctrl_pm_select_default_state(cpu_dai->dev);
86488bd870fSBenoit Cousson 
86588bd870fSBenoit Cousson 		for (j = 0; j < rtd->num_codecs; j++) {
86688bd870fSBenoit Cousson 			struct snd_soc_dai *codec_dai = codec_dais[j];
867988e8cc4SNicolin Chen 			if (codec_dai->active)
868988e8cc4SNicolin Chen 				pinctrl_pm_select_default_state(codec_dai->dev);
869988e8cc4SNicolin Chen 		}
87088bd870fSBenoit Cousson 	}
871988e8cc4SNicolin Chen 
872bc263214SLars-Peter Clausen 	/*
873bc263214SLars-Peter Clausen 	 * DAIs that also act as the control bus master might have other drivers
874bc263214SLars-Peter Clausen 	 * hanging off them so need to resume immediately. Other drivers don't
875bc263214SLars-Peter Clausen 	 * have that problem and may take a substantial amount of time to resume
87664ab9baaSMark Brown 	 * due to I/O costs and anti-pop so handle them out of line.
87764ab9baaSMark Brown 	 */
8781a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
8791a497983SMengdong Lin 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
880bc263214SLars-Peter Clausen 		bus_control |= cpu_dai->driver->bus_control;
88182e14e8bSStephen Warren 	}
882bc263214SLars-Peter Clausen 	if (bus_control) {
883bc263214SLars-Peter Clausen 		dev_dbg(dev, "ASoC: Resuming control bus master immediately\n");
88464ab9baaSMark Brown 		soc_resume_deferred(&card->deferred_resume_work);
88564ab9baaSMark Brown 	} else {
886f110bfc7SLiam Girdwood 		dev_dbg(dev, "ASoC: Scheduling resume work\n");
8876308419aSMark Brown 		if (!schedule_work(&card->deferred_resume_work))
888f110bfc7SLiam Girdwood 			dev_err(dev, "ASoC: resume work item may be lost\n");
889f0fba2adSLiam Girdwood 	}
8906ed25978SAndy Green 
891db2a4165SFrank Mandarino 	return 0;
892db2a4165SFrank Mandarino }
8936f8ab4acSMark Brown EXPORT_SYMBOL_GPL(snd_soc_resume);
894db2a4165SFrank Mandarino #else
8956f8ab4acSMark Brown #define snd_soc_suspend NULL
8966f8ab4acSMark Brown #define snd_soc_resume NULL
897db2a4165SFrank Mandarino #endif
898db2a4165SFrank Mandarino 
89985e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops null_dai_ops = {
90002a06d30SBarry Song };
90102a06d30SBarry Song 
90265d9361fSLars-Peter Clausen static struct snd_soc_component *soc_find_component(
90365d9361fSLars-Peter Clausen 	const struct device_node *of_node, const char *name)
90412023a9aSMisael Lopez Cruz {
90565d9361fSLars-Peter Clausen 	struct snd_soc_component *component;
90612023a9aSMisael Lopez Cruz 
90734e81ab4SLars-Peter Clausen 	lockdep_assert_held(&client_mutex);
90834e81ab4SLars-Peter Clausen 
90965d9361fSLars-Peter Clausen 	list_for_each_entry(component, &component_list, list) {
91065d9361fSLars-Peter Clausen 		if (of_node) {
91165d9361fSLars-Peter Clausen 			if (component->dev->of_node == of_node)
91265d9361fSLars-Peter Clausen 				return component;
91365d9361fSLars-Peter Clausen 		} else if (strcmp(component->name, name) == 0) {
91465d9361fSLars-Peter Clausen 			return component;
91512023a9aSMisael Lopez Cruz 		}
91612023a9aSMisael Lopez Cruz 	}
91712023a9aSMisael Lopez Cruz 
91812023a9aSMisael Lopez Cruz 	return NULL;
91912023a9aSMisael Lopez Cruz }
92012023a9aSMisael Lopez Cruz 
921fbb88b5cSMengdong Lin /**
922fbb88b5cSMengdong Lin  * snd_soc_find_dai - Find a registered DAI
923fbb88b5cSMengdong Lin  *
9244958471bSJeffy Chen  * @dlc: name of the DAI or the DAI driver and optional component info to match
925fbb88b5cSMengdong Lin  *
926ad61dd30SStephen Boyd  * This function will search all registered components and their DAIs to
927fbb88b5cSMengdong Lin  * find the DAI of the same name. The component's of_node and name
928fbb88b5cSMengdong Lin  * should also match if being specified.
929fbb88b5cSMengdong Lin  *
930fbb88b5cSMengdong Lin  * Return: pointer of DAI, or NULL if not found.
931fbb88b5cSMengdong Lin  */
932305e9020SMengdong Lin struct snd_soc_dai *snd_soc_find_dai(
93314621c7eSLars-Peter Clausen 	const struct snd_soc_dai_link_component *dlc)
93412023a9aSMisael Lopez Cruz {
93514621c7eSLars-Peter Clausen 	struct snd_soc_component *component;
93614621c7eSLars-Peter Clausen 	struct snd_soc_dai *dai;
9373e0aa8d8SJyri Sarha 	struct device_node *component_of_node;
93812023a9aSMisael Lopez Cruz 
93934e81ab4SLars-Peter Clausen 	lockdep_assert_held(&client_mutex);
94034e81ab4SLars-Peter Clausen 
94114621c7eSLars-Peter Clausen 	/* Find CPU DAI from registered DAIs*/
94214621c7eSLars-Peter Clausen 	list_for_each_entry(component, &component_list, list) {
9433e0aa8d8SJyri Sarha 		component_of_node = component->dev->of_node;
9443e0aa8d8SJyri Sarha 		if (!component_of_node && component->dev->parent)
9453e0aa8d8SJyri Sarha 			component_of_node = component->dev->parent->of_node;
9463e0aa8d8SJyri Sarha 
9473e0aa8d8SJyri Sarha 		if (dlc->of_node && component_of_node != dlc->of_node)
94812023a9aSMisael Lopez Cruz 			continue;
9491ffae361SLars-Peter Clausen 		if (dlc->name && strcmp(component->name, dlc->name))
95012023a9aSMisael Lopez Cruz 			continue;
95114621c7eSLars-Peter Clausen 		list_for_each_entry(dai, &component->dai_list, list) {
9524958471bSJeffy Chen 			if (dlc->dai_name && strcmp(dai->name, dlc->dai_name)
9536a6dafdaSJeffy Chen 			    && (!dai->driver->name
9546a6dafdaSJeffy Chen 				|| strcmp(dai->driver->name, dlc->dai_name)))
95514621c7eSLars-Peter Clausen 				continue;
95612023a9aSMisael Lopez Cruz 
95714621c7eSLars-Peter Clausen 			return dai;
95812023a9aSMisael Lopez Cruz 		}
95912023a9aSMisael Lopez Cruz 	}
96012023a9aSMisael Lopez Cruz 
96112023a9aSMisael Lopez Cruz 	return NULL;
96212023a9aSMisael Lopez Cruz }
963305e9020SMengdong Lin EXPORT_SYMBOL_GPL(snd_soc_find_dai);
96412023a9aSMisael Lopez Cruz 
96517fb1755SMengdong Lin 
96617fb1755SMengdong Lin /**
96717fb1755SMengdong Lin  * snd_soc_find_dai_link - Find a DAI link
96817fb1755SMengdong Lin  *
96917fb1755SMengdong Lin  * @card: soc card
97017fb1755SMengdong Lin  * @id: DAI link ID to match
97117fb1755SMengdong Lin  * @name: DAI link name to match, optional
9728abab35fSCharles Keepax  * @stream_name: DAI link stream name to match, optional
97317fb1755SMengdong Lin  *
97417fb1755SMengdong Lin  * This function will search all existing DAI links of the soc card to
97517fb1755SMengdong Lin  * find the link of the same ID. Since DAI links may not have their
97617fb1755SMengdong Lin  * unique ID, so name and stream name should also match if being
97717fb1755SMengdong Lin  * specified.
97817fb1755SMengdong Lin  *
97917fb1755SMengdong Lin  * Return: pointer of DAI link, or NULL if not found.
98017fb1755SMengdong Lin  */
98117fb1755SMengdong Lin struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card,
98217fb1755SMengdong Lin 					       int id, const char *name,
98317fb1755SMengdong Lin 					       const char *stream_name)
98417fb1755SMengdong Lin {
98517fb1755SMengdong Lin 	struct snd_soc_dai_link *link, *_link;
98617fb1755SMengdong Lin 
98717fb1755SMengdong Lin 	lockdep_assert_held(&client_mutex);
98817fb1755SMengdong Lin 
98917fb1755SMengdong Lin 	list_for_each_entry_safe(link, _link, &card->dai_link_list, list) {
99017fb1755SMengdong Lin 		if (link->id != id)
99117fb1755SMengdong Lin 			continue;
99217fb1755SMengdong Lin 
99317fb1755SMengdong Lin 		if (name && (!link->name || strcmp(name, link->name)))
99417fb1755SMengdong Lin 			continue;
99517fb1755SMengdong Lin 
99617fb1755SMengdong Lin 		if (stream_name && (!link->stream_name
99717fb1755SMengdong Lin 			|| strcmp(stream_name, link->stream_name)))
99817fb1755SMengdong Lin 			continue;
99917fb1755SMengdong Lin 
100017fb1755SMengdong Lin 		return link;
100117fb1755SMengdong Lin 	}
100217fb1755SMengdong Lin 
100317fb1755SMengdong Lin 	return NULL;
100417fb1755SMengdong Lin }
100517fb1755SMengdong Lin EXPORT_SYMBOL_GPL(snd_soc_find_dai_link);
100617fb1755SMengdong Lin 
100749a5ba1cSMengdong Lin static bool soc_is_dai_link_bound(struct snd_soc_card *card,
100849a5ba1cSMengdong Lin 		struct snd_soc_dai_link *dai_link)
1009db2a4165SFrank Mandarino {
101049a5ba1cSMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
101149a5ba1cSMengdong Lin 
101249a5ba1cSMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
101349a5ba1cSMengdong Lin 		if (rtd->dai_link == dai_link)
101449a5ba1cSMengdong Lin 			return true;
101549a5ba1cSMengdong Lin 	}
101649a5ba1cSMengdong Lin 
101749a5ba1cSMengdong Lin 	return false;
101849a5ba1cSMengdong Lin }
101949a5ba1cSMengdong Lin 
10206f2f1ff0SMengdong Lin static int soc_bind_dai_link(struct snd_soc_card *card,
10216f2f1ff0SMengdong Lin 	struct snd_soc_dai_link *dai_link)
1022db2a4165SFrank Mandarino {
10231a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
102488bd870fSBenoit Cousson 	struct snd_soc_dai_link_component *codecs = dai_link->codecs;
102514621c7eSLars-Peter Clausen 	struct snd_soc_dai_link_component cpu_dai_component;
102690be711eSKuninori Morimoto 	struct snd_soc_component *component;
10271a497983SMengdong Lin 	struct snd_soc_dai **codec_dais;
102806859fcaSCharles Keepax 	struct device_node *platform_of_node;
1029848dd8beSMark Brown 	const char *platform_name;
103088bd870fSBenoit Cousson 	int i;
1031db2a4165SFrank Mandarino 
10326f2f1ff0SMengdong Lin 	dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name);
10336308419aSMark Brown 
103449a5ba1cSMengdong Lin 	if (soc_is_dai_link_bound(card, dai_link)) {
103549a5ba1cSMengdong Lin 		dev_dbg(card->dev, "ASoC: dai link %s already bound\n",
103649a5ba1cSMengdong Lin 			dai_link->name);
103749a5ba1cSMengdong Lin 		return 0;
103849a5ba1cSMengdong Lin 	}
1039db2a4165SFrank Mandarino 
1040513cb311SSudip Mukherjee 	rtd = soc_new_pcm_runtime(card, dai_link);
1041513cb311SSudip Mukherjee 	if (!rtd)
1042513cb311SSudip Mukherjee 		return -ENOMEM;
1043513cb311SSudip Mukherjee 
104414621c7eSLars-Peter Clausen 	cpu_dai_component.name = dai_link->cpu_name;
104514621c7eSLars-Peter Clausen 	cpu_dai_component.of_node = dai_link->cpu_of_node;
104614621c7eSLars-Peter Clausen 	cpu_dai_component.dai_name = dai_link->cpu_dai_name;
104714621c7eSLars-Peter Clausen 	rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component);
1048b19e6e7bSMark Brown 	if (!rtd->cpu_dai) {
10496b490879SMartin Hundebøll 		dev_info(card->dev, "ASoC: CPU DAI %s not registered\n",
1050f0fba2adSLiam Girdwood 			 dai_link->cpu_dai_name);
10511a497983SMengdong Lin 		goto _err_defer;
1052c5af3a2eSMark Brown 	}
105390be711eSKuninori Morimoto 	snd_soc_rtdcom_add(rtd, rtd->cpu_dai->component);
1054c5af3a2eSMark Brown 
105588bd870fSBenoit Cousson 	rtd->num_codecs = dai_link->num_codecs;
105688bd870fSBenoit Cousson 
105788bd870fSBenoit Cousson 	/* Find CODEC from registered CODECs */
10581a497983SMengdong Lin 	codec_dais = rtd->codec_dais;
105988bd870fSBenoit Cousson 	for (i = 0; i < rtd->num_codecs; i++) {
106014621c7eSLars-Peter Clausen 		codec_dais[i] = snd_soc_find_dai(&codecs[i]);
106188bd870fSBenoit Cousson 		if (!codec_dais[i]) {
106212023a9aSMisael Lopez Cruz 			dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n",
106388bd870fSBenoit Cousson 				codecs[i].dai_name);
10641a497983SMengdong Lin 			goto _err_defer;
106512023a9aSMisael Lopez Cruz 		}
106690be711eSKuninori Morimoto 		snd_soc_rtdcom_add(rtd, codec_dais[i]->component);
106788bd870fSBenoit Cousson 	}
106888bd870fSBenoit Cousson 
106988bd870fSBenoit Cousson 	/* Single codec links expect codec and codec_dai in runtime data */
107088bd870fSBenoit Cousson 	rtd->codec_dai = codec_dais[0];
107188bd870fSBenoit Cousson 	rtd->codec = rtd->codec_dai->codec;
107212023a9aSMisael Lopez Cruz 
1073848dd8beSMark Brown 	/* if there's no platform we match on the empty platform */
1074848dd8beSMark Brown 	platform_name = dai_link->platform_name;
10755a504963SStephen Warren 	if (!platform_name && !dai_link->platform_of_node)
1076848dd8beSMark Brown 		platform_name = "snd-soc-dummy";
1077848dd8beSMark Brown 
1078b19e6e7bSMark Brown 	/* find one from the set of registered platforms */
107990be711eSKuninori Morimoto 	list_for_each_entry(component, &component_list, list) {
108090be711eSKuninori Morimoto 		platform_of_node = component->dev->of_node;
108190be711eSKuninori Morimoto 		if (!platform_of_node && component->dev->parent->of_node)
108290be711eSKuninori Morimoto 			platform_of_node = component->dev->parent->of_node;
108390be711eSKuninori Morimoto 
108490be711eSKuninori Morimoto 		if (dai_link->platform_of_node) {
108590be711eSKuninori Morimoto 			if (platform_of_node != dai_link->platform_of_node)
108690be711eSKuninori Morimoto 				continue;
108790be711eSKuninori Morimoto 		} else {
108890be711eSKuninori Morimoto 			if (strcmp(component->name, platform_name))
108990be711eSKuninori Morimoto 				continue;
109090be711eSKuninori Morimoto 		}
109190be711eSKuninori Morimoto 
109290be711eSKuninori Morimoto 		snd_soc_rtdcom_add(rtd, component);
109390be711eSKuninori Morimoto 	}
109490be711eSKuninori Morimoto 
10951a497983SMengdong Lin 	soc_add_pcm_runtime(card, rtd);
1096b19e6e7bSMark Brown 	return 0;
10971a497983SMengdong Lin 
10981a497983SMengdong Lin _err_defer:
10991a497983SMengdong Lin 	soc_free_pcm_runtime(rtd);
11001a497983SMengdong Lin 	return  -EPROBE_DEFER;
11016b05eda6SMark Brown }
11026b05eda6SMark Brown 
1103f1d45cc3SLars-Peter Clausen static void soc_remove_component(struct snd_soc_component *component)
1104d12cd198SStephen Warren {
1105abd31b32SLars-Peter Clausen 	if (!component->card)
110670090bbbSLars-Peter Clausen 		return;
1107d12cd198SStephen Warren 
1108d9fc4063SKuninori Morimoto 	list_del(&component->card_list);
1109d12cd198SStephen Warren 
1110f1d45cc3SLars-Peter Clausen 	if (component->remove)
1111f1d45cc3SLars-Peter Clausen 		component->remove(component);
1112d12cd198SStephen Warren 
1113f1d45cc3SLars-Peter Clausen 	snd_soc_dapm_free(snd_soc_component_get_dapm(component));
1114d12cd198SStephen Warren 
1115f1d45cc3SLars-Peter Clausen 	soc_cleanup_component_debugfs(component);
1116abd31b32SLars-Peter Clausen 	component->card = NULL;
1117f1d45cc3SLars-Peter Clausen 	module_put(component->dev->driver->owner);
1118d12cd198SStephen Warren }
1119d12cd198SStephen Warren 
1120e60cd14fSLars-Peter Clausen static void soc_remove_dai(struct snd_soc_dai *dai, int order)
1121589c3563SJarkko Nikula {
1122589c3563SJarkko Nikula 	int err;
1123589c3563SJarkko Nikula 
1124e60cd14fSLars-Peter Clausen 	if (dai && dai->probed &&
1125e60cd14fSLars-Peter Clausen 			dai->driver->remove_order == order) {
1126e60cd14fSLars-Peter Clausen 		if (dai->driver->remove) {
1127e60cd14fSLars-Peter Clausen 			err = dai->driver->remove(dai);
1128589c3563SJarkko Nikula 			if (err < 0)
1129e60cd14fSLars-Peter Clausen 				dev_err(dai->dev,
1130b0aa88afSMisael Lopez Cruz 					"ASoC: failed to remove %s: %d\n",
1131e60cd14fSLars-Peter Clausen 					dai->name, err);
1132b0aa88afSMisael Lopez Cruz 		}
1133e60cd14fSLars-Peter Clausen 		dai->probed = 0;
1134b0aa88afSMisael Lopez Cruz 	}
1135b0aa88afSMisael Lopez Cruz }
1136b0aa88afSMisael Lopez Cruz 
11371a497983SMengdong Lin static void soc_remove_link_dais(struct snd_soc_card *card,
11381a497983SMengdong Lin 		struct snd_soc_pcm_runtime *rtd, int order)
1139f0fba2adSLiam Girdwood {
1140e60cd14fSLars-Peter Clausen 	int i;
1141f0fba2adSLiam Girdwood 
1142f0fba2adSLiam Girdwood 	/* unregister the rtd device */
1143f0fba2adSLiam Girdwood 	if (rtd->dev_registered) {
114436ae1a96SMark Brown 		device_unregister(rtd->dev);
1145f0fba2adSLiam Girdwood 		rtd->dev_registered = 0;
114602a06d30SBarry Song 	}
114702a06d30SBarry Song 
1148f0fba2adSLiam Girdwood 	/* remove the CODEC DAI */
114988bd870fSBenoit Cousson 	for (i = 0; i < rtd->num_codecs; i++)
1150e60cd14fSLars-Peter Clausen 		soc_remove_dai(rtd->codec_dais[i], order);
1151f0fba2adSLiam Girdwood 
1152e60cd14fSLars-Peter Clausen 	soc_remove_dai(rtd->cpu_dai, order);
1153f0fba2adSLiam Girdwood }
1154f0fba2adSLiam Girdwood 
11551a497983SMengdong Lin static void soc_remove_link_components(struct snd_soc_card *card,
11561a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd, int order)
115762ae68faSStephen Warren {
115861aca564SLars-Peter Clausen 	struct snd_soc_component *component;
115990be711eSKuninori Morimoto 	struct snd_soc_rtdcom_list *rtdcom;
116062ae68faSStephen Warren 
116190be711eSKuninori Morimoto 	for_each_rtdcom(rtd, rtdcom) {
116290be711eSKuninori Morimoto 		component = rtdcom->component;
116362ae68faSStephen Warren 
116470090bbbSLars-Peter Clausen 		if (component->driver->remove_order == order)
116561aca564SLars-Peter Clausen 			soc_remove_component(component);
116662ae68faSStephen Warren 	}
116762ae68faSStephen Warren }
116862ae68faSStephen Warren 
11690671fd8eSKuninori Morimoto static void soc_remove_dai_links(struct snd_soc_card *card)
11700671fd8eSKuninori Morimoto {
11711a497983SMengdong Lin 	int order;
11721a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
1173f8f80361SMengdong Lin 	struct snd_soc_dai_link *link, *_link;
11740671fd8eSKuninori Morimoto 
11750168bf0dSLiam Girdwood 	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
11760168bf0dSLiam Girdwood 			order++) {
11771a497983SMengdong Lin 		list_for_each_entry(rtd, &card->rtd_list, list)
11781a497983SMengdong Lin 			soc_remove_link_dais(card, rtd, order);
11790168bf0dSLiam Girdwood 	}
118062ae68faSStephen Warren 
118162ae68faSStephen Warren 	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
118262ae68faSStephen Warren 			order++) {
11831a497983SMengdong Lin 		list_for_each_entry(rtd, &card->rtd_list, list)
11841a497983SMengdong Lin 			soc_remove_link_components(card, rtd, order);
118562ae68faSStephen Warren 	}
118662ae68faSStephen Warren 
1187f8f80361SMengdong Lin 	list_for_each_entry_safe(link, _link, &card->dai_link_list, list) {
1188f8f80361SMengdong Lin 		if (link->dobj.type == SND_SOC_DOBJ_DAI_LINK)
1189f8f80361SMengdong Lin 			dev_warn(card->dev, "Topology forgot to remove link %s?\n",
1190f8f80361SMengdong Lin 				link->name);
1191f8f80361SMengdong Lin 
1192f8f80361SMengdong Lin 		list_del(&link->list);
1193f8f80361SMengdong Lin 		card->num_dai_links--;
11940671fd8eSKuninori Morimoto 	}
11950671fd8eSKuninori Morimoto }
11960671fd8eSKuninori Morimoto 
1197923c5e61SMengdong Lin static int snd_soc_init_multicodec(struct snd_soc_card *card,
1198923c5e61SMengdong Lin 				   struct snd_soc_dai_link *dai_link)
1199923c5e61SMengdong Lin {
1200923c5e61SMengdong Lin 	/* Legacy codec/codec_dai link is a single entry in multicodec */
1201923c5e61SMengdong Lin 	if (dai_link->codec_name || dai_link->codec_of_node ||
1202923c5e61SMengdong Lin 	    dai_link->codec_dai_name) {
1203923c5e61SMengdong Lin 		dai_link->num_codecs = 1;
1204923c5e61SMengdong Lin 
1205923c5e61SMengdong Lin 		dai_link->codecs = devm_kzalloc(card->dev,
1206923c5e61SMengdong Lin 				sizeof(struct snd_soc_dai_link_component),
1207923c5e61SMengdong Lin 				GFP_KERNEL);
1208923c5e61SMengdong Lin 		if (!dai_link->codecs)
1209923c5e61SMengdong Lin 			return -ENOMEM;
1210923c5e61SMengdong Lin 
1211923c5e61SMengdong Lin 		dai_link->codecs[0].name = dai_link->codec_name;
1212923c5e61SMengdong Lin 		dai_link->codecs[0].of_node = dai_link->codec_of_node;
1213923c5e61SMengdong Lin 		dai_link->codecs[0].dai_name = dai_link->codec_dai_name;
1214923c5e61SMengdong Lin 	}
1215923c5e61SMengdong Lin 
1216923c5e61SMengdong Lin 	if (!dai_link->codecs) {
1217923c5e61SMengdong Lin 		dev_err(card->dev, "ASoC: DAI link has no CODECs\n");
1218923c5e61SMengdong Lin 		return -EINVAL;
1219923c5e61SMengdong Lin 	}
1220923c5e61SMengdong Lin 
1221923c5e61SMengdong Lin 	return 0;
1222923c5e61SMengdong Lin }
1223923c5e61SMengdong Lin 
1224923c5e61SMengdong Lin static int soc_init_dai_link(struct snd_soc_card *card,
1225923c5e61SMengdong Lin 				   struct snd_soc_dai_link *link)
1226923c5e61SMengdong Lin {
1227923c5e61SMengdong Lin 	int i, ret;
1228923c5e61SMengdong Lin 
1229923c5e61SMengdong Lin 	ret = snd_soc_init_multicodec(card, link);
1230923c5e61SMengdong Lin 	if (ret) {
1231923c5e61SMengdong Lin 		dev_err(card->dev, "ASoC: failed to init multicodec\n");
1232923c5e61SMengdong Lin 		return ret;
1233923c5e61SMengdong Lin 	}
1234923c5e61SMengdong Lin 
1235923c5e61SMengdong Lin 	for (i = 0; i < link->num_codecs; i++) {
1236923c5e61SMengdong Lin 		/*
1237923c5e61SMengdong Lin 		 * Codec must be specified by 1 of name or OF node,
1238923c5e61SMengdong Lin 		 * not both or neither.
1239923c5e61SMengdong Lin 		 */
1240923c5e61SMengdong Lin 		if (!!link->codecs[i].name ==
1241923c5e61SMengdong Lin 		    !!link->codecs[i].of_node) {
1242923c5e61SMengdong Lin 			dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n",
1243923c5e61SMengdong Lin 				link->name);
1244923c5e61SMengdong Lin 			return -EINVAL;
1245923c5e61SMengdong Lin 		}
1246923c5e61SMengdong Lin 		/* Codec DAI name must be specified */
1247923c5e61SMengdong Lin 		if (!link->codecs[i].dai_name) {
1248923c5e61SMengdong Lin 			dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n",
1249923c5e61SMengdong Lin 				link->name);
1250923c5e61SMengdong Lin 			return -EINVAL;
1251923c5e61SMengdong Lin 		}
1252923c5e61SMengdong Lin 	}
1253923c5e61SMengdong Lin 
1254923c5e61SMengdong Lin 	/*
1255923c5e61SMengdong Lin 	 * Platform may be specified by either name or OF node, but
1256923c5e61SMengdong Lin 	 * can be left unspecified, and a dummy platform will be used.
1257923c5e61SMengdong Lin 	 */
1258923c5e61SMengdong Lin 	if (link->platform_name && link->platform_of_node) {
1259923c5e61SMengdong Lin 		dev_err(card->dev,
1260923c5e61SMengdong Lin 			"ASoC: Both platform name/of_node are set for %s\n",
1261923c5e61SMengdong Lin 			link->name);
1262923c5e61SMengdong Lin 		return -EINVAL;
1263923c5e61SMengdong Lin 	}
1264923c5e61SMengdong Lin 
1265923c5e61SMengdong Lin 	/*
1266923c5e61SMengdong Lin 	 * CPU device may be specified by either name or OF node, but
1267923c5e61SMengdong Lin 	 * can be left unspecified, and will be matched based on DAI
1268923c5e61SMengdong Lin 	 * name alone..
1269923c5e61SMengdong Lin 	 */
1270923c5e61SMengdong Lin 	if (link->cpu_name && link->cpu_of_node) {
1271923c5e61SMengdong Lin 		dev_err(card->dev,
1272923c5e61SMengdong Lin 			"ASoC: Neither/both cpu name/of_node are set for %s\n",
1273923c5e61SMengdong Lin 			link->name);
1274923c5e61SMengdong Lin 		return -EINVAL;
1275923c5e61SMengdong Lin 	}
1276923c5e61SMengdong Lin 	/*
1277923c5e61SMengdong Lin 	 * At least one of CPU DAI name or CPU device name/node must be
1278923c5e61SMengdong Lin 	 * specified
1279923c5e61SMengdong Lin 	 */
1280923c5e61SMengdong Lin 	if (!link->cpu_dai_name &&
1281923c5e61SMengdong Lin 	    !(link->cpu_name || link->cpu_of_node)) {
1282923c5e61SMengdong Lin 		dev_err(card->dev,
1283923c5e61SMengdong Lin 			"ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n",
1284923c5e61SMengdong Lin 			link->name);
1285923c5e61SMengdong Lin 		return -EINVAL;
1286923c5e61SMengdong Lin 	}
1287923c5e61SMengdong Lin 
1288923c5e61SMengdong Lin 	return 0;
1289923c5e61SMengdong Lin }
1290923c5e61SMengdong Lin 
1291ef2e8175SKuninori Morimoto void snd_soc_disconnect_sync(struct device *dev)
1292ef2e8175SKuninori Morimoto {
1293ef2e8175SKuninori Morimoto 	struct snd_soc_component *component = snd_soc_lookup_component(dev, NULL);
1294ef2e8175SKuninori Morimoto 
1295ef2e8175SKuninori Morimoto 	if (!component || !component->card)
1296ef2e8175SKuninori Morimoto 		return;
1297ef2e8175SKuninori Morimoto 
1298ef2e8175SKuninori Morimoto 	snd_card_disconnect_sync(component->card->snd_card);
1299ef2e8175SKuninori Morimoto }
1300df532185SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_disconnect_sync);
1301ef2e8175SKuninori Morimoto 
1302f8f80361SMengdong Lin /**
1303f8f80361SMengdong Lin  * snd_soc_add_dai_link - Add a DAI link dynamically
1304f8f80361SMengdong Lin  * @card: The ASoC card to which the DAI link is added
1305f8f80361SMengdong Lin  * @dai_link: The new DAI link to add
1306f8f80361SMengdong Lin  *
1307f8f80361SMengdong Lin  * This function adds a DAI link to the ASoC card's link list.
1308f8f80361SMengdong Lin  *
1309f8f80361SMengdong Lin  * Note: Topology can use this API to add DAI links when probing the
1310f8f80361SMengdong Lin  * topology component. And machine drivers can still define static
1311f8f80361SMengdong Lin  * DAI links in dai_link array.
1312f8f80361SMengdong Lin  */
1313f8f80361SMengdong Lin int snd_soc_add_dai_link(struct snd_soc_card *card,
1314f8f80361SMengdong Lin 		struct snd_soc_dai_link *dai_link)
1315f8f80361SMengdong Lin {
1316f8f80361SMengdong Lin 	if (dai_link->dobj.type
1317f8f80361SMengdong Lin 	    && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) {
1318f8f80361SMengdong Lin 		dev_err(card->dev, "Invalid dai link type %d\n",
1319f8f80361SMengdong Lin 			dai_link->dobj.type);
1320f8f80361SMengdong Lin 		return -EINVAL;
1321f8f80361SMengdong Lin 	}
1322f8f80361SMengdong Lin 
1323f8f80361SMengdong Lin 	lockdep_assert_held(&client_mutex);
1324d6f220eaSMengdong Lin 	/* Notify the machine driver for extra initialization
1325d6f220eaSMengdong Lin 	 * on the link created by topology.
1326d6f220eaSMengdong Lin 	 */
1327d6f220eaSMengdong Lin 	if (dai_link->dobj.type && card->add_dai_link)
1328d6f220eaSMengdong Lin 		card->add_dai_link(card, dai_link);
1329d6f220eaSMengdong Lin 
1330f8f80361SMengdong Lin 	list_add_tail(&dai_link->list, &card->dai_link_list);
1331f8f80361SMengdong Lin 	card->num_dai_links++;
1332f8f80361SMengdong Lin 
1333f8f80361SMengdong Lin 	return 0;
1334f8f80361SMengdong Lin }
1335f8f80361SMengdong Lin EXPORT_SYMBOL_GPL(snd_soc_add_dai_link);
1336f8f80361SMengdong Lin 
1337f8f80361SMengdong Lin /**
1338f8f80361SMengdong Lin  * snd_soc_remove_dai_link - Remove a DAI link from the list
1339f8f80361SMengdong Lin  * @card: The ASoC card that owns the link
1340f8f80361SMengdong Lin  * @dai_link: The DAI link to remove
1341f8f80361SMengdong Lin  *
1342f8f80361SMengdong Lin  * This function removes a DAI link from the ASoC card's link list.
1343f8f80361SMengdong Lin  *
1344f8f80361SMengdong Lin  * For DAI links previously added by topology, topology should
1345f8f80361SMengdong Lin  * remove them by using the dobj embedded in the link.
1346f8f80361SMengdong Lin  */
1347f8f80361SMengdong Lin void snd_soc_remove_dai_link(struct snd_soc_card *card,
1348f8f80361SMengdong Lin 			     struct snd_soc_dai_link *dai_link)
1349f8f80361SMengdong Lin {
1350f8f80361SMengdong Lin 	struct snd_soc_dai_link *link, *_link;
1351f8f80361SMengdong Lin 
1352f8f80361SMengdong Lin 	if (dai_link->dobj.type
1353f8f80361SMengdong Lin 	    && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) {
1354f8f80361SMengdong Lin 		dev_err(card->dev, "Invalid dai link type %d\n",
1355f8f80361SMengdong Lin 			dai_link->dobj.type);
1356f8f80361SMengdong Lin 		return;
1357f8f80361SMengdong Lin 	}
1358f8f80361SMengdong Lin 
1359f8f80361SMengdong Lin 	lockdep_assert_held(&client_mutex);
1360d6f220eaSMengdong Lin 	/* Notify the machine driver for extra destruction
1361d6f220eaSMengdong Lin 	 * on the link created by topology.
1362d6f220eaSMengdong Lin 	 */
1363d6f220eaSMengdong Lin 	if (dai_link->dobj.type && card->remove_dai_link)
1364d6f220eaSMengdong Lin 		card->remove_dai_link(card, dai_link);
1365d6f220eaSMengdong Lin 
1366f8f80361SMengdong Lin 	list_for_each_entry_safe(link, _link, &card->dai_link_list, list) {
1367f8f80361SMengdong Lin 		if (link == dai_link) {
1368f8f80361SMengdong Lin 			list_del(&link->list);
1369f8f80361SMengdong Lin 			card->num_dai_links--;
1370f8f80361SMengdong Lin 			return;
1371f8f80361SMengdong Lin 		}
1372f8f80361SMengdong Lin 	}
1373f8f80361SMengdong Lin }
1374f8f80361SMengdong Lin EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link);
1375f0fba2adSLiam Girdwood 
1376ead9b919SJarkko Nikula static void soc_set_name_prefix(struct snd_soc_card *card,
137794f99c87SLars-Peter Clausen 				struct snd_soc_component *component)
1378ead9b919SJarkko Nikula {
1379ead9b919SJarkko Nikula 	int i;
1380ead9b919SJarkko Nikula 
1381ff819b83SDimitris Papastamos 	if (card->codec_conf == NULL)
1382ead9b919SJarkko Nikula 		return;
1383ead9b919SJarkko Nikula 
1384ff819b83SDimitris Papastamos 	for (i = 0; i < card->num_configs; i++) {
1385ff819b83SDimitris Papastamos 		struct snd_soc_codec_conf *map = &card->codec_conf[i];
1386*b24c539bSCharles Keepax 		struct device_node *component_of_node = component->dev->of_node;
1387*b24c539bSCharles Keepax 
1388*b24c539bSCharles Keepax 		if (!component_of_node && component->dev->parent)
1389*b24c539bSCharles Keepax 			component_of_node = component->dev->parent->of_node;
1390*b24c539bSCharles Keepax 
1391*b24c539bSCharles Keepax 		if (map->of_node && component_of_node != map->of_node)
13923ca041edSSebastian Reichel 			continue;
139394f99c87SLars-Peter Clausen 		if (map->dev_name && strcmp(component->name, map->dev_name))
13943ca041edSSebastian Reichel 			continue;
139594f99c87SLars-Peter Clausen 		component->name_prefix = map->name_prefix;
1396ead9b919SJarkko Nikula 		break;
1397ead9b919SJarkko Nikula 	}
1398ead9b919SJarkko Nikula }
1399ead9b919SJarkko Nikula 
1400f1d45cc3SLars-Peter Clausen static int soc_probe_component(struct snd_soc_card *card,
1401f1d45cc3SLars-Peter Clausen 	struct snd_soc_component *component)
1402589c3563SJarkko Nikula {
1403f1d45cc3SLars-Peter Clausen 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
1404888df395SMark Brown 	struct snd_soc_dai *dai;
1405f1d45cc3SLars-Peter Clausen 	int ret;
1406589c3563SJarkko Nikula 
14071b7c1231SLars-Peter Clausen 	if (!strcmp(component->name, "snd-soc-dummy"))
140870090bbbSLars-Peter Clausen 		return 0;
1409589c3563SJarkko Nikula 
1410abd31b32SLars-Peter Clausen 	if (component->card) {
14111b7c1231SLars-Peter Clausen 		if (component->card != card) {
14121b7c1231SLars-Peter Clausen 			dev_err(component->dev,
14131b7c1231SLars-Peter Clausen 				"Trying to bind component to card \"%s\" but is already bound to card \"%s\"\n",
14141b7c1231SLars-Peter Clausen 				card->name, component->card->name);
14151b7c1231SLars-Peter Clausen 			return -ENODEV;
14161b7c1231SLars-Peter Clausen 		}
14171b7c1231SLars-Peter Clausen 		return 0;
14181b7c1231SLars-Peter Clausen 	}
14191b7c1231SLars-Peter Clausen 
1420abd31b32SLars-Peter Clausen 	if (!try_module_get(component->dev->driver->owner))
1421abd31b32SLars-Peter Clausen 		return -ENODEV;
1422abd31b32SLars-Peter Clausen 
1423f1d45cc3SLars-Peter Clausen 	component->card = card;
1424f1d45cc3SLars-Peter Clausen 	dapm->card = card;
1425f1d45cc3SLars-Peter Clausen 	soc_set_name_prefix(card, component);
1426589c3563SJarkko Nikula 
1427f1d45cc3SLars-Peter Clausen 	soc_init_component_debugfs(component);
1428d5d1e0beSLars-Peter Clausen 
1429688d0ebfSKuninori Morimoto 	if (component->driver->dapm_widgets) {
1430688d0ebfSKuninori Morimoto 		ret = snd_soc_dapm_new_controls(dapm,
1431688d0ebfSKuninori Morimoto 					component->driver->dapm_widgets,
1432688d0ebfSKuninori Morimoto 					component->driver->num_dapm_widgets);
143377530150SLars-Peter Clausen 
1434b318ad50SNariman Poushin 		if (ret != 0) {
1435f1d45cc3SLars-Peter Clausen 			dev_err(component->dev,
1436b318ad50SNariman Poushin 				"Failed to create new controls %d\n", ret);
1437b318ad50SNariman Poushin 			goto err_probe;
1438b318ad50SNariman Poushin 		}
1439b318ad50SNariman Poushin 	}
1440b318ad50SNariman Poushin 
14410634814fSLars-Peter Clausen 	list_for_each_entry(dai, &component->dai_list, list) {
14420634814fSLars-Peter Clausen 		ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
1443261edc70SNariman Poushin 		if (ret != 0) {
1444f1d45cc3SLars-Peter Clausen 			dev_err(component->dev,
1445261edc70SNariman Poushin 				"Failed to create DAI widgets %d\n", ret);
1446261edc70SNariman Poushin 			goto err_probe;
1447261edc70SNariman Poushin 		}
1448261edc70SNariman Poushin 	}
1449888df395SMark Brown 
1450f1d45cc3SLars-Peter Clausen 	if (component->probe) {
1451f1d45cc3SLars-Peter Clausen 		ret = component->probe(component);
1452589c3563SJarkko Nikula 		if (ret < 0) {
1453f1d45cc3SLars-Peter Clausen 			dev_err(component->dev,
1454f1d45cc3SLars-Peter Clausen 				"ASoC: failed to probe component %d\n", ret);
145570d29331SJarkko Nikula 			goto err_probe;
1456589c3563SJarkko Nikula 		}
1457cb2cf612SLiam Girdwood 
1458f1d45cc3SLars-Peter Clausen 		WARN(dapm->idle_bias_off &&
1459f1d45cc3SLars-Peter Clausen 			dapm->bias_level != SND_SOC_BIAS_OFF,
1460956245e9SLiam Girdwood 			"codec %s can not start from non-off bias with idle_bias_off==1\n",
1461f1d45cc3SLars-Peter Clausen 			component->name);
1462956245e9SLiam Girdwood 	}
1463956245e9SLiam Girdwood 
1464f2ed6b07SMengdong Lin 	/* machine specific init */
1465f2ed6b07SMengdong Lin 	if (component->init) {
1466f2ed6b07SMengdong Lin 		ret = component->init(component);
1467f2ed6b07SMengdong Lin 		if (ret < 0) {
1468f2ed6b07SMengdong Lin 			dev_err(component->dev,
1469f2ed6b07SMengdong Lin 				"Failed to do machine specific init %d\n", ret);
1470f2ed6b07SMengdong Lin 			goto err_probe;
1471f2ed6b07SMengdong Lin 		}
1472f2ed6b07SMengdong Lin 	}
1473f2ed6b07SMengdong Lin 
1474b8972bf0SKuninori Morimoto 	if (component->driver->controls)
1475b8972bf0SKuninori Morimoto 		snd_soc_add_component_controls(component,
1476b8972bf0SKuninori Morimoto 					       component->driver->controls,
1477b8972bf0SKuninori Morimoto 					       component->driver->num_controls);
14786969b2baSKuninori Morimoto 	if (component->driver->dapm_routes)
14796969b2baSKuninori Morimoto 		snd_soc_dapm_add_routes(dapm,
14806969b2baSKuninori Morimoto 					component->driver->dapm_routes,
14816969b2baSKuninori Morimoto 					component->driver->num_dapm_routes);
1482956245e9SLiam Girdwood 
1483f1d45cc3SLars-Peter Clausen 	list_add(&dapm->list, &card->dapm_list);
1484d9fc4063SKuninori Morimoto 	list_add(&component->card_list, &card->component_dev_list);
1485956245e9SLiam Girdwood 
1486956245e9SLiam Girdwood 	return 0;
1487956245e9SLiam Girdwood 
1488956245e9SLiam Girdwood err_probe:
1489f1d45cc3SLars-Peter Clausen 	soc_cleanup_component_debugfs(component);
1490abd31b32SLars-Peter Clausen 	component->card = NULL;
1491f1d45cc3SLars-Peter Clausen 	module_put(component->dev->driver->owner);
1492956245e9SLiam Girdwood 
1493956245e9SLiam Girdwood 	return ret;
1494956245e9SLiam Girdwood }
1495956245e9SLiam Girdwood 
149636ae1a96SMark Brown static void rtd_release(struct device *dev)
149736ae1a96SMark Brown {
149836ae1a96SMark Brown 	kfree(dev);
149936ae1a96SMark Brown }
1500f0fba2adSLiam Girdwood 
15015f3484acSLars-Peter Clausen static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd,
15025f3484acSLars-Peter Clausen 	const char *name)
1503503ae5e0SMisael Lopez Cruz {
1504589c3563SJarkko Nikula 	int ret = 0;
1505589c3563SJarkko Nikula 
1506589c3563SJarkko Nikula 	/* register the rtd device */
150736ae1a96SMark Brown 	rtd->dev = kzalloc(sizeof(struct device), GFP_KERNEL);
150836ae1a96SMark Brown 	if (!rtd->dev)
150936ae1a96SMark Brown 		return -ENOMEM;
151036ae1a96SMark Brown 	device_initialize(rtd->dev);
15115f3484acSLars-Peter Clausen 	rtd->dev->parent = rtd->card->dev;
151236ae1a96SMark Brown 	rtd->dev->release = rtd_release;
1513d29697dcSTakashi Iwai 	rtd->dev->groups = soc_dev_attr_groups;
1514f294afedSLars-Peter Clausen 	dev_set_name(rtd->dev, "%s", name);
151536ae1a96SMark Brown 	dev_set_drvdata(rtd->dev, rtd);
1516b8c0dab9SLiam Girdwood 	mutex_init(&rtd->pcm_mutex);
151701d7584cSLiam Girdwood 	INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients);
151801d7584cSLiam Girdwood 	INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients);
151901d7584cSLiam Girdwood 	INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].fe_clients);
152001d7584cSLiam Girdwood 	INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients);
152136ae1a96SMark Brown 	ret = device_add(rtd->dev);
1522589c3563SJarkko Nikula 	if (ret < 0) {
1523865df9cbSChuansheng Liu 		/* calling put_device() here to free the rtd->dev */
1524865df9cbSChuansheng Liu 		put_device(rtd->dev);
15255f3484acSLars-Peter Clausen 		dev_err(rtd->card->dev,
1526f110bfc7SLiam Girdwood 			"ASoC: failed to register runtime device: %d\n", ret);
1527589c3563SJarkko Nikula 		return ret;
1528589c3563SJarkko Nikula 	}
1529589c3563SJarkko Nikula 	rtd->dev_registered = 1;
1530589c3563SJarkko Nikula 	return 0;
1531589c3563SJarkko Nikula }
1532589c3563SJarkko Nikula 
15331a497983SMengdong Lin static int soc_probe_link_components(struct snd_soc_card *card,
15341a497983SMengdong Lin 			struct snd_soc_pcm_runtime *rtd,
153562ae68faSStephen Warren 				     int order)
153662ae68faSStephen Warren {
1537f1d45cc3SLars-Peter Clausen 	struct snd_soc_component *component;
153890be711eSKuninori Morimoto 	struct snd_soc_rtdcom_list *rtdcom;
153990be711eSKuninori Morimoto 	int ret;
154062ae68faSStephen Warren 
154190be711eSKuninori Morimoto 	for_each_rtdcom(rtd, rtdcom) {
154290be711eSKuninori Morimoto 		component = rtdcom->component;
154390be711eSKuninori Morimoto 
154470090bbbSLars-Peter Clausen 		if (component->driver->probe_order == order) {
1545f1d45cc3SLars-Peter Clausen 			ret = soc_probe_component(card, component);
154662ae68faSStephen Warren 			if (ret < 0)
154762ae68faSStephen Warren 				return ret;
154862ae68faSStephen Warren 		}
154962ae68faSStephen Warren 	}
155062ae68faSStephen Warren 
155162ae68faSStephen Warren 	return 0;
155262ae68faSStephen Warren }
155362ae68faSStephen Warren 
15548e2be562SLars-Peter Clausen static int soc_probe_dai(struct snd_soc_dai *dai, int order)
1555b0aa88afSMisael Lopez Cruz {
15567a2ccad5SKuninori Morimoto 	if (dai->probed ||
15577a2ccad5SKuninori Morimoto 	    dai->driver->probe_order != order)
15587a2ccad5SKuninori Morimoto 		return 0;
1559b0aa88afSMisael Lopez Cruz 
15608e2be562SLars-Peter Clausen 	if (dai->driver->probe) {
15617a2ccad5SKuninori Morimoto 		int ret = dai->driver->probe(dai);
1562b0aa88afSMisael Lopez Cruz 		if (ret < 0) {
15637a2ccad5SKuninori Morimoto 			dev_err(dai->dev, "ASoC: failed to probe DAI %s: %d\n",
15648e2be562SLars-Peter Clausen 				dai->name, ret);
1565b0aa88afSMisael Lopez Cruz 			return ret;
1566b0aa88afSMisael Lopez Cruz 		}
1567b0aa88afSMisael Lopez Cruz 	}
1568b0aa88afSMisael Lopez Cruz 
15698e2be562SLars-Peter Clausen 	dai->probed = 1;
1570b0aa88afSMisael Lopez Cruz 
1571b0aa88afSMisael Lopez Cruz 	return 0;
1572b0aa88afSMisael Lopez Cruz }
1573b0aa88afSMisael Lopez Cruz 
157425f7b701SArnaud Pouliquen static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais,
157525f7b701SArnaud Pouliquen 				struct snd_soc_pcm_runtime *rtd)
157625f7b701SArnaud Pouliquen {
157725f7b701SArnaud Pouliquen 	int i, ret = 0;
157825f7b701SArnaud Pouliquen 
157925f7b701SArnaud Pouliquen 	for (i = 0; i < num_dais; ++i) {
158025f7b701SArnaud Pouliquen 		struct snd_soc_dai_driver *drv = dais[i]->driver;
158125f7b701SArnaud Pouliquen 
158225f7b701SArnaud Pouliquen 		if (!rtd->dai_link->no_pcm && drv->pcm_new)
158325f7b701SArnaud Pouliquen 			ret = drv->pcm_new(rtd, dais[i]);
158425f7b701SArnaud Pouliquen 		if (ret < 0) {
158525f7b701SArnaud Pouliquen 			dev_err(dais[i]->dev,
158625f7b701SArnaud Pouliquen 				"ASoC: Failed to bind %s with pcm device\n",
158725f7b701SArnaud Pouliquen 				dais[i]->name);
158825f7b701SArnaud Pouliquen 			return ret;
158925f7b701SArnaud Pouliquen 		}
159025f7b701SArnaud Pouliquen 	}
159125f7b701SArnaud Pouliquen 
159225f7b701SArnaud Pouliquen 	return 0;
159325f7b701SArnaud Pouliquen }
159425f7b701SArnaud Pouliquen 
15952436a723SMisael Lopez Cruz static int soc_link_dai_widgets(struct snd_soc_card *card,
15962436a723SMisael Lopez Cruz 				struct snd_soc_dai_link *dai_link,
15973f901a02SBenoit Cousson 				struct snd_soc_pcm_runtime *rtd)
15982436a723SMisael Lopez Cruz {
15993f901a02SBenoit Cousson 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
16003f901a02SBenoit Cousson 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
16013de7c420SVinod Koul 	struct snd_soc_dapm_widget *sink, *source;
16022436a723SMisael Lopez Cruz 	int ret;
16032436a723SMisael Lopez Cruz 
160488bd870fSBenoit Cousson 	if (rtd->num_codecs > 1)
160588bd870fSBenoit Cousson 		dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n");
160688bd870fSBenoit Cousson 
16072436a723SMisael Lopez Cruz 	/* link the DAI widgets */
16083de7c420SVinod Koul 	sink = codec_dai->playback_widget;
16093de7c420SVinod Koul 	source = cpu_dai->capture_widget;
16103de7c420SVinod Koul 	if (sink && source) {
16112436a723SMisael Lopez Cruz 		ret = snd_soc_dapm_new_pcm(card, dai_link->params,
16123de7c420SVinod Koul 					   dai_link->num_params,
16133de7c420SVinod Koul 					   source, sink);
16142436a723SMisael Lopez Cruz 		if (ret != 0) {
16152436a723SMisael Lopez Cruz 			dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
16163de7c420SVinod Koul 				sink->name, source->name, ret);
16172436a723SMisael Lopez Cruz 			return ret;
16182436a723SMisael Lopez Cruz 		}
16192436a723SMisael Lopez Cruz 	}
16202436a723SMisael Lopez Cruz 
16213de7c420SVinod Koul 	sink = cpu_dai->playback_widget;
16223de7c420SVinod Koul 	source = codec_dai->capture_widget;
16233de7c420SVinod Koul 	if (sink && source) {
16242436a723SMisael Lopez Cruz 		ret = snd_soc_dapm_new_pcm(card, dai_link->params,
16253de7c420SVinod Koul 					   dai_link->num_params,
16263de7c420SVinod Koul 					   source, sink);
16272436a723SMisael Lopez Cruz 		if (ret != 0) {
16282436a723SMisael Lopez Cruz 			dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
16293de7c420SVinod Koul 				sink->name, source->name, ret);
16302436a723SMisael Lopez Cruz 			return ret;
16312436a723SMisael Lopez Cruz 		}
16322436a723SMisael Lopez Cruz 	}
16332436a723SMisael Lopez Cruz 
16342436a723SMisael Lopez Cruz 	return 0;
16352436a723SMisael Lopez Cruz }
16362436a723SMisael Lopez Cruz 
16371a497983SMengdong Lin static int soc_probe_link_dais(struct snd_soc_card *card,
16381a497983SMengdong Lin 		struct snd_soc_pcm_runtime *rtd, int order)
1639f0fba2adSLiam Girdwood {
16401a497983SMengdong Lin 	struct snd_soc_dai_link *dai_link = rtd->dai_link;
1641c74184edSMark Brown 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1642291bfb92SMark Brown 	int i, ret;
1643f0fba2adSLiam Girdwood 
1644f110bfc7SLiam Girdwood 	dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n",
16451a497983SMengdong Lin 			card->name, rtd->num, order);
1646f0fba2adSLiam Girdwood 
1647f0fba2adSLiam Girdwood 	/* set default power off timeout */
1648f0fba2adSLiam Girdwood 	rtd->pmdown_time = pmdown_time;
1649f0fba2adSLiam Girdwood 
16508e2be562SLars-Peter Clausen 	ret = soc_probe_dai(cpu_dai, order);
16518e2be562SLars-Peter Clausen 	if (ret)
1652f0fba2adSLiam Girdwood 		return ret;
1653f0fba2adSLiam Girdwood 
1654f0fba2adSLiam Girdwood 	/* probe the CODEC DAI */
165588bd870fSBenoit Cousson 	for (i = 0; i < rtd->num_codecs; i++) {
16568e2be562SLars-Peter Clausen 		ret = soc_probe_dai(rtd->codec_dais[i], order);
1657b0aa88afSMisael Lopez Cruz 		if (ret)
1658f0fba2adSLiam Girdwood 			return ret;
165988bd870fSBenoit Cousson 	}
1660f0fba2adSLiam Girdwood 
16610168bf0dSLiam Girdwood 	/* complete DAI probe during last probe */
16620168bf0dSLiam Girdwood 	if (order != SND_SOC_COMP_ORDER_LAST)
16630168bf0dSLiam Girdwood 		return 0;
16640168bf0dSLiam Girdwood 
16655f3484acSLars-Peter Clausen 	/* do machine specific initialization */
16665f3484acSLars-Peter Clausen 	if (dai_link->init) {
16675f3484acSLars-Peter Clausen 		ret = dai_link->init(rtd);
16685f3484acSLars-Peter Clausen 		if (ret < 0) {
16695f3484acSLars-Peter Clausen 			dev_err(card->dev, "ASoC: failed to init %s: %d\n",
16705f3484acSLars-Peter Clausen 				dai_link->name, ret);
16715f3484acSLars-Peter Clausen 			return ret;
16725f3484acSLars-Peter Clausen 		}
16735f3484acSLars-Peter Clausen 	}
16745f3484acSLars-Peter Clausen 
1675a5053a8eSKuninori Morimoto 	if (dai_link->dai_fmt)
1676a5053a8eSKuninori Morimoto 		snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt);
1677a5053a8eSKuninori Morimoto 
16785f3484acSLars-Peter Clausen 	ret = soc_post_component_init(rtd, dai_link->name);
1679589c3563SJarkko Nikula 	if (ret)
1680f0fba2adSLiam Girdwood 		return ret;
1681f0fba2adSLiam Girdwood 
16825f3484acSLars-Peter Clausen #ifdef CONFIG_DEBUG_FS
16835f3484acSLars-Peter Clausen 	/* add DPCM sysfs entries */
16842e55b90aSLars-Peter Clausen 	if (dai_link->dynamic)
16852e55b90aSLars-Peter Clausen 		soc_dpcm_debugfs_add(rtd);
16865f3484acSLars-Peter Clausen #endif
16875f3484acSLars-Peter Clausen 
16886f0c4226SJie Yang 	if (cpu_dai->driver->compress_new) {
16891245b700SNamarta Kohli 		/*create compress_device"*/
1690291bfb92SMark Brown 		ret = cpu_dai->driver->compress_new(rtd, rtd->num);
16911245b700SNamarta Kohli 		if (ret < 0) {
1692f110bfc7SLiam Girdwood 			dev_err(card->dev, "ASoC: can't create compress %s\n",
16931245b700SNamarta Kohli 					 dai_link->stream_name);
16941245b700SNamarta Kohli 			return ret;
16951245b700SNamarta Kohli 		}
16961245b700SNamarta Kohli 	} else {
16971245b700SNamarta Kohli 
1698c74184edSMark Brown 		if (!dai_link->params) {
1699f0fba2adSLiam Girdwood 			/* create the pcm */
1700291bfb92SMark Brown 			ret = soc_new_pcm(rtd, rtd->num);
1701f0fba2adSLiam Girdwood 			if (ret < 0) {
1702f110bfc7SLiam Girdwood 				dev_err(card->dev, "ASoC: can't create pcm %s :%d\n",
17030837fc62SFabio Estevam 				       dai_link->stream_name, ret);
1704f0fba2adSLiam Girdwood 				return ret;
1705f0fba2adSLiam Girdwood 			}
170625f7b701SArnaud Pouliquen 			ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd);
170725f7b701SArnaud Pouliquen 			if (ret < 0)
170825f7b701SArnaud Pouliquen 				return ret;
170925f7b701SArnaud Pouliquen 			ret = soc_link_dai_pcm_new(rtd->codec_dais,
171025f7b701SArnaud Pouliquen 						   rtd->num_codecs, rtd);
171125f7b701SArnaud Pouliquen 			if (ret < 0)
171225f7b701SArnaud Pouliquen 				return ret;
1713c74184edSMark Brown 		} else {
17149d58a077SRichard Fitzgerald 			INIT_DELAYED_WORK(&rtd->delayed_work,
17159d58a077SRichard Fitzgerald 						codec2codec_close_delayed_work);
17169d58a077SRichard Fitzgerald 
1717c74184edSMark Brown 			/* link the DAI widgets */
17183f901a02SBenoit Cousson 			ret = soc_link_dai_widgets(card, dai_link, rtd);
17192436a723SMisael Lopez Cruz 			if (ret)
1720c74184edSMark Brown 				return ret;
1721c74184edSMark Brown 		}
1722c74184edSMark Brown 	}
1723c74184edSMark Brown 
1724f0fba2adSLiam Girdwood 	return 0;
1725f0fba2adSLiam Girdwood }
1726f0fba2adSLiam Girdwood 
172744c69bb1SLars-Peter Clausen static int soc_bind_aux_dev(struct snd_soc_card *card, int num)
1728b19e6e7bSMark Brown {
17293ca041edSSebastian Reichel 	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
1730f2ed6b07SMengdong Lin 	struct snd_soc_component *component;
1731f2ed6b07SMengdong Lin 	const char *name;
1732f2ed6b07SMengdong Lin 	struct device_node *codec_of_node;
17333ca041edSSebastian Reichel 
1734f2ed6b07SMengdong Lin 	if (aux_dev->codec_of_node || aux_dev->codec_name) {
1735f2ed6b07SMengdong Lin 		/* codecs, usually analog devices */
1736f2ed6b07SMengdong Lin 		name = aux_dev->codec_name;
1737f2ed6b07SMengdong Lin 		codec_of_node = aux_dev->codec_of_node;
1738f2ed6b07SMengdong Lin 		component = soc_find_component(codec_of_node, name);
1739f2ed6b07SMengdong Lin 		if (!component) {
1740f2ed6b07SMengdong Lin 			if (codec_of_node)
1741f2ed6b07SMengdong Lin 				name = of_node_full_name(codec_of_node);
1742f2ed6b07SMengdong Lin 			goto err_defer;
1743f2ed6b07SMengdong Lin 		}
1744f2ed6b07SMengdong Lin 	} else if (aux_dev->name) {
1745f2ed6b07SMengdong Lin 		/* generic components */
1746f2ed6b07SMengdong Lin 		name = aux_dev->name;
1747f2ed6b07SMengdong Lin 		component = soc_find_component(NULL, name);
1748f2ed6b07SMengdong Lin 		if (!component)
1749f2ed6b07SMengdong Lin 			goto err_defer;
1750f2ed6b07SMengdong Lin 	} else {
1751f2ed6b07SMengdong Lin 		dev_err(card->dev, "ASoC: Invalid auxiliary device\n");
1752f2ed6b07SMengdong Lin 		return -EINVAL;
1753f2ed6b07SMengdong Lin 	}
17543ca041edSSebastian Reichel 
1755f2ed6b07SMengdong Lin 	component->init = aux_dev->init;
1756d2e3a135SSylwester Nawrocki 	list_add(&component->card_aux_list, &card->aux_comp_list);
17571a653aa4SKuninori Morimoto 
1758f2ed6b07SMengdong Lin 	return 0;
1759f2ed6b07SMengdong Lin 
1760f2ed6b07SMengdong Lin err_defer:
176165d9361fSLars-Peter Clausen 	dev_err(card->dev, "ASoC: %s not registered\n", name);
1762b19e6e7bSMark Brown 	return -EPROBE_DEFER;
1763b19e6e7bSMark Brown }
1764b19e6e7bSMark Brown 
1765f2ed6b07SMengdong Lin static int soc_probe_aux_devices(struct snd_soc_card *card)
1766f2ed6b07SMengdong Lin {
1767991454e1SKuninori Morimoto 	struct snd_soc_component *comp;
1768f2ed6b07SMengdong Lin 	int order;
1769f2ed6b07SMengdong Lin 	int ret;
1770f2ed6b07SMengdong Lin 
1771f2ed6b07SMengdong Lin 	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
1772f2ed6b07SMengdong Lin 		order++) {
1773991454e1SKuninori Morimoto 		list_for_each_entry(comp, &card->aux_comp_list, card_aux_list) {
1774f2ed6b07SMengdong Lin 			if (comp->driver->probe_order == order) {
1775f2ed6b07SMengdong Lin 				ret = soc_probe_component(card,	comp);
1776f2ed6b07SMengdong Lin 				if (ret < 0) {
1777f2ed6b07SMengdong Lin 					dev_err(card->dev,
1778f2ed6b07SMengdong Lin 						"ASoC: failed to probe aux component %s %d\n",
1779f2ed6b07SMengdong Lin 						comp->name, ret);
1780f2ed6b07SMengdong Lin 					return ret;
1781f2ed6b07SMengdong Lin 				}
1782f2ed6b07SMengdong Lin 			}
1783f2ed6b07SMengdong Lin 		}
1784f2ed6b07SMengdong Lin 	}
178565d9361fSLars-Peter Clausen 
178644c69bb1SLars-Peter Clausen 	return 0;
17873ca041edSSebastian Reichel }
17882eea392dSJarkko Nikula 
1789f2ed6b07SMengdong Lin static void soc_remove_aux_devices(struct snd_soc_card *card)
179044c69bb1SLars-Peter Clausen {
1791f2ed6b07SMengdong Lin 	struct snd_soc_component *comp, *_comp;
1792f2ed6b07SMengdong Lin 	int order;
179344c69bb1SLars-Peter Clausen 
1794f2ed6b07SMengdong Lin 	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
1795f2ed6b07SMengdong Lin 		order++) {
1796f2ed6b07SMengdong Lin 		list_for_each_entry_safe(comp, _comp,
1797991454e1SKuninori Morimoto 			&card->aux_comp_list, card_aux_list) {
17981a653aa4SKuninori Morimoto 
1799f2ed6b07SMengdong Lin 			if (comp->driver->remove_order == order) {
1800f2ed6b07SMengdong Lin 				soc_remove_component(comp);
1801991454e1SKuninori Morimoto 				/* remove it from the card's aux_comp_list */
1802991454e1SKuninori Morimoto 				list_del(&comp->card_aux_list);
18032eea392dSJarkko Nikula 			}
18045f3484acSLars-Peter Clausen 		}
18052eea392dSJarkko Nikula 	}
18062eea392dSJarkko Nikula }
18072eea392dSJarkko Nikula 
1808f90fb3f7SLars-Peter Clausen static int snd_soc_init_codec_cache(struct snd_soc_codec *codec)
1809fdf0f54dSDimitris Papastamos {
1810fdf0f54dSDimitris Papastamos 	int ret;
1811fdf0f54dSDimitris Papastamos 
1812fdf0f54dSDimitris Papastamos 	if (codec->cache_init)
1813fdf0f54dSDimitris Papastamos 		return 0;
1814fdf0f54dSDimitris Papastamos 
1815fdf0f54dSDimitris Papastamos 	ret = snd_soc_cache_init(codec);
1816fdf0f54dSDimitris Papastamos 	if (ret < 0) {
181710e8aa9aSMichał Mirosław 		dev_err(codec->dev,
181810e8aa9aSMichał Mirosław 			"ASoC: Failed to set cache compression type: %d\n",
181910e8aa9aSMichał Mirosław 			ret);
1820fdf0f54dSDimitris Papastamos 		return ret;
1821fdf0f54dSDimitris Papastamos 	}
1822fdf0f54dSDimitris Papastamos 	codec->cache_init = 1;
1823fdf0f54dSDimitris Papastamos 	return 0;
1824fdf0f54dSDimitris Papastamos }
1825fdf0f54dSDimitris Papastamos 
1826ce64c8b9SLars-Peter Clausen /**
1827ce64c8b9SLars-Peter Clausen  * snd_soc_runtime_set_dai_fmt() - Change DAI link format for a ASoC runtime
1828ce64c8b9SLars-Peter Clausen  * @rtd: The runtime for which the DAI link format should be changed
1829ce64c8b9SLars-Peter Clausen  * @dai_fmt: The new DAI link format
1830ce64c8b9SLars-Peter Clausen  *
1831ce64c8b9SLars-Peter Clausen  * This function updates the DAI link format for all DAIs connected to the DAI
1832ce64c8b9SLars-Peter Clausen  * link for the specified runtime.
1833ce64c8b9SLars-Peter Clausen  *
1834ce64c8b9SLars-Peter Clausen  * Note: For setups with a static format set the dai_fmt field in the
1835ce64c8b9SLars-Peter Clausen  * corresponding snd_dai_link struct instead of using this function.
1836ce64c8b9SLars-Peter Clausen  *
1837ce64c8b9SLars-Peter Clausen  * Returns 0 on success, otherwise a negative error code.
1838ce64c8b9SLars-Peter Clausen  */
1839ce64c8b9SLars-Peter Clausen int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
1840ce64c8b9SLars-Peter Clausen 	unsigned int dai_fmt)
1841ce64c8b9SLars-Peter Clausen {
1842ce64c8b9SLars-Peter Clausen 	struct snd_soc_dai **codec_dais = rtd->codec_dais;
1843ce64c8b9SLars-Peter Clausen 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1844ce64c8b9SLars-Peter Clausen 	unsigned int i;
1845ce64c8b9SLars-Peter Clausen 	int ret;
1846ce64c8b9SLars-Peter Clausen 
1847ce64c8b9SLars-Peter Clausen 	for (i = 0; i < rtd->num_codecs; i++) {
1848ce64c8b9SLars-Peter Clausen 		struct snd_soc_dai *codec_dai = codec_dais[i];
1849ce64c8b9SLars-Peter Clausen 
1850ce64c8b9SLars-Peter Clausen 		ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
1851ce64c8b9SLars-Peter Clausen 		if (ret != 0 && ret != -ENOTSUPP) {
1852ce64c8b9SLars-Peter Clausen 			dev_warn(codec_dai->dev,
1853ce64c8b9SLars-Peter Clausen 				 "ASoC: Failed to set DAI format: %d\n", ret);
1854ce64c8b9SLars-Peter Clausen 			return ret;
1855ce64c8b9SLars-Peter Clausen 		}
1856ce64c8b9SLars-Peter Clausen 	}
1857ce64c8b9SLars-Peter Clausen 
1858ce64c8b9SLars-Peter Clausen 	/* Flip the polarity for the "CPU" end of a CODEC<->CODEC link */
1859cb2cf0deSKuninori Morimoto 	/* the component which has non_legacy_dai_naming is Codec */
1860cb2cf0deSKuninori Morimoto 	if (cpu_dai->codec ||
1861cb2cf0deSKuninori Morimoto 	    cpu_dai->component->driver->non_legacy_dai_naming) {
1862ce64c8b9SLars-Peter Clausen 		unsigned int inv_dai_fmt;
1863ce64c8b9SLars-Peter Clausen 
1864ce64c8b9SLars-Peter Clausen 		inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_MASTER_MASK;
1865ce64c8b9SLars-Peter Clausen 		switch (dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1866ce64c8b9SLars-Peter Clausen 		case SND_SOC_DAIFMT_CBM_CFM:
1867ce64c8b9SLars-Peter Clausen 			inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
1868ce64c8b9SLars-Peter Clausen 			break;
1869ce64c8b9SLars-Peter Clausen 		case SND_SOC_DAIFMT_CBM_CFS:
1870ce64c8b9SLars-Peter Clausen 			inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFM;
1871ce64c8b9SLars-Peter Clausen 			break;
1872ce64c8b9SLars-Peter Clausen 		case SND_SOC_DAIFMT_CBS_CFM:
1873ce64c8b9SLars-Peter Clausen 			inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFS;
1874ce64c8b9SLars-Peter Clausen 			break;
1875ce64c8b9SLars-Peter Clausen 		case SND_SOC_DAIFMT_CBS_CFS:
1876ce64c8b9SLars-Peter Clausen 			inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
1877ce64c8b9SLars-Peter Clausen 			break;
1878ce64c8b9SLars-Peter Clausen 		}
1879ce64c8b9SLars-Peter Clausen 
1880ce64c8b9SLars-Peter Clausen 		dai_fmt = inv_dai_fmt;
1881ce64c8b9SLars-Peter Clausen 	}
1882ce64c8b9SLars-Peter Clausen 
1883ce64c8b9SLars-Peter Clausen 	ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
1884ce64c8b9SLars-Peter Clausen 	if (ret != 0 && ret != -ENOTSUPP) {
1885ce64c8b9SLars-Peter Clausen 		dev_warn(cpu_dai->dev,
1886ce64c8b9SLars-Peter Clausen 			 "ASoC: Failed to set DAI format: %d\n", ret);
1887ce64c8b9SLars-Peter Clausen 		return ret;
1888ce64c8b9SLars-Peter Clausen 	}
1889ce64c8b9SLars-Peter Clausen 
1890ce64c8b9SLars-Peter Clausen 	return 0;
1891ce64c8b9SLars-Peter Clausen }
1892ddaca25aSLars-Peter Clausen EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt);
1893ce64c8b9SLars-Peter Clausen 
1894345233d7SLiam Girdwood 
18951f5a4535STakashi Iwai #ifdef CONFIG_DMI
1896345233d7SLiam Girdwood /* Trim special characters, and replace '-' with '_' since '-' is used to
1897345233d7SLiam Girdwood  * separate different DMI fields in the card long name. Only number and
1898345233d7SLiam Girdwood  * alphabet characters and a few separator characters are kept.
1899345233d7SLiam Girdwood  */
1900345233d7SLiam Girdwood static void cleanup_dmi_name(char *name)
1901345233d7SLiam Girdwood {
1902345233d7SLiam Girdwood 	int i, j = 0;
1903345233d7SLiam Girdwood 
1904345233d7SLiam Girdwood 	for (i = 0; name[i]; i++) {
1905345233d7SLiam Girdwood 		if (isalnum(name[i]) || (name[i] == '.')
1906345233d7SLiam Girdwood 		    || (name[i] == '_'))
1907345233d7SLiam Girdwood 			name[j++] = name[i];
1908345233d7SLiam Girdwood 		else if (name[i] == '-')
1909345233d7SLiam Girdwood 			name[j++] = '_';
1910345233d7SLiam Girdwood 	}
1911345233d7SLiam Girdwood 
1912345233d7SLiam Girdwood 	name[j] = '\0';
1913345233d7SLiam Girdwood }
1914345233d7SLiam Girdwood 
191598faf436SMengdong Lin /* Check if a DMI field is valid, i.e. not containing any string
191698faf436SMengdong Lin  * in the black list.
191798faf436SMengdong Lin  */
191898faf436SMengdong Lin static int is_dmi_valid(const char *field)
191998faf436SMengdong Lin {
192098faf436SMengdong Lin 	int i = 0;
192198faf436SMengdong Lin 
192298faf436SMengdong Lin 	while (dmi_blacklist[i]) {
192398faf436SMengdong Lin 		if (strstr(field, dmi_blacklist[i]))
192498faf436SMengdong Lin 			return 0;
192598faf436SMengdong Lin 		i++;
192646b5a4d2SWu Fengguang 	}
192798faf436SMengdong Lin 
192898faf436SMengdong Lin 	return 1;
192998faf436SMengdong Lin }
193098faf436SMengdong Lin 
1931345233d7SLiam Girdwood /**
1932345233d7SLiam Girdwood  * snd_soc_set_dmi_name() - Register DMI names to card
1933345233d7SLiam Girdwood  * @card: The card to register DMI names
1934345233d7SLiam Girdwood  * @flavour: The flavour "differentiator" for the card amongst its peers.
1935345233d7SLiam Girdwood  *
1936345233d7SLiam Girdwood  * An Intel machine driver may be used by many different devices but are
1937345233d7SLiam Girdwood  * difficult for userspace to differentiate, since machine drivers ususally
1938345233d7SLiam Girdwood  * use their own name as the card short name and leave the card long name
1939345233d7SLiam Girdwood  * blank. To differentiate such devices and fix bugs due to lack of
1940345233d7SLiam Girdwood  * device-specific configurations, this function allows DMI info to be used
1941345233d7SLiam Girdwood  * as the sound card long name, in the format of
1942345233d7SLiam Girdwood  * "vendor-product-version-board"
1943345233d7SLiam Girdwood  * (Character '-' is used to separate different DMI fields here).
1944345233d7SLiam Girdwood  * This will help the user space to load the device-specific Use Case Manager
1945345233d7SLiam Girdwood  * (UCM) configurations for the card.
1946345233d7SLiam Girdwood  *
1947345233d7SLiam Girdwood  * Possible card long names may be:
1948345233d7SLiam Girdwood  * DellInc.-XPS139343-01-0310JH
1949345233d7SLiam Girdwood  * ASUSTeKCOMPUTERINC.-T100TA-1.0-T100TA
1950345233d7SLiam Girdwood  * Circuitco-MinnowboardMaxD0PLATFORM-D0-MinnowBoardMAX
1951345233d7SLiam Girdwood  *
1952345233d7SLiam Girdwood  * This function also supports flavoring the card longname to provide
1953345233d7SLiam Girdwood  * the extra differentiation, like "vendor-product-version-board-flavor".
1954345233d7SLiam Girdwood  *
1955345233d7SLiam Girdwood  * We only keep number and alphabet characters and a few separator characters
1956345233d7SLiam Girdwood  * in the card long name since UCM in the user space uses the card long names
1957345233d7SLiam Girdwood  * as card configuration directory names and AudoConf cannot support special
1958345233d7SLiam Girdwood  * charactors like SPACE.
1959345233d7SLiam Girdwood  *
1960345233d7SLiam Girdwood  * Returns 0 on success, otherwise a negative error code.
1961345233d7SLiam Girdwood  */
1962345233d7SLiam Girdwood int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour)
1963345233d7SLiam Girdwood {
1964345233d7SLiam Girdwood 	const char *vendor, *product, *product_version, *board;
1965345233d7SLiam Girdwood 	size_t longname_buf_size = sizeof(card->snd_card->longname);
1966345233d7SLiam Girdwood 	size_t len;
1967345233d7SLiam Girdwood 
1968345233d7SLiam Girdwood 	if (card->long_name)
1969345233d7SLiam Girdwood 		return 0; /* long name already set by driver or from DMI */
1970345233d7SLiam Girdwood 
1971345233d7SLiam Girdwood 	/* make up dmi long name as: vendor.product.version.board */
1972345233d7SLiam Girdwood 	vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
197398faf436SMengdong Lin 	if (!vendor || !is_dmi_valid(vendor)) {
1974345233d7SLiam Girdwood 		dev_warn(card->dev, "ASoC: no DMI vendor name!\n");
1975345233d7SLiam Girdwood 		return 0;
1976345233d7SLiam Girdwood 	}
1977345233d7SLiam Girdwood 
197898faf436SMengdong Lin 
1979345233d7SLiam Girdwood 	snprintf(card->dmi_longname, sizeof(card->snd_card->longname),
1980345233d7SLiam Girdwood 			 "%s", vendor);
1981345233d7SLiam Girdwood 	cleanup_dmi_name(card->dmi_longname);
1982345233d7SLiam Girdwood 
1983345233d7SLiam Girdwood 	product = dmi_get_system_info(DMI_PRODUCT_NAME);
198498faf436SMengdong Lin 	if (product && is_dmi_valid(product)) {
1985345233d7SLiam Girdwood 		len = strlen(card->dmi_longname);
1986345233d7SLiam Girdwood 		snprintf(card->dmi_longname + len,
1987345233d7SLiam Girdwood 			 longname_buf_size - len,
1988345233d7SLiam Girdwood 			 "-%s", product);
1989345233d7SLiam Girdwood 
1990345233d7SLiam Girdwood 		len++;	/* skip the separator "-" */
1991345233d7SLiam Girdwood 		if (len < longname_buf_size)
1992345233d7SLiam Girdwood 			cleanup_dmi_name(card->dmi_longname + len);
1993345233d7SLiam Girdwood 
1994345233d7SLiam Girdwood 		/* some vendors like Lenovo may only put a self-explanatory
1995345233d7SLiam Girdwood 		 * name in the product version field
1996345233d7SLiam Girdwood 		 */
1997345233d7SLiam Girdwood 		product_version = dmi_get_system_info(DMI_PRODUCT_VERSION);
199898faf436SMengdong Lin 		if (product_version && is_dmi_valid(product_version)) {
1999345233d7SLiam Girdwood 			len = strlen(card->dmi_longname);
2000345233d7SLiam Girdwood 			snprintf(card->dmi_longname + len,
2001345233d7SLiam Girdwood 				 longname_buf_size - len,
2002345233d7SLiam Girdwood 				 "-%s", product_version);
2003345233d7SLiam Girdwood 
2004345233d7SLiam Girdwood 			len++;
2005345233d7SLiam Girdwood 			if (len < longname_buf_size)
2006345233d7SLiam Girdwood 				cleanup_dmi_name(card->dmi_longname + len);
2007345233d7SLiam Girdwood 		}
2008345233d7SLiam Girdwood 	}
2009345233d7SLiam Girdwood 
2010345233d7SLiam Girdwood 	board = dmi_get_system_info(DMI_BOARD_NAME);
201198faf436SMengdong Lin 	if (board && is_dmi_valid(board)) {
2012345233d7SLiam Girdwood 		len = strlen(card->dmi_longname);
2013345233d7SLiam Girdwood 		snprintf(card->dmi_longname + len,
2014345233d7SLiam Girdwood 			 longname_buf_size - len,
2015345233d7SLiam Girdwood 			 "-%s", board);
2016345233d7SLiam Girdwood 
2017345233d7SLiam Girdwood 		len++;
2018345233d7SLiam Girdwood 		if (len < longname_buf_size)
2019345233d7SLiam Girdwood 			cleanup_dmi_name(card->dmi_longname + len);
2020345233d7SLiam Girdwood 	} else if (!product) {
2021345233d7SLiam Girdwood 		/* fall back to using legacy name */
2022345233d7SLiam Girdwood 		dev_warn(card->dev, "ASoC: no DMI board/product name!\n");
2023345233d7SLiam Girdwood 		return 0;
2024345233d7SLiam Girdwood 	}
2025345233d7SLiam Girdwood 
2026345233d7SLiam Girdwood 	/* Add flavour to dmi long name */
2027345233d7SLiam Girdwood 	if (flavour) {
2028345233d7SLiam Girdwood 		len = strlen(card->dmi_longname);
2029345233d7SLiam Girdwood 		snprintf(card->dmi_longname + len,
2030345233d7SLiam Girdwood 			 longname_buf_size - len,
2031345233d7SLiam Girdwood 			 "-%s", flavour);
2032345233d7SLiam Girdwood 
2033345233d7SLiam Girdwood 		len++;
2034345233d7SLiam Girdwood 		if (len < longname_buf_size)
2035345233d7SLiam Girdwood 			cleanup_dmi_name(card->dmi_longname + len);
2036345233d7SLiam Girdwood 	}
2037345233d7SLiam Girdwood 
2038345233d7SLiam Girdwood 	/* set the card long name */
2039345233d7SLiam Girdwood 	card->long_name = card->dmi_longname;
2040345233d7SLiam Girdwood 
2041345233d7SLiam Girdwood 	return 0;
2042345233d7SLiam Girdwood }
2043345233d7SLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_set_dmi_name);
20441f5a4535STakashi Iwai #endif /* CONFIG_DMI */
2045345233d7SLiam Girdwood 
2046b19e6e7bSMark Brown static int snd_soc_instantiate_card(struct snd_soc_card *card)
2047f0fba2adSLiam Girdwood {
2048fdf0f54dSDimitris Papastamos 	struct snd_soc_codec *codec;
20491a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
205061b0088bSMengdong Lin 	struct snd_soc_dai_link *dai_link;
2051ce64c8b9SLars-Peter Clausen 	int ret, i, order;
205296dd3622SMark Brown 
205334e81ab4SLars-Peter Clausen 	mutex_lock(&client_mutex);
205401b9d99aSLiam Girdwood 	mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
2055f0fba2adSLiam Girdwood 
2056b19e6e7bSMark Brown 	/* bind DAIs */
2057b19e6e7bSMark Brown 	for (i = 0; i < card->num_links; i++) {
20586f2f1ff0SMengdong Lin 		ret = soc_bind_dai_link(card, &card->dai_link[i]);
2059b19e6e7bSMark Brown 		if (ret != 0)
2060b19e6e7bSMark Brown 			goto base_error;
2061db2a4165SFrank Mandarino 	}
2062db2a4165SFrank Mandarino 
206344c69bb1SLars-Peter Clausen 	/* bind aux_devs too */
2064b19e6e7bSMark Brown 	for (i = 0; i < card->num_aux_devs; i++) {
206544c69bb1SLars-Peter Clausen 		ret = soc_bind_aux_dev(card, i);
2066b19e6e7bSMark Brown 		if (ret != 0)
2067b19e6e7bSMark Brown 			goto base_error;
2068db2a4165SFrank Mandarino 	}
2069db2a4165SFrank Mandarino 
2070f8f80361SMengdong Lin 	/* add predefined DAI links to the list */
2071f8f80361SMengdong Lin 	for (i = 0; i < card->num_links; i++)
2072f8f80361SMengdong Lin 		snd_soc_add_dai_link(card, card->dai_link+i);
2073f8f80361SMengdong Lin 
2074fdf0f54dSDimitris Papastamos 	/* initialize the register cache for each available codec */
2075fdf0f54dSDimitris Papastamos 	list_for_each_entry(codec, &codec_list, list) {
2076fdf0f54dSDimitris Papastamos 		if (codec->cache_init)
2077fdf0f54dSDimitris Papastamos 			continue;
2078f90fb3f7SLars-Peter Clausen 		ret = snd_soc_init_codec_cache(codec);
2079b19e6e7bSMark Brown 		if (ret < 0)
2080b19e6e7bSMark Brown 			goto base_error;
2081fdf0f54dSDimitris Papastamos 	}
2082fdf0f54dSDimitris Papastamos 
2083f0fba2adSLiam Girdwood 	/* card bind complete so register a sound card */
2084102b5a8dSTakashi Iwai 	ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
2085f0fba2adSLiam Girdwood 			card->owner, 0, &card->snd_card);
2086f0fba2adSLiam Girdwood 	if (ret < 0) {
208710e8aa9aSMichał Mirosław 		dev_err(card->dev,
208810e8aa9aSMichał Mirosław 			"ASoC: can't create sound card for card %s: %d\n",
208910e8aa9aSMichał Mirosław 			card->name, ret);
2090b19e6e7bSMark Brown 		goto base_error;
2091db2a4165SFrank Mandarino 	}
2092db2a4165SFrank Mandarino 
20930757d834SLars-Peter Clausen 	soc_init_card_debugfs(card);
20940757d834SLars-Peter Clausen 
2095e37a4970SMark Brown 	card->dapm.bias_level = SND_SOC_BIAS_OFF;
2096e37a4970SMark Brown 	card->dapm.dev = card->dev;
2097e37a4970SMark Brown 	card->dapm.card = card;
2098e37a4970SMark Brown 	list_add(&card->dapm.list, &card->dapm_list);
2099e37a4970SMark Brown 
2100d5d1e0beSLars-Peter Clausen #ifdef CONFIG_DEBUG_FS
2101d5d1e0beSLars-Peter Clausen 	snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root);
2102d5d1e0beSLars-Peter Clausen #endif
2103d5d1e0beSLars-Peter Clausen 
210488ee1c61SMark Brown #ifdef CONFIG_PM_SLEEP
21056ed25978SAndy Green 	/* deferred resume work */
21066308419aSMark Brown 	INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
21071301a964SRandy Dunlap #endif
21086ed25978SAndy Green 
21099a841ebbSMark Brown 	if (card->dapm_widgets)
21109a841ebbSMark Brown 		snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
21119a841ebbSMark Brown 					  card->num_dapm_widgets);
21129a841ebbSMark Brown 
2113f23e860eSNicolin Chen 	if (card->of_dapm_widgets)
2114f23e860eSNicolin Chen 		snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets,
2115f23e860eSNicolin Chen 					  card->num_of_dapm_widgets);
2116f23e860eSNicolin Chen 
2117f0fba2adSLiam Girdwood 	/* initialise the sound card only once */
2118f0fba2adSLiam Girdwood 	if (card->probe) {
2119e7361ec4SMark Brown 		ret = card->probe(card);
2120f0fba2adSLiam Girdwood 		if (ret < 0)
2121f0fba2adSLiam Girdwood 			goto card_probe_error;
2122f0fba2adSLiam Girdwood 	}
2123f0fba2adSLiam Girdwood 
212462ae68faSStephen Warren 	/* probe all components used by DAI links on this card */
21250168bf0dSLiam Girdwood 	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
21260168bf0dSLiam Girdwood 			order++) {
21271a497983SMengdong Lin 		list_for_each_entry(rtd, &card->rtd_list, list) {
21281a497983SMengdong Lin 			ret = soc_probe_link_components(card, rtd, order);
212962ae68faSStephen Warren 			if (ret < 0) {
2130f110bfc7SLiam Girdwood 				dev_err(card->dev,
2131f110bfc7SLiam Girdwood 					"ASoC: failed to instantiate card %d\n",
2132f110bfc7SLiam Girdwood 					ret);
213362ae68faSStephen Warren 				goto probe_dai_err;
213462ae68faSStephen Warren 			}
213562ae68faSStephen Warren 		}
213662ae68faSStephen Warren 	}
213762ae68faSStephen Warren 
2138f2ed6b07SMengdong Lin 	/* probe auxiliary components */
2139f2ed6b07SMengdong Lin 	ret = soc_probe_aux_devices(card);
2140f2ed6b07SMengdong Lin 	if (ret < 0)
2141f2ed6b07SMengdong Lin 		goto probe_dai_err;
2142f2ed6b07SMengdong Lin 
214361b0088bSMengdong Lin 	/* Find new DAI links added during probing components and bind them.
214461b0088bSMengdong Lin 	 * Components with topology may bring new DAIs and DAI links.
214561b0088bSMengdong Lin 	 */
214661b0088bSMengdong Lin 	list_for_each_entry(dai_link, &card->dai_link_list, list) {
214761b0088bSMengdong Lin 		if (soc_is_dai_link_bound(card, dai_link))
214861b0088bSMengdong Lin 			continue;
214961b0088bSMengdong Lin 
215061b0088bSMengdong Lin 		ret = soc_init_dai_link(card, dai_link);
215161b0088bSMengdong Lin 		if (ret)
215261b0088bSMengdong Lin 			goto probe_dai_err;
215361b0088bSMengdong Lin 		ret = soc_bind_dai_link(card, dai_link);
215461b0088bSMengdong Lin 		if (ret)
215561b0088bSMengdong Lin 			goto probe_dai_err;
215661b0088bSMengdong Lin 	}
215761b0088bSMengdong Lin 
215862ae68faSStephen Warren 	/* probe all DAI links on this card */
215962ae68faSStephen Warren 	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
216062ae68faSStephen Warren 			order++) {
21611a497983SMengdong Lin 		list_for_each_entry(rtd, &card->rtd_list, list) {
21621a497983SMengdong Lin 			ret = soc_probe_link_dais(card, rtd, order);
2163fe3e78e0SMark Brown 			if (ret < 0) {
2164f110bfc7SLiam Girdwood 				dev_err(card->dev,
2165f110bfc7SLiam Girdwood 					"ASoC: failed to instantiate card %d\n",
2166f110bfc7SLiam Girdwood 					ret);
2167f0fba2adSLiam Girdwood 				goto probe_dai_err;
2168fe3e78e0SMark Brown 			}
2169fe3e78e0SMark Brown 		}
21700168bf0dSLiam Girdwood 	}
2171fe3e78e0SMark Brown 
2172888df395SMark Brown 	snd_soc_dapm_link_dai_widgets(card);
2173b893ea5fSLiam Girdwood 	snd_soc_dapm_connect_dai_link_widgets(card);
2174888df395SMark Brown 
2175b7af1dafSMark Brown 	if (card->controls)
2176022658beSLiam Girdwood 		snd_soc_add_card_controls(card, card->controls, card->num_controls);
2177b7af1dafSMark Brown 
2178b8ad29deSMark Brown 	if (card->dapm_routes)
2179b8ad29deSMark Brown 		snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
2180b8ad29deSMark Brown 					card->num_dapm_routes);
2181b8ad29deSMark Brown 
2182f23e860eSNicolin Chen 	if (card->of_dapm_routes)
2183f23e860eSNicolin Chen 		snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes,
2184f23e860eSNicolin Chen 					card->num_of_dapm_routes);
218575d9ac46SMark Brown 
2186861886d3STakashi Iwai 	/* try to set some sane longname if DMI is available */
2187861886d3STakashi Iwai 	snd_soc_set_dmi_name(card, NULL);
2188861886d3STakashi Iwai 
2189f0fba2adSLiam Girdwood 	snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
2190fe3e78e0SMark Brown 		 "%s", card->name);
2191f0fba2adSLiam Girdwood 	snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
219222de71baSLiam Girdwood 		 "%s", card->long_name ? card->long_name : card->name);
2193f0e8ed85SMark Brown 	snprintf(card->snd_card->driver, sizeof(card->snd_card->driver),
2194f0e8ed85SMark Brown 		 "%s", card->driver_name ? card->driver_name : card->name);
2195f0e8ed85SMark Brown 	for (i = 0; i < ARRAY_SIZE(card->snd_card->driver); i++) {
2196f0e8ed85SMark Brown 		switch (card->snd_card->driver[i]) {
2197f0e8ed85SMark Brown 		case '_':
2198f0e8ed85SMark Brown 		case '-':
2199f0e8ed85SMark Brown 		case '\0':
2200f0e8ed85SMark Brown 			break;
2201f0e8ed85SMark Brown 		default:
2202f0e8ed85SMark Brown 			if (!isalnum(card->snd_card->driver[i]))
2203f0e8ed85SMark Brown 				card->snd_card->driver[i] = '_';
2204f0e8ed85SMark Brown 			break;
2205f0e8ed85SMark Brown 		}
2206f0e8ed85SMark Brown 	}
2207fe3e78e0SMark Brown 
220828e9ad92SMark Brown 	if (card->late_probe) {
220928e9ad92SMark Brown 		ret = card->late_probe(card);
221028e9ad92SMark Brown 		if (ret < 0) {
2211f110bfc7SLiam Girdwood 			dev_err(card->dev, "ASoC: %s late_probe() failed: %d\n",
221228e9ad92SMark Brown 				card->name, ret);
221328e9ad92SMark Brown 			goto probe_aux_dev_err;
221428e9ad92SMark Brown 		}
221528e9ad92SMark Brown 	}
221628e9ad92SMark Brown 
2217824ef826SLars-Peter Clausen 	snd_soc_dapm_new_widgets(card);
22188c193b8dSLars-Peter Clausen 
2219f0fba2adSLiam Girdwood 	ret = snd_card_register(card->snd_card);
2220fe3e78e0SMark Brown 	if (ret < 0) {
2221f110bfc7SLiam Girdwood 		dev_err(card->dev, "ASoC: failed to register soundcard %d\n",
2222f110bfc7SLiam Girdwood 				ret);
22236b3ed785SAxel Lin 		goto probe_aux_dev_err;
2224fe3e78e0SMark Brown 	}
2225fe3e78e0SMark Brown 
2226435c5e25SMark Brown 	card->instantiated = 1;
22274f4c0072SMark Brown 	snd_soc_dapm_sync(&card->dapm);
2228f0fba2adSLiam Girdwood 	mutex_unlock(&card->mutex);
222934e81ab4SLars-Peter Clausen 	mutex_unlock(&client_mutex);
2230b19e6e7bSMark Brown 
2231b19e6e7bSMark Brown 	return 0;
2232db2a4165SFrank Mandarino 
22332eea392dSJarkko Nikula probe_aux_dev_err:
2234f2ed6b07SMengdong Lin 	soc_remove_aux_devices(card);
22352eea392dSJarkko Nikula 
2236f0fba2adSLiam Girdwood probe_dai_err:
22370671fd8eSKuninori Morimoto 	soc_remove_dai_links(card);
2238fe3e78e0SMark Brown 
2239f0fba2adSLiam Girdwood card_probe_error:
224087506549SMark Brown 	if (card->remove)
2241e7361ec4SMark Brown 		card->remove(card);
2242f0fba2adSLiam Girdwood 
22432210438bSLars-Peter Clausen 	snd_soc_dapm_free(&card->dapm);
22440757d834SLars-Peter Clausen 	soc_cleanup_card_debugfs(card);
2245f0fba2adSLiam Girdwood 	snd_card_free(card->snd_card);
2246f0fba2adSLiam Girdwood 
2247b19e6e7bSMark Brown base_error:
22481a497983SMengdong Lin 	soc_remove_pcm_runtimes(card);
2249f0fba2adSLiam Girdwood 	mutex_unlock(&card->mutex);
225034e81ab4SLars-Peter Clausen 	mutex_unlock(&client_mutex);
2251db2a4165SFrank Mandarino 
2252b19e6e7bSMark Brown 	return ret;
2253435c5e25SMark Brown }
2254435c5e25SMark Brown 
2255435c5e25SMark Brown /* probes a new socdev */
2256435c5e25SMark Brown static int soc_probe(struct platform_device *pdev)
2257435c5e25SMark Brown {
2258f0fba2adSLiam Girdwood 	struct snd_soc_card *card = platform_get_drvdata(pdev);
2259435c5e25SMark Brown 
226070a7ca34SVinod Koul 	/*
226170a7ca34SVinod Koul 	 * no card, so machine driver should be registering card
226270a7ca34SVinod Koul 	 * we should not be here in that case so ret error
226370a7ca34SVinod Koul 	 */
226470a7ca34SVinod Koul 	if (!card)
226570a7ca34SVinod Koul 		return -EINVAL;
226670a7ca34SVinod Koul 
2267fe4085e8SMark Brown 	dev_warn(&pdev->dev,
2268f110bfc7SLiam Girdwood 		 "ASoC: machine %s should use snd_soc_register_card()\n",
2269fe4085e8SMark Brown 		 card->name);
2270fe4085e8SMark Brown 
2271435c5e25SMark Brown 	/* Bodge while we unpick instantiation */
2272435c5e25SMark Brown 	card->dev = &pdev->dev;
2273f0fba2adSLiam Girdwood 
227428d528c8SMark Brown 	return snd_soc_register_card(card);
2275435c5e25SMark Brown }
2276435c5e25SMark Brown 
2277b0e26485SVinod Koul static int soc_cleanup_card_resources(struct snd_soc_card *card)
2278db2a4165SFrank Mandarino {
22791a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
2280db2a4165SFrank Mandarino 
2281f0fba2adSLiam Girdwood 	/* make sure any delayed work runs */
22821a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list)
228343829731STejun Heo 		flush_delayed_work(&rtd->delayed_work);
2284db2a4165SFrank Mandarino 
22854efda5f2STakashi Iwai 	/* free the ALSA card at first; this syncs with pending operations */
22864efda5f2STakashi Iwai 	snd_card_free(card->snd_card);
22874efda5f2STakashi Iwai 
2288f0fba2adSLiam Girdwood 	/* remove and free each DAI */
22890671fd8eSKuninori Morimoto 	soc_remove_dai_links(card);
22901a497983SMengdong Lin 	soc_remove_pcm_runtimes(card);
2291f0fba2adSLiam Girdwood 
2292f2ed6b07SMengdong Lin 	/* remove auxiliary devices */
2293f2ed6b07SMengdong Lin 	soc_remove_aux_devices(card);
2294f2ed6b07SMengdong Lin 
2295d1e81428SMark Brown 	snd_soc_dapm_free(&card->dapm);
2296a6052154SJarkko Nikula 	soc_cleanup_card_debugfs(card);
2297a6052154SJarkko Nikula 
2298f0fba2adSLiam Girdwood 	/* remove the card */
229987506549SMark Brown 	if (card->remove)
2300e7361ec4SMark Brown 		card->remove(card);
2301f0fba2adSLiam Girdwood 
2302b0e26485SVinod Koul 	return 0;
2303b2dfa62cSGuennadi Liakhovetski }
2304b0e26485SVinod Koul 
2305b0e26485SVinod Koul /* removes a socdev */
2306b0e26485SVinod Koul static int soc_remove(struct platform_device *pdev)
2307b0e26485SVinod Koul {
2308b0e26485SVinod Koul 	struct snd_soc_card *card = platform_get_drvdata(pdev);
2309b0e26485SVinod Koul 
2310c5af3a2eSMark Brown 	snd_soc_unregister_card(card);
2311db2a4165SFrank Mandarino 	return 0;
2312db2a4165SFrank Mandarino }
2313db2a4165SFrank Mandarino 
23146f8ab4acSMark Brown int snd_soc_poweroff(struct device *dev)
231551737470SMark Brown {
23166f8ab4acSMark Brown 	struct snd_soc_card *card = dev_get_drvdata(dev);
23171a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
231851737470SMark Brown 
231951737470SMark Brown 	if (!card->instantiated)
2320416356fcSMark Brown 		return 0;
232151737470SMark Brown 
232251737470SMark Brown 	/* Flush out pmdown_time work - we actually do want to run it
232351737470SMark Brown 	 * now, we're shutting down so no imminent restart. */
23241a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list)
232543829731STejun Heo 		flush_delayed_work(&rtd->delayed_work);
232651737470SMark Brown 
2327f0fba2adSLiam Girdwood 	snd_soc_dapm_shutdown(card);
2328416356fcSMark Brown 
2329988e8cc4SNicolin Chen 	/* deactivate pins to sleep state */
23301a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list) {
233188bd870fSBenoit Cousson 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
23321a497983SMengdong Lin 		int i;
233388bd870fSBenoit Cousson 
2334988e8cc4SNicolin Chen 		pinctrl_pm_select_sleep_state(cpu_dai->dev);
23351a497983SMengdong Lin 		for (i = 0; i < rtd->num_codecs; i++) {
23361a497983SMengdong Lin 			struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
233788bd870fSBenoit Cousson 			pinctrl_pm_select_sleep_state(codec_dai->dev);
233888bd870fSBenoit Cousson 		}
2339988e8cc4SNicolin Chen 	}
2340988e8cc4SNicolin Chen 
2341416356fcSMark Brown 	return 0;
234251737470SMark Brown }
23436f8ab4acSMark Brown EXPORT_SYMBOL_GPL(snd_soc_poweroff);
234451737470SMark Brown 
23456f8ab4acSMark Brown const struct dev_pm_ops snd_soc_pm_ops = {
2346b1dd5897SViresh Kumar 	.suspend = snd_soc_suspend,
2347b1dd5897SViresh Kumar 	.resume = snd_soc_resume,
2348b1dd5897SViresh Kumar 	.freeze = snd_soc_suspend,
2349b1dd5897SViresh Kumar 	.thaw = snd_soc_resume,
23506f8ab4acSMark Brown 	.poweroff = snd_soc_poweroff,
2351b1dd5897SViresh Kumar 	.restore = snd_soc_resume,
2352416356fcSMark Brown };
2353deb2607eSStephen Warren EXPORT_SYMBOL_GPL(snd_soc_pm_ops);
2354416356fcSMark Brown 
2355db2a4165SFrank Mandarino /* ASoC platform driver */
2356db2a4165SFrank Mandarino static struct platform_driver soc_driver = {
2357db2a4165SFrank Mandarino 	.driver		= {
2358db2a4165SFrank Mandarino 		.name		= "soc-audio",
23596f8ab4acSMark Brown 		.pm		= &snd_soc_pm_ops,
2360db2a4165SFrank Mandarino 	},
2361db2a4165SFrank Mandarino 	.probe		= soc_probe,
2362db2a4165SFrank Mandarino 	.remove		= soc_remove,
2363db2a4165SFrank Mandarino };
2364db2a4165SFrank Mandarino 
2365096e49d5SMark Brown /**
2366db2a4165SFrank Mandarino  * snd_soc_cnew - create new control
2367db2a4165SFrank Mandarino  * @_template: control template
2368db2a4165SFrank Mandarino  * @data: control private data
2369ac11a2b3SMark Brown  * @long_name: control long name
2370efb7ac3fSMark Brown  * @prefix: control name prefix
2371db2a4165SFrank Mandarino  *
2372db2a4165SFrank Mandarino  * Create a new mixer control from a template control.
2373db2a4165SFrank Mandarino  *
2374db2a4165SFrank Mandarino  * Returns 0 for success, else error.
2375db2a4165SFrank Mandarino  */
2376db2a4165SFrank Mandarino struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
23773056557fSMark Brown 				  void *data, const char *long_name,
2378efb7ac3fSMark Brown 				  const char *prefix)
2379db2a4165SFrank Mandarino {
2380db2a4165SFrank Mandarino 	struct snd_kcontrol_new template;
2381efb7ac3fSMark Brown 	struct snd_kcontrol *kcontrol;
2382efb7ac3fSMark Brown 	char *name = NULL;
2383db2a4165SFrank Mandarino 
2384db2a4165SFrank Mandarino 	memcpy(&template, _template, sizeof(template));
2385db2a4165SFrank Mandarino 	template.index = 0;
2386db2a4165SFrank Mandarino 
2387efb7ac3fSMark Brown 	if (!long_name)
2388efb7ac3fSMark Brown 		long_name = template.name;
2389efb7ac3fSMark Brown 
2390efb7ac3fSMark Brown 	if (prefix) {
23912b581074SLars-Peter Clausen 		name = kasprintf(GFP_KERNEL, "%s %s", prefix, long_name);
2392efb7ac3fSMark Brown 		if (!name)
2393efb7ac3fSMark Brown 			return NULL;
2394efb7ac3fSMark Brown 
2395efb7ac3fSMark Brown 		template.name = name;
2396efb7ac3fSMark Brown 	} else {
2397efb7ac3fSMark Brown 		template.name = long_name;
2398efb7ac3fSMark Brown 	}
2399efb7ac3fSMark Brown 
2400efb7ac3fSMark Brown 	kcontrol = snd_ctl_new1(&template, data);
2401efb7ac3fSMark Brown 
2402efb7ac3fSMark Brown 	kfree(name);
2403efb7ac3fSMark Brown 
2404efb7ac3fSMark Brown 	return kcontrol;
2405db2a4165SFrank Mandarino }
2406db2a4165SFrank Mandarino EXPORT_SYMBOL_GPL(snd_soc_cnew);
2407db2a4165SFrank Mandarino 
2408022658beSLiam Girdwood static int snd_soc_add_controls(struct snd_card *card, struct device *dev,
2409022658beSLiam Girdwood 	const struct snd_kcontrol_new *controls, int num_controls,
2410022658beSLiam Girdwood 	const char *prefix, void *data)
2411022658beSLiam Girdwood {
2412022658beSLiam Girdwood 	int err, i;
2413022658beSLiam Girdwood 
2414022658beSLiam Girdwood 	for (i = 0; i < num_controls; i++) {
2415022658beSLiam Girdwood 		const struct snd_kcontrol_new *control = &controls[i];
2416022658beSLiam Girdwood 		err = snd_ctl_add(card, snd_soc_cnew(control, data,
2417022658beSLiam Girdwood 						     control->name, prefix));
2418022658beSLiam Girdwood 		if (err < 0) {
2419f110bfc7SLiam Girdwood 			dev_err(dev, "ASoC: Failed to add %s: %d\n",
2420f110bfc7SLiam Girdwood 				control->name, err);
2421022658beSLiam Girdwood 			return err;
2422022658beSLiam Girdwood 		}
2423022658beSLiam Girdwood 	}
2424022658beSLiam Girdwood 
2425022658beSLiam Girdwood 	return 0;
2426022658beSLiam Girdwood }
2427022658beSLiam Girdwood 
24284fefd698SDimitris Papastamos struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
24294fefd698SDimitris Papastamos 					       const char *name)
24304fefd698SDimitris Papastamos {
24314fefd698SDimitris Papastamos 	struct snd_card *card = soc_card->snd_card;
24324fefd698SDimitris Papastamos 	struct snd_kcontrol *kctl;
24334fefd698SDimitris Papastamos 
24344fefd698SDimitris Papastamos 	if (unlikely(!name))
24354fefd698SDimitris Papastamos 		return NULL;
24364fefd698SDimitris Papastamos 
24374fefd698SDimitris Papastamos 	list_for_each_entry(kctl, &card->controls, list)
24384fefd698SDimitris Papastamos 		if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name)))
24394fefd698SDimitris Papastamos 			return kctl;
24404fefd698SDimitris Papastamos 	return NULL;
24414fefd698SDimitris Papastamos }
24424fefd698SDimitris Papastamos EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol);
24434fefd698SDimitris Papastamos 
2444db2a4165SFrank Mandarino /**
24450f2780adSLars-Peter Clausen  * snd_soc_add_component_controls - Add an array of controls to a component.
24460f2780adSLars-Peter Clausen  *
24470f2780adSLars-Peter Clausen  * @component: Component to add controls to
24480f2780adSLars-Peter Clausen  * @controls: Array of controls to add
24490f2780adSLars-Peter Clausen  * @num_controls: Number of elements in the array
24500f2780adSLars-Peter Clausen  *
24510f2780adSLars-Peter Clausen  * Return: 0 for success, else error.
24520f2780adSLars-Peter Clausen  */
24530f2780adSLars-Peter Clausen int snd_soc_add_component_controls(struct snd_soc_component *component,
24540f2780adSLars-Peter Clausen 	const struct snd_kcontrol_new *controls, unsigned int num_controls)
24550f2780adSLars-Peter Clausen {
24560f2780adSLars-Peter Clausen 	struct snd_card *card = component->card->snd_card;
24570f2780adSLars-Peter Clausen 
24580f2780adSLars-Peter Clausen 	return snd_soc_add_controls(card, component->dev, controls,
24590f2780adSLars-Peter Clausen 			num_controls, component->name_prefix, component);
24600f2780adSLars-Peter Clausen }
24610f2780adSLars-Peter Clausen EXPORT_SYMBOL_GPL(snd_soc_add_component_controls);
24620f2780adSLars-Peter Clausen 
24630f2780adSLars-Peter Clausen /**
2464022658beSLiam Girdwood  * snd_soc_add_codec_controls - add an array of controls to a codec.
2465022658beSLiam Girdwood  * Convenience function to add a list of controls. Many codecs were
24663e8e1952SIan Molton  * duplicating this code.
24673e8e1952SIan Molton  *
24683e8e1952SIan Molton  * @codec: codec to add controls to
24693e8e1952SIan Molton  * @controls: array of controls to add
24703e8e1952SIan Molton  * @num_controls: number of elements in the array
24713e8e1952SIan Molton  *
24723e8e1952SIan Molton  * Return 0 for success, else error.
24733e8e1952SIan Molton  */
2474022658beSLiam Girdwood int snd_soc_add_codec_controls(struct snd_soc_codec *codec,
24750f2780adSLars-Peter Clausen 	const struct snd_kcontrol_new *controls, unsigned int num_controls)
24763e8e1952SIan Molton {
24770f2780adSLars-Peter Clausen 	return snd_soc_add_component_controls(&codec->component, controls,
24780f2780adSLars-Peter Clausen 		num_controls);
24793e8e1952SIan Molton }
2480022658beSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_add_codec_controls);
24813e8e1952SIan Molton 
24823e8e1952SIan Molton /**
2483022658beSLiam Girdwood  * snd_soc_add_card_controls - add an array of controls to a SoC card.
2484022658beSLiam Girdwood  * Convenience function to add a list of controls.
2485022658beSLiam Girdwood  *
2486022658beSLiam Girdwood  * @soc_card: SoC card to add controls to
2487022658beSLiam Girdwood  * @controls: array of controls to add
2488022658beSLiam Girdwood  * @num_controls: number of elements in the array
2489022658beSLiam Girdwood  *
2490022658beSLiam Girdwood  * Return 0 for success, else error.
2491022658beSLiam Girdwood  */
2492022658beSLiam Girdwood int snd_soc_add_card_controls(struct snd_soc_card *soc_card,
2493022658beSLiam Girdwood 	const struct snd_kcontrol_new *controls, int num_controls)
2494022658beSLiam Girdwood {
2495022658beSLiam Girdwood 	struct snd_card *card = soc_card->snd_card;
2496022658beSLiam Girdwood 
2497022658beSLiam Girdwood 	return snd_soc_add_controls(card, soc_card->dev, controls, num_controls,
2498022658beSLiam Girdwood 			NULL, soc_card);
2499022658beSLiam Girdwood }
2500022658beSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_add_card_controls);
2501022658beSLiam Girdwood 
2502022658beSLiam Girdwood /**
2503022658beSLiam Girdwood  * snd_soc_add_dai_controls - add an array of controls to a DAI.
2504022658beSLiam Girdwood  * Convienience function to add a list of controls.
2505022658beSLiam Girdwood  *
2506022658beSLiam Girdwood  * @dai: DAI to add controls to
2507022658beSLiam Girdwood  * @controls: array of controls to add
2508022658beSLiam Girdwood  * @num_controls: number of elements in the array
2509022658beSLiam Girdwood  *
2510022658beSLiam Girdwood  * Return 0 for success, else error.
2511022658beSLiam Girdwood  */
2512022658beSLiam Girdwood int snd_soc_add_dai_controls(struct snd_soc_dai *dai,
2513022658beSLiam Girdwood 	const struct snd_kcontrol_new *controls, int num_controls)
2514022658beSLiam Girdwood {
2515313665b9SLars-Peter Clausen 	struct snd_card *card = dai->component->card->snd_card;
2516022658beSLiam Girdwood 
2517022658beSLiam Girdwood 	return snd_soc_add_controls(card, dai->dev, controls, num_controls,
2518022658beSLiam Girdwood 			NULL, dai);
2519022658beSLiam Girdwood }
2520022658beSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls);
2521022658beSLiam Girdwood 
2522022658beSLiam Girdwood /**
25238c6529dbSLiam Girdwood  * snd_soc_dai_set_sysclk - configure DAI system or master clock.
25248c6529dbSLiam Girdwood  * @dai: DAI
25258c6529dbSLiam Girdwood  * @clk_id: DAI specific clock ID
25268c6529dbSLiam Girdwood  * @freq: new clock frequency in Hz
25278c6529dbSLiam Girdwood  * @dir: new clock direction - input/output.
25288c6529dbSLiam Girdwood  *
25298c6529dbSLiam Girdwood  * Configures the DAI master (MCLK) or system (SYSCLK) clocking.
25308c6529dbSLiam Girdwood  */
25318c6529dbSLiam Girdwood int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
25328c6529dbSLiam Girdwood 	unsigned int freq, int dir)
25338c6529dbSLiam Girdwood {
253446471925SKuninori Morimoto 	if (dai->driver->ops->set_sysclk)
2535f0fba2adSLiam Girdwood 		return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
253671ccef0dSKuninori Morimoto 
253771ccef0dSKuninori Morimoto 	return snd_soc_component_set_sysclk(dai->component, clk_id, 0,
2538ec4ee52aSMark Brown 					    freq, dir);
25398c6529dbSLiam Girdwood }
25408c6529dbSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
25418c6529dbSLiam Girdwood 
25428c6529dbSLiam Girdwood /**
2543ec4ee52aSMark Brown  * snd_soc_codec_set_sysclk - configure CODEC system or master clock.
2544ec4ee52aSMark Brown  * @codec: CODEC
2545ec4ee52aSMark Brown  * @clk_id: DAI specific clock ID
2546da1c6ea6SMark Brown  * @source: Source for the clock
2547ec4ee52aSMark Brown  * @freq: new clock frequency in Hz
2548ec4ee52aSMark Brown  * @dir: new clock direction - input/output.
2549ec4ee52aSMark Brown  *
2550ec4ee52aSMark Brown  * Configures the CODEC master (MCLK) or system (SYSCLK) clocking.
2551ec4ee52aSMark Brown  */
2552ec4ee52aSMark Brown int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id,
2553da1c6ea6SMark Brown 			     int source, unsigned int freq, int dir)
2554ec4ee52aSMark Brown {
2555ec4ee52aSMark Brown 	if (codec->driver->set_sysclk)
2556da1c6ea6SMark Brown 		return codec->driver->set_sysclk(codec, clk_id, source,
2557da1c6ea6SMark Brown 						 freq, dir);
2558ec4ee52aSMark Brown 	else
25591104a9c8SMark Brown 		return -ENOTSUPP;
2560ec4ee52aSMark Brown }
2561ec4ee52aSMark Brown EXPORT_SYMBOL_GPL(snd_soc_codec_set_sysclk);
2562ec4ee52aSMark Brown 
2563ec4ee52aSMark Brown /**
256471ccef0dSKuninori Morimoto  * snd_soc_component_set_sysclk - configure COMPONENT system or master clock.
256571ccef0dSKuninori Morimoto  * @component: COMPONENT
256671ccef0dSKuninori Morimoto  * @clk_id: DAI specific clock ID
256771ccef0dSKuninori Morimoto  * @source: Source for the clock
256871ccef0dSKuninori Morimoto  * @freq: new clock frequency in Hz
256971ccef0dSKuninori Morimoto  * @dir: new clock direction - input/output.
257071ccef0dSKuninori Morimoto  *
257171ccef0dSKuninori Morimoto  * Configures the CODEC master (MCLK) or system (SYSCLK) clocking.
257271ccef0dSKuninori Morimoto  */
257371ccef0dSKuninori Morimoto int snd_soc_component_set_sysclk(struct snd_soc_component *component, int clk_id,
257471ccef0dSKuninori Morimoto 			     int source, unsigned int freq, int dir)
257571ccef0dSKuninori Morimoto {
257671ccef0dSKuninori Morimoto 	/* will be removed */
257771ccef0dSKuninori Morimoto 	if (component->set_sysclk)
257871ccef0dSKuninori Morimoto 		return component->set_sysclk(component, clk_id, source,
257971ccef0dSKuninori Morimoto 					     freq, dir);
258071ccef0dSKuninori Morimoto 
258171ccef0dSKuninori Morimoto 	if (component->driver->set_sysclk)
258271ccef0dSKuninori Morimoto 		return component->driver->set_sysclk(component, clk_id, source,
258371ccef0dSKuninori Morimoto 						 freq, dir);
258471ccef0dSKuninori Morimoto 
258571ccef0dSKuninori Morimoto 	return -ENOTSUPP;
258671ccef0dSKuninori Morimoto }
258771ccef0dSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_component_set_sysclk);
258871ccef0dSKuninori Morimoto 
258971ccef0dSKuninori Morimoto /**
25908c6529dbSLiam Girdwood  * snd_soc_dai_set_clkdiv - configure DAI clock dividers.
25918c6529dbSLiam Girdwood  * @dai: DAI
2592ac11a2b3SMark Brown  * @div_id: DAI specific clock divider ID
25938c6529dbSLiam Girdwood  * @div: new clock divisor.
25948c6529dbSLiam Girdwood  *
25958c6529dbSLiam Girdwood  * Configures the clock dividers. This is used to derive the best DAI bit and
25968c6529dbSLiam Girdwood  * frame clocks from the system or master clock. It's best to set the DAI bit
25978c6529dbSLiam Girdwood  * and frame clocks as low as possible to save system power.
25988c6529dbSLiam Girdwood  */
25998c6529dbSLiam Girdwood int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
26008c6529dbSLiam Girdwood 	int div_id, int div)
26018c6529dbSLiam Girdwood {
260246471925SKuninori Morimoto 	if (dai->driver->ops->set_clkdiv)
2603f0fba2adSLiam Girdwood 		return dai->driver->ops->set_clkdiv(dai, div_id, div);
26048c6529dbSLiam Girdwood 	else
26058c6529dbSLiam Girdwood 		return -EINVAL;
26068c6529dbSLiam Girdwood }
26078c6529dbSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
26088c6529dbSLiam Girdwood 
26098c6529dbSLiam Girdwood /**
26108c6529dbSLiam Girdwood  * snd_soc_dai_set_pll - configure DAI PLL.
26118c6529dbSLiam Girdwood  * @dai: DAI
26128c6529dbSLiam Girdwood  * @pll_id: DAI specific PLL ID
261385488037SMark Brown  * @source: DAI specific source for the PLL
26148c6529dbSLiam Girdwood  * @freq_in: PLL input clock frequency in Hz
26158c6529dbSLiam Girdwood  * @freq_out: requested PLL output clock frequency in Hz
26168c6529dbSLiam Girdwood  *
26178c6529dbSLiam Girdwood  * Configures and enables PLL to generate output clock based on input clock.
26188c6529dbSLiam Girdwood  */
261985488037SMark Brown int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
262085488037SMark Brown 	unsigned int freq_in, unsigned int freq_out)
26218c6529dbSLiam Girdwood {
262246471925SKuninori Morimoto 	if (dai->driver->ops->set_pll)
2623f0fba2adSLiam Girdwood 		return dai->driver->ops->set_pll(dai, pll_id, source,
262485488037SMark Brown 					 freq_in, freq_out);
2625ef641e5dSKuninori Morimoto 
2626ef641e5dSKuninori Morimoto 	return snd_soc_component_set_pll(dai->component, pll_id, source,
2627ec4ee52aSMark Brown 					 freq_in, freq_out);
26288c6529dbSLiam Girdwood }
26298c6529dbSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
26308c6529dbSLiam Girdwood 
2631ec4ee52aSMark Brown /*
2632ec4ee52aSMark Brown  * snd_soc_codec_set_pll - configure codec PLL.
2633ec4ee52aSMark Brown  * @codec: CODEC
2634ec4ee52aSMark Brown  * @pll_id: DAI specific PLL ID
2635ec4ee52aSMark Brown  * @source: DAI specific source for the PLL
2636ec4ee52aSMark Brown  * @freq_in: PLL input clock frequency in Hz
2637ec4ee52aSMark Brown  * @freq_out: requested PLL output clock frequency in Hz
2638ec4ee52aSMark Brown  *
2639ec4ee52aSMark Brown  * Configures and enables PLL to generate output clock based on input clock.
2640ec4ee52aSMark Brown  */
2641ec4ee52aSMark Brown int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
2642ec4ee52aSMark Brown 			  unsigned int freq_in, unsigned int freq_out)
2643ec4ee52aSMark Brown {
2644ec4ee52aSMark Brown 	if (codec->driver->set_pll)
2645ec4ee52aSMark Brown 		return codec->driver->set_pll(codec, pll_id, source,
2646ec4ee52aSMark Brown 					      freq_in, freq_out);
2647ec4ee52aSMark Brown 	else
2648ec4ee52aSMark Brown 		return -EINVAL;
2649ec4ee52aSMark Brown }
2650ec4ee52aSMark Brown EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll);
2651ec4ee52aSMark Brown 
2652ef641e5dSKuninori Morimoto /*
2653ef641e5dSKuninori Morimoto  * snd_soc_component_set_pll - configure component PLL.
2654ef641e5dSKuninori Morimoto  * @component: COMPONENT
2655ef641e5dSKuninori Morimoto  * @pll_id: DAI specific PLL ID
2656ef641e5dSKuninori Morimoto  * @source: DAI specific source for the PLL
2657ef641e5dSKuninori Morimoto  * @freq_in: PLL input clock frequency in Hz
2658ef641e5dSKuninori Morimoto  * @freq_out: requested PLL output clock frequency in Hz
2659ef641e5dSKuninori Morimoto  *
2660ef641e5dSKuninori Morimoto  * Configures and enables PLL to generate output clock based on input clock.
2661ef641e5dSKuninori Morimoto  */
2662ef641e5dSKuninori Morimoto int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id,
2663ef641e5dSKuninori Morimoto 			      int source, unsigned int freq_in,
2664ef641e5dSKuninori Morimoto 			      unsigned int freq_out)
2665ef641e5dSKuninori Morimoto {
2666ef641e5dSKuninori Morimoto 	/* will be removed */
2667ef641e5dSKuninori Morimoto 	if (component->set_pll)
2668ef641e5dSKuninori Morimoto 		return component->set_pll(component, pll_id, source,
2669ef641e5dSKuninori Morimoto 					      freq_in, freq_out);
2670ef641e5dSKuninori Morimoto 
2671ef641e5dSKuninori Morimoto 	if (component->driver->set_pll)
2672ef641e5dSKuninori Morimoto 		return component->driver->set_pll(component, pll_id, source,
2673ef641e5dSKuninori Morimoto 					      freq_in, freq_out);
2674ef641e5dSKuninori Morimoto 
2675ef641e5dSKuninori Morimoto 	return -EINVAL;
2676ef641e5dSKuninori Morimoto }
2677ef641e5dSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_component_set_pll);
2678ef641e5dSKuninori Morimoto 
26798c6529dbSLiam Girdwood /**
2680e54cf76bSLiam Girdwood  * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio.
2681e54cf76bSLiam Girdwood  * @dai: DAI
2682231b86b1SMasanari Iida  * @ratio: Ratio of BCLK to Sample rate.
2683e54cf76bSLiam Girdwood  *
2684e54cf76bSLiam Girdwood  * Configures the DAI for a preset BCLK to sample rate ratio.
2685e54cf76bSLiam Girdwood  */
2686e54cf76bSLiam Girdwood int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
2687e54cf76bSLiam Girdwood {
268846471925SKuninori Morimoto 	if (dai->driver->ops->set_bclk_ratio)
2689e54cf76bSLiam Girdwood 		return dai->driver->ops->set_bclk_ratio(dai, ratio);
2690e54cf76bSLiam Girdwood 	else
2691e54cf76bSLiam Girdwood 		return -EINVAL;
2692e54cf76bSLiam Girdwood }
2693e54cf76bSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
2694e54cf76bSLiam Girdwood 
2695e54cf76bSLiam Girdwood /**
26968c6529dbSLiam Girdwood  * snd_soc_dai_set_fmt - configure DAI hardware audio format.
26978c6529dbSLiam Girdwood  * @dai: DAI
2698bb19ba2aSRandy Dunlap  * @fmt: SND_SOC_DAIFMT_* format value.
26998c6529dbSLiam Girdwood  *
27008c6529dbSLiam Girdwood  * Configures the DAI hardware format and clocking.
27018c6529dbSLiam Girdwood  */
27028c6529dbSLiam Girdwood int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
27038c6529dbSLiam Girdwood {
27045e4ba569SShawn Guo 	if (dai->driver == NULL)
27058c6529dbSLiam Girdwood 		return -EINVAL;
27065e4ba569SShawn Guo 	if (dai->driver->ops->set_fmt == NULL)
27075e4ba569SShawn Guo 		return -ENOTSUPP;
27085e4ba569SShawn Guo 	return dai->driver->ops->set_fmt(dai, fmt);
27098c6529dbSLiam Girdwood }
27108c6529dbSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
27118c6529dbSLiam Girdwood 
27128c6529dbSLiam Girdwood /**
2713e5c21514SXiubo Li  * snd_soc_xlate_tdm_slot - generate tx/rx slot mask.
271489c67857SXiubo Li  * @slots: Number of slots in use.
271589c67857SXiubo Li  * @tx_mask: bitmask representing active TX slots.
271689c67857SXiubo Li  * @rx_mask: bitmask representing active RX slots.
271789c67857SXiubo Li  *
271889c67857SXiubo Li  * Generates the TDM tx and rx slot default masks for DAI.
271989c67857SXiubo Li  */
2720e5c21514SXiubo Li static int snd_soc_xlate_tdm_slot_mask(unsigned int slots,
272189c67857SXiubo Li 					  unsigned int *tx_mask,
272289c67857SXiubo Li 					  unsigned int *rx_mask)
272389c67857SXiubo Li {
272489c67857SXiubo Li 	if (*tx_mask || *rx_mask)
272589c67857SXiubo Li 		return 0;
272689c67857SXiubo Li 
272789c67857SXiubo Li 	if (!slots)
272889c67857SXiubo Li 		return -EINVAL;
272989c67857SXiubo Li 
273089c67857SXiubo Li 	*tx_mask = (1 << slots) - 1;
273189c67857SXiubo Li 	*rx_mask = (1 << slots) - 1;
273289c67857SXiubo Li 
273389c67857SXiubo Li 	return 0;
273489c67857SXiubo Li }
273589c67857SXiubo Li 
273689c67857SXiubo Li /**
2737e46c9366SLars-Peter Clausen  * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation
2738e46c9366SLars-Peter Clausen  * @dai: The DAI to configure
2739a5479e38SDaniel Ribeiro  * @tx_mask: bitmask representing active TX slots.
2740a5479e38SDaniel Ribeiro  * @rx_mask: bitmask representing active RX slots.
27418c6529dbSLiam Girdwood  * @slots: Number of slots in use.
2742a5479e38SDaniel Ribeiro  * @slot_width: Width in bits for each slot.
27438c6529dbSLiam Girdwood  *
2744e46c9366SLars-Peter Clausen  * This function configures the specified DAI for TDM operation. @slot contains
2745e46c9366SLars-Peter Clausen  * the total number of slots of the TDM stream and @slot_with the width of each
2746e46c9366SLars-Peter Clausen  * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the
2747e46c9366SLars-Peter Clausen  * active slots of the TDM stream for the specified DAI, i.e. which slots the
2748e46c9366SLars-Peter Clausen  * DAI should write to or read from. If a bit is set the corresponding slot is
2749e46c9366SLars-Peter Clausen  * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to
2750e46c9366SLars-Peter Clausen  * the first slot, bit 1 to the second slot and so on. The first active slot
2751e46c9366SLars-Peter Clausen  * maps to the first channel of the DAI, the second active slot to the second
2752e46c9366SLars-Peter Clausen  * channel and so on.
2753e46c9366SLars-Peter Clausen  *
2754e46c9366SLars-Peter Clausen  * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask,
2755e46c9366SLars-Peter Clausen  * @rx_mask and @slot_width will be ignored.
2756e46c9366SLars-Peter Clausen  *
2757e46c9366SLars-Peter Clausen  * Returns 0 on success, a negative error code otherwise.
27588c6529dbSLiam Girdwood  */
27598c6529dbSLiam Girdwood int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
2760a5479e38SDaniel Ribeiro 	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
27618c6529dbSLiam Girdwood {
276246471925SKuninori Morimoto 	if (dai->driver->ops->xlate_tdm_slot_mask)
2763e5c21514SXiubo Li 		dai->driver->ops->xlate_tdm_slot_mask(slots,
276489c67857SXiubo Li 						&tx_mask, &rx_mask);
276589c67857SXiubo Li 	else
2766e5c21514SXiubo Li 		snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
276789c67857SXiubo Li 
276888bd870fSBenoit Cousson 	dai->tx_mask = tx_mask;
276988bd870fSBenoit Cousson 	dai->rx_mask = rx_mask;
277088bd870fSBenoit Cousson 
277146471925SKuninori Morimoto 	if (dai->driver->ops->set_tdm_slot)
2772f0fba2adSLiam Girdwood 		return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
2773a5479e38SDaniel Ribeiro 				slots, slot_width);
27748c6529dbSLiam Girdwood 	else
2775b2cbb6e1SXiubo Li 		return -ENOTSUPP;
27768c6529dbSLiam Girdwood }
27778c6529dbSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
27788c6529dbSLiam Girdwood 
27798c6529dbSLiam Girdwood /**
2780472df3cbSBarry Song  * snd_soc_dai_set_channel_map - configure DAI audio channel map
2781472df3cbSBarry Song  * @dai: DAI
2782472df3cbSBarry Song  * @tx_num: how many TX channels
2783472df3cbSBarry Song  * @tx_slot: pointer to an array which imply the TX slot number channel
2784472df3cbSBarry Song  *           0~num-1 uses
2785472df3cbSBarry Song  * @rx_num: how many RX channels
2786472df3cbSBarry Song  * @rx_slot: pointer to an array which imply the RX slot number channel
2787472df3cbSBarry Song  *           0~num-1 uses
2788472df3cbSBarry Song  *
2789472df3cbSBarry Song  * configure the relationship between channel number and TDM slot number.
2790472df3cbSBarry Song  */
2791472df3cbSBarry Song int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
2792472df3cbSBarry Song 	unsigned int tx_num, unsigned int *tx_slot,
2793472df3cbSBarry Song 	unsigned int rx_num, unsigned int *rx_slot)
2794472df3cbSBarry Song {
279546471925SKuninori Morimoto 	if (dai->driver->ops->set_channel_map)
2796f0fba2adSLiam Girdwood 		return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
2797472df3cbSBarry Song 			rx_num, rx_slot);
2798472df3cbSBarry Song 	else
2799472df3cbSBarry Song 		return -EINVAL;
2800472df3cbSBarry Song }
2801472df3cbSBarry Song EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
2802472df3cbSBarry Song 
2803472df3cbSBarry Song /**
28048c6529dbSLiam Girdwood  * snd_soc_dai_set_tristate - configure DAI system or master clock.
28058c6529dbSLiam Girdwood  * @dai: DAI
28068c6529dbSLiam Girdwood  * @tristate: tristate enable
28078c6529dbSLiam Girdwood  *
28088c6529dbSLiam Girdwood  * Tristates the DAI so that others can use it.
28098c6529dbSLiam Girdwood  */
28108c6529dbSLiam Girdwood int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
28118c6529dbSLiam Girdwood {
281246471925SKuninori Morimoto 	if (dai->driver->ops->set_tristate)
2813f0fba2adSLiam Girdwood 		return dai->driver->ops->set_tristate(dai, tristate);
28148c6529dbSLiam Girdwood 	else
28158c6529dbSLiam Girdwood 		return -EINVAL;
28168c6529dbSLiam Girdwood }
28178c6529dbSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
28188c6529dbSLiam Girdwood 
28198c6529dbSLiam Girdwood /**
28208c6529dbSLiam Girdwood  * snd_soc_dai_digital_mute - configure DAI system or master clock.
28218c6529dbSLiam Girdwood  * @dai: DAI
28228c6529dbSLiam Girdwood  * @mute: mute enable
2823da18396fSMark Brown  * @direction: stream to mute
28248c6529dbSLiam Girdwood  *
28258c6529dbSLiam Girdwood  * Mutes the DAI DAC.
28268c6529dbSLiam Girdwood  */
2827da18396fSMark Brown int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
2828da18396fSMark Brown 			     int direction)
28298c6529dbSLiam Girdwood {
2830da18396fSMark Brown 	if (!dai->driver)
2831da18396fSMark Brown 		return -ENOTSUPP;
2832da18396fSMark Brown 
2833da18396fSMark Brown 	if (dai->driver->ops->mute_stream)
2834da18396fSMark Brown 		return dai->driver->ops->mute_stream(dai, mute, direction);
2835da18396fSMark Brown 	else if (direction == SNDRV_PCM_STREAM_PLAYBACK &&
2836da18396fSMark Brown 		 dai->driver->ops->digital_mute)
2837f0fba2adSLiam Girdwood 		return dai->driver->ops->digital_mute(dai, mute);
28388c6529dbSLiam Girdwood 	else
283904570c62SMark Brown 		return -ENOTSUPP;
28408c6529dbSLiam Girdwood }
28418c6529dbSLiam Girdwood EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
28428c6529dbSLiam Girdwood 
2843c5af3a2eSMark Brown /**
2844c5af3a2eSMark Brown  * snd_soc_register_card - Register a card with the ASoC core
2845c5af3a2eSMark Brown  *
2846ac11a2b3SMark Brown  * @card: Card to register
2847c5af3a2eSMark Brown  *
2848c5af3a2eSMark Brown  */
284970a7ca34SVinod Koul int snd_soc_register_card(struct snd_soc_card *card)
2850c5af3a2eSMark Brown {
2851923c5e61SMengdong Lin 	int i, ret;
28521a497983SMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
2853f0fba2adSLiam Girdwood 
2854c5af3a2eSMark Brown 	if (!card->name || !card->dev)
2855c5af3a2eSMark Brown 		return -EINVAL;
2856c5af3a2eSMark Brown 
28575a504963SStephen Warren 	for (i = 0; i < card->num_links; i++) {
28585a504963SStephen Warren 		struct snd_soc_dai_link *link = &card->dai_link[i];
28595a504963SStephen Warren 
2860923c5e61SMengdong Lin 		ret = soc_init_dai_link(card, link);
286188bd870fSBenoit Cousson 		if (ret) {
2862923c5e61SMengdong Lin 			dev_err(card->dev, "ASoC: failed to init link %s\n",
2863923c5e61SMengdong Lin 				link->name);
286488bd870fSBenoit Cousson 			return ret;
286588bd870fSBenoit Cousson 		}
28665a504963SStephen Warren 	}
28675a504963SStephen Warren 
2868ed77cc12SMark Brown 	dev_set_drvdata(card->dev, card);
2869ed77cc12SMark Brown 
2870111c6419SStephen Warren 	snd_soc_initialize_card_lists(card);
2871111c6419SStephen Warren 
2872f8f80361SMengdong Lin 	INIT_LIST_HEAD(&card->dai_link_list);
2873f8f80361SMengdong Lin 	card->num_dai_links = 0;
2874f0fba2adSLiam Girdwood 
28751a497983SMengdong Lin 	INIT_LIST_HEAD(&card->rtd_list);
28769115171aSMark Brown 	card->num_rtd = 0;
2877db2a4165SFrank Mandarino 
2878db432b41SMark Brown 	INIT_LIST_HEAD(&card->dapm_dirty);
28798a978234SLiam Girdwood 	INIT_LIST_HEAD(&card->dobj_list);
2880db2a4165SFrank Mandarino 	card->instantiated = 0;
2881db2a4165SFrank Mandarino 	mutex_init(&card->mutex);
2882a73fb2dfSLiam Girdwood 	mutex_init(&card->dapm_mutex);
2883db2a4165SFrank Mandarino 
2884b19e6e7bSMark Brown 	ret = snd_soc_instantiate_card(card);
2885b19e6e7bSMark Brown 	if (ret != 0)
28864e2576bdSKuninori Morimoto 		return ret;
2887db2a4165SFrank Mandarino 
2888988e8cc4SNicolin Chen 	/* deactivate pins to sleep state */
28891a497983SMengdong Lin 	list_for_each_entry(rtd, &card->rtd_list, list)  {
289088bd870fSBenoit Cousson 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
289188bd870fSBenoit Cousson 		int j;
289288bd870fSBenoit Cousson 
289388bd870fSBenoit Cousson 		for (j = 0; j < rtd->num_codecs; j++) {
289488bd870fSBenoit Cousson 			struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
2895988e8cc4SNicolin Chen 			if (!codec_dai->active)
2896988e8cc4SNicolin Chen 				pinctrl_pm_select_sleep_state(codec_dai->dev);
289788bd870fSBenoit Cousson 		}
289888bd870fSBenoit Cousson 
2899988e8cc4SNicolin Chen 		if (!cpu_dai->active)
2900988e8cc4SNicolin Chen 			pinctrl_pm_select_sleep_state(cpu_dai->dev);
2901988e8cc4SNicolin Chen 	}
2902988e8cc4SNicolin Chen 
2903b19e6e7bSMark Brown 	return ret;
2904db2a4165SFrank Mandarino }
290570a7ca34SVinod Koul EXPORT_SYMBOL_GPL(snd_soc_register_card);
2906db2a4165SFrank Mandarino 
2907db2a4165SFrank Mandarino /**
2908db2a4165SFrank Mandarino  * snd_soc_unregister_card - Unregister a card with the ASoC core
2909db2a4165SFrank Mandarino  *
2910db2a4165SFrank Mandarino  * @card: Card to unregister
2911db2a4165SFrank Mandarino  *
2912db2a4165SFrank Mandarino  */
291370a7ca34SVinod Koul int snd_soc_unregister_card(struct snd_soc_card *card)
2914db2a4165SFrank Mandarino {
291501e0df66SLars-Peter Clausen 	if (card->instantiated) {
291601e0df66SLars-Peter Clausen 		card->instantiated = false;
29171c325f77SLars-Peter Clausen 		snd_soc_dapm_shutdown(card);
2918b0e26485SVinod Koul 		soc_cleanup_card_resources(card);
2919f110bfc7SLiam Girdwood 		dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name);
29208f6f9b29SKuninori Morimoto 	}
2921db2a4165SFrank Mandarino 
2922db2a4165SFrank Mandarino 	return 0;
2923db2a4165SFrank Mandarino }
292470a7ca34SVinod Koul EXPORT_SYMBOL_GPL(snd_soc_unregister_card);
2925db2a4165SFrank Mandarino 
2926db2a4165SFrank Mandarino /*
2927db2a4165SFrank Mandarino  * Simplify DAI link configuration by removing ".-1" from device names
2928db2a4165SFrank Mandarino  * and sanitizing names.
2929db2a4165SFrank Mandarino  */
29300b9a214aSDimitris Papastamos static char *fmt_single_name(struct device *dev, int *id)
2931db2a4165SFrank Mandarino {
2932db2a4165SFrank Mandarino 	char *found, name[NAME_SIZE];
2933db2a4165SFrank Mandarino 	int id1, id2;
2934db2a4165SFrank Mandarino 
2935db2a4165SFrank Mandarino 	if (dev_name(dev) == NULL)
2936db2a4165SFrank Mandarino 		return NULL;
2937db2a4165SFrank Mandarino 
293858818a77SDimitris Papastamos 	strlcpy(name, dev_name(dev), NAME_SIZE);
2939db2a4165SFrank Mandarino 
2940db2a4165SFrank Mandarino 	/* are we a "%s.%d" name (platform and SPI components) */
2941c5af3a2eSMark Brown 	found = strstr(name, dev->driver->name);
2942c5af3a2eSMark Brown 	if (found) {
2943c5af3a2eSMark Brown 		/* get ID */
2944c5af3a2eSMark Brown 		if (sscanf(&found[strlen(dev->driver->name)], ".%d", id) == 1) {
2945c5af3a2eSMark Brown 
2946c5af3a2eSMark Brown 			/* discard ID from name if ID == -1 */
2947c5af3a2eSMark Brown 			if (*id == -1)
2948c5af3a2eSMark Brown 				found[strlen(dev->driver->name)] = '\0';
2949c5af3a2eSMark Brown 		}
2950c5af3a2eSMark Brown 
2951c5af3a2eSMark Brown 	} else {
2952c5af3a2eSMark Brown 		/* I2C component devices are named "bus-addr"  */
2953c5af3a2eSMark Brown 		if (sscanf(name, "%x-%x", &id1, &id2) == 2) {
2954c5af3a2eSMark Brown 			char tmp[NAME_SIZE];
2955c5af3a2eSMark Brown 
2956c5af3a2eSMark Brown 			/* create unique ID number from I2C addr and bus */
2957c5af3a2eSMark Brown 			*id = ((id1 & 0xffff) << 16) + id2;
2958c5af3a2eSMark Brown 
2959c5af3a2eSMark Brown 			/* sanitize component name for DAI link creation */
2960c5af3a2eSMark Brown 			snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, name);
296158818a77SDimitris Papastamos 			strlcpy(name, tmp, NAME_SIZE);
2962c5af3a2eSMark Brown 		} else
2963c5af3a2eSMark Brown 			*id = 0;
2964c5af3a2eSMark Brown 	}
2965c5af3a2eSMark Brown 
2966c5af3a2eSMark Brown 	return kstrdup(name, GFP_KERNEL);
2967c5af3a2eSMark Brown }
2968c5af3a2eSMark Brown 
2969c5af3a2eSMark Brown /*
2970c5af3a2eSMark Brown  * Simplify DAI link naming for single devices with multiple DAIs by removing
2971c5af3a2eSMark Brown  * any ".-1" and using the DAI name (instead of device name).
2972c5af3a2eSMark Brown  */
2973c5af3a2eSMark Brown static inline char *fmt_multiple_name(struct device *dev,
2974c5af3a2eSMark Brown 		struct snd_soc_dai_driver *dai_drv)
2975c5af3a2eSMark Brown {
2976c5af3a2eSMark Brown 	if (dai_drv->name == NULL) {
297710e8aa9aSMichał Mirosław 		dev_err(dev,
297810e8aa9aSMichał Mirosław 			"ASoC: error - multiple DAI %s registered with no name\n",
297910e8aa9aSMichał Mirosław 			dev_name(dev));
2980c5af3a2eSMark Brown 		return NULL;
2981c5af3a2eSMark Brown 	}
2982c5af3a2eSMark Brown 
2983c5af3a2eSMark Brown 	return kstrdup(dai_drv->name, GFP_KERNEL);
2984c5af3a2eSMark Brown }
2985c5af3a2eSMark Brown 
2986c5af3a2eSMark Brown /**
298732c9ba54SLars-Peter Clausen  * snd_soc_unregister_dai - Unregister DAIs from the ASoC core
29889115171aSMark Brown  *
298932c9ba54SLars-Peter Clausen  * @component: The component for which the DAIs should be unregistered
29909115171aSMark Brown  */
299132c9ba54SLars-Peter Clausen static void snd_soc_unregister_dais(struct snd_soc_component *component)
29929115171aSMark Brown {
29935c1d5f09SLars-Peter Clausen 	struct snd_soc_dai *dai, *_dai;
29949115171aSMark Brown 
29955c1d5f09SLars-Peter Clausen 	list_for_each_entry_safe(dai, _dai, &component->dai_list, list) {
299632c9ba54SLars-Peter Clausen 		dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n",
299732c9ba54SLars-Peter Clausen 			dai->name);
29989115171aSMark Brown 		list_del(&dai->list);
2999f0fba2adSLiam Girdwood 		kfree(dai->name);
3000f0fba2adSLiam Girdwood 		kfree(dai);
30019115171aSMark Brown 	}
300232c9ba54SLars-Peter Clausen }
30039115171aSMark Brown 
30045e4fb372SMengdong Lin /* Create a DAI and add it to the component's DAI list */
30055e4fb372SMengdong Lin static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component,
30065e4fb372SMengdong Lin 	struct snd_soc_dai_driver *dai_drv,
30075e4fb372SMengdong Lin 	bool legacy_dai_naming)
30085e4fb372SMengdong Lin {
30095e4fb372SMengdong Lin 	struct device *dev = component->dev;
30105e4fb372SMengdong Lin 	struct snd_soc_dai *dai;
30115e4fb372SMengdong Lin 
30125e4fb372SMengdong Lin 	dev_dbg(dev, "ASoC: dynamically register DAI %s\n", dev_name(dev));
30135e4fb372SMengdong Lin 
30145e4fb372SMengdong Lin 	dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
30155e4fb372SMengdong Lin 	if (dai == NULL)
30165e4fb372SMengdong Lin 		return NULL;
30175e4fb372SMengdong Lin 
30185e4fb372SMengdong Lin 	/*
30195e4fb372SMengdong Lin 	 * Back in the old days when we still had component-less DAIs,
30205e4fb372SMengdong Lin 	 * instead of having a static name, component-less DAIs would
30215e4fb372SMengdong Lin 	 * inherit the name of the parent device so it is possible to
30225e4fb372SMengdong Lin 	 * register multiple instances of the DAI. We still need to keep
30235e4fb372SMengdong Lin 	 * the same naming style even though those DAIs are not
30245e4fb372SMengdong Lin 	 * component-less anymore.
30255e4fb372SMengdong Lin 	 */
30265e4fb372SMengdong Lin 	if (legacy_dai_naming &&
30275e4fb372SMengdong Lin 	   (dai_drv->id == 0 || dai_drv->name == NULL)) {
30285e4fb372SMengdong Lin 		dai->name = fmt_single_name(dev, &dai->id);
30295e4fb372SMengdong Lin 	} else {
30305e4fb372SMengdong Lin 		dai->name = fmt_multiple_name(dev, dai_drv);
30315e4fb372SMengdong Lin 		if (dai_drv->id)
30325e4fb372SMengdong Lin 			dai->id = dai_drv->id;
30335e4fb372SMengdong Lin 		else
30345e4fb372SMengdong Lin 			dai->id = component->num_dai;
30355e4fb372SMengdong Lin 	}
30365e4fb372SMengdong Lin 	if (dai->name == NULL) {
30375e4fb372SMengdong Lin 		kfree(dai);
30385e4fb372SMengdong Lin 		return NULL;
30395e4fb372SMengdong Lin 	}
30405e4fb372SMengdong Lin 
30415e4fb372SMengdong Lin 	dai->component = component;
30425e4fb372SMengdong Lin 	dai->dev = dev;
30435e4fb372SMengdong Lin 	dai->driver = dai_drv;
30445e4fb372SMengdong Lin 	if (!dai->driver->ops)
30455e4fb372SMengdong Lin 		dai->driver->ops = &null_dai_ops;
30465e4fb372SMengdong Lin 
304758bf4179SKuninori Morimoto 	list_add_tail(&dai->list, &component->dai_list);
30485e4fb372SMengdong Lin 	component->num_dai++;
30495e4fb372SMengdong Lin 
30505e4fb372SMengdong Lin 	dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
30515e4fb372SMengdong Lin 	return dai;
30525e4fb372SMengdong Lin }
30535e4fb372SMengdong Lin 
30549115171aSMark Brown /**
305532c9ba54SLars-Peter Clausen  * snd_soc_register_dais - Register a DAI with the ASoC core
30569115171aSMark Brown  *
30576106d129SLars-Peter Clausen  * @component: The component the DAIs are registered for
30586106d129SLars-Peter Clausen  * @dai_drv: DAI driver to use for the DAIs
3059ac11a2b3SMark Brown  * @count: Number of DAIs
306032c9ba54SLars-Peter Clausen  * @legacy_dai_naming: Use the legacy naming scheme and let the DAI inherit the
306132c9ba54SLars-Peter Clausen  *                     parent's name.
30629115171aSMark Brown  */
306332c9ba54SLars-Peter Clausen static int snd_soc_register_dais(struct snd_soc_component *component,
3064bb13109dSLars-Peter Clausen 	struct snd_soc_dai_driver *dai_drv, size_t count,
3065bb13109dSLars-Peter Clausen 	bool legacy_dai_naming)
30669115171aSMark Brown {
30676106d129SLars-Peter Clausen 	struct device *dev = component->dev;
3068f0fba2adSLiam Girdwood 	struct snd_soc_dai *dai;
306932c9ba54SLars-Peter Clausen 	unsigned int i;
307032c9ba54SLars-Peter Clausen 	int ret;
3071f0fba2adSLiam Girdwood 
30725b5e0928SAlexey Dobriyan 	dev_dbg(dev, "ASoC: dai register %s #%zu\n", dev_name(dev), count);
30739115171aSMark Brown 
30749115171aSMark Brown 	for (i = 0; i < count; i++) {
3075f0fba2adSLiam Girdwood 
30765e4fb372SMengdong Lin 		dai = soc_add_dai(component, dai_drv + i,
30775e4fb372SMengdong Lin 				count == 1 && legacy_dai_naming);
3078c46e0079SAxel Lin 		if (dai == NULL) {
3079c46e0079SAxel Lin 			ret = -ENOMEM;
3080c46e0079SAxel Lin 			goto err;
3081c46e0079SAxel Lin 		}
3082f0fba2adSLiam Girdwood 	}
3083f0fba2adSLiam Girdwood 
30849115171aSMark Brown 	return 0;
30859115171aSMark Brown 
30869115171aSMark Brown err:
308732c9ba54SLars-Peter Clausen 	snd_soc_unregister_dais(component);
30889115171aSMark Brown 
30899115171aSMark Brown 	return ret;
30909115171aSMark Brown }
30919115171aSMark Brown 
309268003e6cSMengdong Lin /**
309368003e6cSMengdong Lin  * snd_soc_register_dai - Register a DAI dynamically & create its widgets
309468003e6cSMengdong Lin  *
309568003e6cSMengdong Lin  * @component: The component the DAIs are registered for
309668003e6cSMengdong Lin  * @dai_drv: DAI driver to use for the DAI
309768003e6cSMengdong Lin  *
309868003e6cSMengdong Lin  * Topology can use this API to register DAIs when probing a component.
309968003e6cSMengdong Lin  * These DAIs's widgets will be freed in the card cleanup and the DAIs
310068003e6cSMengdong Lin  * will be freed in the component cleanup.
310168003e6cSMengdong Lin  */
310268003e6cSMengdong Lin int snd_soc_register_dai(struct snd_soc_component *component,
310368003e6cSMengdong Lin 	struct snd_soc_dai_driver *dai_drv)
310468003e6cSMengdong Lin {
310568003e6cSMengdong Lin 	struct snd_soc_dapm_context *dapm =
310668003e6cSMengdong Lin 		snd_soc_component_get_dapm(component);
310768003e6cSMengdong Lin 	struct snd_soc_dai *dai;
310868003e6cSMengdong Lin 	int ret;
310968003e6cSMengdong Lin 
311068003e6cSMengdong Lin 	if (dai_drv->dobj.type != SND_SOC_DOBJ_PCM) {
311168003e6cSMengdong Lin 		dev_err(component->dev, "Invalid dai type %d\n",
311268003e6cSMengdong Lin 			dai_drv->dobj.type);
311368003e6cSMengdong Lin 		return -EINVAL;
311468003e6cSMengdong Lin 	}
311568003e6cSMengdong Lin 
311668003e6cSMengdong Lin 	lockdep_assert_held(&client_mutex);
311768003e6cSMengdong Lin 	dai = soc_add_dai(component, dai_drv, false);
311868003e6cSMengdong Lin 	if (!dai)
311968003e6cSMengdong Lin 		return -ENOMEM;
312068003e6cSMengdong Lin 
312168003e6cSMengdong Lin 	/* Create the DAI widgets here. After adding DAIs, topology may
312268003e6cSMengdong Lin 	 * also add routes that need these widgets as source or sink.
312368003e6cSMengdong Lin 	 */
312468003e6cSMengdong Lin 	ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
312568003e6cSMengdong Lin 	if (ret != 0) {
312668003e6cSMengdong Lin 		dev_err(component->dev,
312768003e6cSMengdong Lin 			"Failed to create DAI widgets %d\n", ret);
312868003e6cSMengdong Lin 	}
312968003e6cSMengdong Lin 
313068003e6cSMengdong Lin 	return ret;
313168003e6cSMengdong Lin }
313268003e6cSMengdong Lin EXPORT_SYMBOL_GPL(snd_soc_register_dai);
313368003e6cSMengdong Lin 
313414e8bdebSLars-Peter Clausen static void snd_soc_component_seq_notifier(struct snd_soc_dapm_context *dapm,
313514e8bdebSLars-Peter Clausen 	enum snd_soc_dapm_type type, int subseq)
3136d191bd8dSKuninori Morimoto {
313714e8bdebSLars-Peter Clausen 	struct snd_soc_component *component = dapm->component;
3138d191bd8dSKuninori Morimoto 
313914e8bdebSLars-Peter Clausen 	component->driver->seq_notifier(component, type, subseq);
314014e8bdebSLars-Peter Clausen }
3141d191bd8dSKuninori Morimoto 
314214e8bdebSLars-Peter Clausen static int snd_soc_component_stream_event(struct snd_soc_dapm_context *dapm,
314314e8bdebSLars-Peter Clausen 	int event)
314414e8bdebSLars-Peter Clausen {
314514e8bdebSLars-Peter Clausen 	struct snd_soc_component *component = dapm->component;
314614e8bdebSLars-Peter Clausen 
314714e8bdebSLars-Peter Clausen 	return component->driver->stream_event(component, event);
314814e8bdebSLars-Peter Clausen }
314914e8bdebSLars-Peter Clausen 
3150f523acebSKuninori Morimoto static int snd_soc_component_drv_pcm_new(struct snd_soc_component *component,
3151f523acebSKuninori Morimoto 					struct snd_soc_pcm_runtime *rtd)
3152f523acebSKuninori Morimoto {
3153f523acebSKuninori Morimoto 	if (component->driver->pcm_new)
3154f523acebSKuninori Morimoto 		return component->driver->pcm_new(rtd);
3155f523acebSKuninori Morimoto 
3156f523acebSKuninori Morimoto 	return 0;
3157f523acebSKuninori Morimoto }
3158f523acebSKuninori Morimoto 
3159f523acebSKuninori Morimoto static void snd_soc_component_drv_pcm_free(struct snd_soc_component *component,
3160f523acebSKuninori Morimoto 					  struct snd_pcm *pcm)
3161f523acebSKuninori Morimoto {
3162f523acebSKuninori Morimoto 	if (component->driver->pcm_free)
3163f523acebSKuninori Morimoto 		component->driver->pcm_free(pcm);
3164f523acebSKuninori Morimoto }
3165f523acebSKuninori Morimoto 
31667ba236ceSKuninori Morimoto static int snd_soc_component_set_bias_level(struct snd_soc_dapm_context *dapm,
31677ba236ceSKuninori Morimoto 					enum snd_soc_bias_level level)
31687ba236ceSKuninori Morimoto {
31697ba236ceSKuninori Morimoto 	struct snd_soc_component *component = dapm->component;
31707ba236ceSKuninori Morimoto 
31717ba236ceSKuninori Morimoto 	return component->driver->set_bias_level(component, level);
31727ba236ceSKuninori Morimoto }
31737ba236ceSKuninori Morimoto 
3174bb13109dSLars-Peter Clausen static int snd_soc_component_initialize(struct snd_soc_component *component,
3175bb13109dSLars-Peter Clausen 	const struct snd_soc_component_driver *driver, struct device *dev)
3176d191bd8dSKuninori Morimoto {
3177ce0fc93aSLars-Peter Clausen 	struct snd_soc_dapm_context *dapm;
3178ce0fc93aSLars-Peter Clausen 
3179bb13109dSLars-Peter Clausen 	component->name = fmt_single_name(dev, &component->id);
3180bb13109dSLars-Peter Clausen 	if (!component->name) {
3181bb13109dSLars-Peter Clausen 		dev_err(dev, "ASoC: Failed to allocate name\n");
3182d191bd8dSKuninori Morimoto 		return -ENOMEM;
3183d191bd8dSKuninori Morimoto 	}
3184d191bd8dSKuninori Morimoto 
3185bb13109dSLars-Peter Clausen 	component->dev = dev;
3186bb13109dSLars-Peter Clausen 	component->driver = driver;
318761aca564SLars-Peter Clausen 	component->probe = component->driver->probe;
318861aca564SLars-Peter Clausen 	component->remove = component->driver->remove;
31899178feb4SKuninori Morimoto 	component->suspend = component->driver->suspend;
31909178feb4SKuninori Morimoto 	component->resume = component->driver->resume;
319171ccef0dSKuninori Morimoto 	component->set_sysclk = component->driver->set_sysclk;
3192ef641e5dSKuninori Morimoto 	component->set_pll = component->driver->set_pll;
319344c07365SKuninori Morimoto 	component->set_jack = component->driver->set_jack;
3194f523acebSKuninori Morimoto 	component->pcm_new = snd_soc_component_drv_pcm_new;
3195f523acebSKuninori Morimoto 	component->pcm_free = snd_soc_component_drv_pcm_free;
3196e2c330b9SLars-Peter Clausen 
319788c27465SKuninori Morimoto 	dapm = snd_soc_component_get_dapm(component);
3198ce0fc93aSLars-Peter Clausen 	dapm->dev = dev;
3199ce0fc93aSLars-Peter Clausen 	dapm->component = component;
3200ce0fc93aSLars-Peter Clausen 	dapm->bias_level = SND_SOC_BIAS_OFF;
32017ba236ceSKuninori Morimoto 	dapm->idle_bias_off = !driver->idle_bias_on;
32027ba236ceSKuninori Morimoto 	dapm->suspend_bias_off = driver->suspend_bias_off;
320314e8bdebSLars-Peter Clausen 	if (driver->seq_notifier)
320414e8bdebSLars-Peter Clausen 		dapm->seq_notifier = snd_soc_component_seq_notifier;
320514e8bdebSLars-Peter Clausen 	if (driver->stream_event)
320614e8bdebSLars-Peter Clausen 		dapm->stream_event = snd_soc_component_stream_event;
32077ba236ceSKuninori Morimoto 	if (driver->set_bias_level)
32087ba236ceSKuninori Morimoto 		dapm->set_bias_level = snd_soc_component_set_bias_level;
3209ce0fc93aSLars-Peter Clausen 
3210bb13109dSLars-Peter Clausen 	INIT_LIST_HEAD(&component->dai_list);
3211bb13109dSLars-Peter Clausen 	mutex_init(&component->io_mutex);
3212bb13109dSLars-Peter Clausen 
3213bb13109dSLars-Peter Clausen 	return 0;
3214d191bd8dSKuninori Morimoto }
3215d191bd8dSKuninori Morimoto 
321620feb881SLars-Peter Clausen static void snd_soc_component_setup_regmap(struct snd_soc_component *component)
3217886f5692SLars-Peter Clausen {
3218886f5692SLars-Peter Clausen 	int val_bytes = regmap_get_val_bytes(component->regmap);
321920feb881SLars-Peter Clausen 
3220886f5692SLars-Peter Clausen 	/* Errors are legitimate for non-integer byte multiples */
3221886f5692SLars-Peter Clausen 	if (val_bytes > 0)
3222886f5692SLars-Peter Clausen 		component->val_bytes = val_bytes;
3223886f5692SLars-Peter Clausen }
322420feb881SLars-Peter Clausen 
3225e874bf5fSLars-Peter Clausen #ifdef CONFIG_REGMAP
3226e874bf5fSLars-Peter Clausen 
322720feb881SLars-Peter Clausen /**
322820feb881SLars-Peter Clausen  * snd_soc_component_init_regmap() - Initialize regmap instance for the component
322920feb881SLars-Peter Clausen  * @component: The component for which to initialize the regmap instance
323020feb881SLars-Peter Clausen  * @regmap: The regmap instance that should be used by the component
323120feb881SLars-Peter Clausen  *
323220feb881SLars-Peter Clausen  * This function allows deferred assignment of the regmap instance that is
323320feb881SLars-Peter Clausen  * associated with the component. Only use this if the regmap instance is not
323420feb881SLars-Peter Clausen  * yet ready when the component is registered. The function must also be called
323520feb881SLars-Peter Clausen  * before the first IO attempt of the component.
323620feb881SLars-Peter Clausen  */
323720feb881SLars-Peter Clausen void snd_soc_component_init_regmap(struct snd_soc_component *component,
323820feb881SLars-Peter Clausen 	struct regmap *regmap)
323920feb881SLars-Peter Clausen {
324020feb881SLars-Peter Clausen 	component->regmap = regmap;
324120feb881SLars-Peter Clausen 	snd_soc_component_setup_regmap(component);
3242886f5692SLars-Peter Clausen }
324320feb881SLars-Peter Clausen EXPORT_SYMBOL_GPL(snd_soc_component_init_regmap);
324420feb881SLars-Peter Clausen 
324520feb881SLars-Peter Clausen /**
324620feb881SLars-Peter Clausen  * snd_soc_component_exit_regmap() - De-initialize regmap instance for the component
324720feb881SLars-Peter Clausen  * @component: The component for which to de-initialize the regmap instance
324820feb881SLars-Peter Clausen  *
324920feb881SLars-Peter Clausen  * Calls regmap_exit() on the regmap instance associated to the component and
325020feb881SLars-Peter Clausen  * removes the regmap instance from the component.
325120feb881SLars-Peter Clausen  *
325220feb881SLars-Peter Clausen  * This function should only be used if snd_soc_component_init_regmap() was used
325320feb881SLars-Peter Clausen  * to initialize the regmap instance.
325420feb881SLars-Peter Clausen  */
325520feb881SLars-Peter Clausen void snd_soc_component_exit_regmap(struct snd_soc_component *component)
325620feb881SLars-Peter Clausen {
325720feb881SLars-Peter Clausen 	regmap_exit(component->regmap);
325820feb881SLars-Peter Clausen 	component->regmap = NULL;
325920feb881SLars-Peter Clausen }
326020feb881SLars-Peter Clausen EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap);
3261886f5692SLars-Peter Clausen 
3262e874bf5fSLars-Peter Clausen #endif
3263d191bd8dSKuninori Morimoto 
3264bb13109dSLars-Peter Clausen static void snd_soc_component_add_unlocked(struct snd_soc_component *component)
3265bb13109dSLars-Peter Clausen {
326620feb881SLars-Peter Clausen 	if (!component->write && !component->read) {
326720feb881SLars-Peter Clausen 		if (!component->regmap)
326820feb881SLars-Peter Clausen 			component->regmap = dev_get_regmap(component->dev, NULL);
326920feb881SLars-Peter Clausen 		if (component->regmap)
327020feb881SLars-Peter Clausen 			snd_soc_component_setup_regmap(component);
327120feb881SLars-Peter Clausen 	}
3272886f5692SLars-Peter Clausen 
3273bb13109dSLars-Peter Clausen 	list_add(&component->list, &component_list);
32748a978234SLiam Girdwood 	INIT_LIST_HEAD(&component->dobj_list);
3275d191bd8dSKuninori Morimoto }
3276d191bd8dSKuninori Morimoto 
3277bb13109dSLars-Peter Clausen static void snd_soc_component_add(struct snd_soc_component *component)
3278bb13109dSLars-Peter Clausen {
3279d191bd8dSKuninori Morimoto 	mutex_lock(&client_mutex);
3280bb13109dSLars-Peter Clausen 	snd_soc_component_add_unlocked(component);
3281d191bd8dSKuninori Morimoto 	mutex_unlock(&client_mutex);
3282bb13109dSLars-Peter Clausen }
3283d191bd8dSKuninori Morimoto 
3284bb13109dSLars-Peter Clausen static void snd_soc_component_cleanup(struct snd_soc_component *component)
3285bb13109dSLars-Peter Clausen {
3286bb13109dSLars-Peter Clausen 	snd_soc_unregister_dais(component);
3287bb13109dSLars-Peter Clausen 	kfree(component->name);
3288bb13109dSLars-Peter Clausen }
3289d191bd8dSKuninori Morimoto 
3290bb13109dSLars-Peter Clausen static void snd_soc_component_del_unlocked(struct snd_soc_component *component)
3291bb13109dSLars-Peter Clausen {
3292c12c1aadSKuninori Morimoto 	struct snd_soc_card *card = component->card;
3293c12c1aadSKuninori Morimoto 
3294c12c1aadSKuninori Morimoto 	if (card)
3295c12c1aadSKuninori Morimoto 		snd_soc_unregister_card(card);
3296c12c1aadSKuninori Morimoto 
3297bb13109dSLars-Peter Clausen 	list_del(&component->list);
3298bb13109dSLars-Peter Clausen }
3299d191bd8dSKuninori Morimoto 
3300273d778eSKuninori Morimoto #define ENDIANNESS_MAP(name) \
3301273d778eSKuninori Morimoto 	(SNDRV_PCM_FMTBIT_##name##LE | SNDRV_PCM_FMTBIT_##name##BE)
3302273d778eSKuninori Morimoto static u64 endianness_format_map[] = {
3303273d778eSKuninori Morimoto 	ENDIANNESS_MAP(S16_),
3304273d778eSKuninori Morimoto 	ENDIANNESS_MAP(U16_),
3305273d778eSKuninori Morimoto 	ENDIANNESS_MAP(S24_),
3306273d778eSKuninori Morimoto 	ENDIANNESS_MAP(U24_),
3307273d778eSKuninori Morimoto 	ENDIANNESS_MAP(S32_),
3308273d778eSKuninori Morimoto 	ENDIANNESS_MAP(U32_),
3309273d778eSKuninori Morimoto 	ENDIANNESS_MAP(S24_3),
3310273d778eSKuninori Morimoto 	ENDIANNESS_MAP(U24_3),
3311273d778eSKuninori Morimoto 	ENDIANNESS_MAP(S20_3),
3312273d778eSKuninori Morimoto 	ENDIANNESS_MAP(U20_3),
3313273d778eSKuninori Morimoto 	ENDIANNESS_MAP(S18_3),
3314273d778eSKuninori Morimoto 	ENDIANNESS_MAP(U18_3),
3315273d778eSKuninori Morimoto 	ENDIANNESS_MAP(FLOAT_),
3316273d778eSKuninori Morimoto 	ENDIANNESS_MAP(FLOAT64_),
3317273d778eSKuninori Morimoto 	ENDIANNESS_MAP(IEC958_SUBFRAME_),
3318273d778eSKuninori Morimoto };
3319273d778eSKuninori Morimoto 
3320273d778eSKuninori Morimoto /*
3321273d778eSKuninori Morimoto  * Fix up the DAI formats for endianness: codecs don't actually see
3322273d778eSKuninori Morimoto  * the endianness of the data but we're using the CPU format
3323273d778eSKuninori Morimoto  * definitions which do need to include endianness so we ensure that
3324273d778eSKuninori Morimoto  * codec DAIs always have both big and little endian variants set.
3325273d778eSKuninori Morimoto  */
3326273d778eSKuninori Morimoto static void convert_endianness_formats(struct snd_soc_pcm_stream *stream)
3327273d778eSKuninori Morimoto {
3328273d778eSKuninori Morimoto 	int i;
3329273d778eSKuninori Morimoto 
3330273d778eSKuninori Morimoto 	for (i = 0; i < ARRAY_SIZE(endianness_format_map); i++)
3331273d778eSKuninori Morimoto 		if (stream->formats & endianness_format_map[i])
3332273d778eSKuninori Morimoto 			stream->formats |= endianness_format_map[i];
3333273d778eSKuninori Morimoto }
3334273d778eSKuninori Morimoto 
3335e0dac41bSKuninori Morimoto int snd_soc_add_component(struct device *dev,
3336e0dac41bSKuninori Morimoto 			struct snd_soc_component *component,
3337cf9e829eSKuninori Morimoto 			const struct snd_soc_component_driver *component_driver,
3338d191bd8dSKuninori Morimoto 			struct snd_soc_dai_driver *dai_drv,
3339d191bd8dSKuninori Morimoto 			int num_dai)
3340d191bd8dSKuninori Morimoto {
3341bb13109dSLars-Peter Clausen 	int ret;
3342273d778eSKuninori Morimoto 	int i;
3343d191bd8dSKuninori Morimoto 
3344cf9e829eSKuninori Morimoto 	ret = snd_soc_component_initialize(component, component_driver, dev);
3345bb13109dSLars-Peter Clausen 	if (ret)
3346bb13109dSLars-Peter Clausen 		goto err_free;
3347bb13109dSLars-Peter Clausen 
3348cf9e829eSKuninori Morimoto 	component->ignore_pmdown_time = true;
3349cf9e829eSKuninori Morimoto 	component->registered_as_component = true;
33503d59400fSLars-Peter Clausen 
3351273d778eSKuninori Morimoto 	if (component_driver->endianness) {
3352273d778eSKuninori Morimoto 		for (i = 0; i < num_dai; i++) {
3353273d778eSKuninori Morimoto 			convert_endianness_formats(&dai_drv[i].playback);
3354273d778eSKuninori Morimoto 			convert_endianness_formats(&dai_drv[i].capture);
3355273d778eSKuninori Morimoto 		}
3356273d778eSKuninori Morimoto 	}
3357273d778eSKuninori Morimoto 
335869941babSKuninori Morimoto 	ret = snd_soc_register_dais(component, dai_drv, num_dai,
335969941babSKuninori Morimoto 				    !component_driver->non_legacy_dai_naming);
3360bb13109dSLars-Peter Clausen 	if (ret < 0) {
3361f42cf8d6SMasanari Iida 		dev_err(dev, "ASoC: Failed to register DAIs: %d\n", ret);
3362bb13109dSLars-Peter Clausen 		goto err_cleanup;
3363bb13109dSLars-Peter Clausen 	}
3364bb13109dSLars-Peter Clausen 
3365cf9e829eSKuninori Morimoto 	snd_soc_component_add(component);
3366bb13109dSLars-Peter Clausen 
3367bb13109dSLars-Peter Clausen 	return 0;
3368bb13109dSLars-Peter Clausen 
3369bb13109dSLars-Peter Clausen err_cleanup:
3370cf9e829eSKuninori Morimoto 	snd_soc_component_cleanup(component);
3371bb13109dSLars-Peter Clausen err_free:
3372bb13109dSLars-Peter Clausen 	return ret;
3373d191bd8dSKuninori Morimoto }
3374e0dac41bSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_add_component);
3375e0dac41bSKuninori Morimoto 
3376e0dac41bSKuninori Morimoto int snd_soc_register_component(struct device *dev,
3377e0dac41bSKuninori Morimoto 			const struct snd_soc_component_driver *component_driver,
3378e0dac41bSKuninori Morimoto 			struct snd_soc_dai_driver *dai_drv,
3379e0dac41bSKuninori Morimoto 			int num_dai)
3380e0dac41bSKuninori Morimoto {
3381e0dac41bSKuninori Morimoto 	struct snd_soc_component *component;
3382e0dac41bSKuninori Morimoto 
33837ecbd6a9SKuninori Morimoto 	component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL);
338408e61d03SKuninori Morimoto 	if (!component)
3385e0dac41bSKuninori Morimoto 		return -ENOMEM;
3386e0dac41bSKuninori Morimoto 
3387e0dac41bSKuninori Morimoto 	return snd_soc_add_component(dev, component, component_driver,
3388e0dac41bSKuninori Morimoto 				     dai_drv, num_dai);
3389e0dac41bSKuninori Morimoto }
3390d191bd8dSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_register_component);
3391d191bd8dSKuninori Morimoto 
3392d191bd8dSKuninori Morimoto /**
33932eccea8cSKuninori Morimoto  * snd_soc_unregister_component - Unregister all related component
33942eccea8cSKuninori Morimoto  * from the ASoC core
3395d191bd8dSKuninori Morimoto  *
3396628536eaSJonathan Corbet  * @dev: The device to unregister
3397d191bd8dSKuninori Morimoto  */
33982eccea8cSKuninori Morimoto static int __snd_soc_unregister_component(struct device *dev)
3399d191bd8dSKuninori Morimoto {
3400cf9e829eSKuninori Morimoto 	struct snd_soc_component *component;
340121a03528SKuninori Morimoto 	int found = 0;
3402d191bd8dSKuninori Morimoto 
340334e81ab4SLars-Peter Clausen 	mutex_lock(&client_mutex);
3404cf9e829eSKuninori Morimoto 	list_for_each_entry(component, &component_list, list) {
340521a03528SKuninori Morimoto 		if (dev != component->dev ||
340621a03528SKuninori Morimoto 		    !component->registered_as_component)
340721a03528SKuninori Morimoto 			continue;
3408d191bd8dSKuninori Morimoto 
3409cf9e829eSKuninori Morimoto 		snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL);
3410cf9e829eSKuninori Morimoto 		snd_soc_component_del_unlocked(component);
341121a03528SKuninori Morimoto 		found = 1;
341221a03528SKuninori Morimoto 		break;
3413d191bd8dSKuninori Morimoto 	}
3414d191bd8dSKuninori Morimoto 	mutex_unlock(&client_mutex);
3415d191bd8dSKuninori Morimoto 
341621a03528SKuninori Morimoto 	if (found) {
3417cf9e829eSKuninori Morimoto 		snd_soc_component_cleanup(component);
3418d191bd8dSKuninori Morimoto 	}
34192eccea8cSKuninori Morimoto 
34202eccea8cSKuninori Morimoto 	return found;
34212eccea8cSKuninori Morimoto }
34222eccea8cSKuninori Morimoto 
34232eccea8cSKuninori Morimoto void snd_soc_unregister_component(struct device *dev)
34242eccea8cSKuninori Morimoto {
34252eccea8cSKuninori Morimoto 	while (__snd_soc_unregister_component(dev));
3426d191bd8dSKuninori Morimoto }
3427d191bd8dSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
3428d191bd8dSKuninori Morimoto 
34297dd5d0d9SKuninori Morimoto struct snd_soc_component *snd_soc_lookup_component(struct device *dev,
34307dd5d0d9SKuninori Morimoto 						   const char *driver_name)
34317dd5d0d9SKuninori Morimoto {
34327dd5d0d9SKuninori Morimoto 	struct snd_soc_component *component;
34337dd5d0d9SKuninori Morimoto 	struct snd_soc_component *ret;
34347dd5d0d9SKuninori Morimoto 
34357dd5d0d9SKuninori Morimoto 	ret = NULL;
34367dd5d0d9SKuninori Morimoto 	mutex_lock(&client_mutex);
34377dd5d0d9SKuninori Morimoto 	list_for_each_entry(component, &component_list, list) {
34387dd5d0d9SKuninori Morimoto 		if (dev != component->dev)
34397dd5d0d9SKuninori Morimoto 			continue;
34407dd5d0d9SKuninori Morimoto 
34417dd5d0d9SKuninori Morimoto 		if (driver_name &&
34427dd5d0d9SKuninori Morimoto 		    (driver_name != component->driver->name) &&
34437dd5d0d9SKuninori Morimoto 		    (strcmp(component->driver->name, driver_name) != 0))
34447dd5d0d9SKuninori Morimoto 			continue;
34457dd5d0d9SKuninori Morimoto 
34467dd5d0d9SKuninori Morimoto 		ret = component;
34477dd5d0d9SKuninori Morimoto 		break;
34487dd5d0d9SKuninori Morimoto 	}
34497dd5d0d9SKuninori Morimoto 	mutex_unlock(&client_mutex);
34507dd5d0d9SKuninori Morimoto 
34517dd5d0d9SKuninori Morimoto 	return ret;
34527dd5d0d9SKuninori Morimoto }
34537dd5d0d9SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_lookup_component);
34547dd5d0d9SKuninori Morimoto 
3455f1d45cc3SLars-Peter Clausen static int snd_soc_codec_drv_probe(struct snd_soc_component *component)
3456f1d45cc3SLars-Peter Clausen {
3457f1d45cc3SLars-Peter Clausen 	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
3458f1d45cc3SLars-Peter Clausen 
3459f1d45cc3SLars-Peter Clausen 	return codec->driver->probe(codec);
3460f1d45cc3SLars-Peter Clausen }
3461f1d45cc3SLars-Peter Clausen 
3462f1d45cc3SLars-Peter Clausen static void snd_soc_codec_drv_remove(struct snd_soc_component *component)
3463f1d45cc3SLars-Peter Clausen {
3464f1d45cc3SLars-Peter Clausen 	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
3465f1d45cc3SLars-Peter Clausen 
3466f1d45cc3SLars-Peter Clausen 	codec->driver->remove(codec);
3467f1d45cc3SLars-Peter Clausen }
3468f1d45cc3SLars-Peter Clausen 
34699178feb4SKuninori Morimoto static int snd_soc_codec_drv_suspend(struct snd_soc_component *component)
34709178feb4SKuninori Morimoto {
34719178feb4SKuninori Morimoto 	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
34729178feb4SKuninori Morimoto 
34739178feb4SKuninori Morimoto 	return codec->driver->suspend(codec);
34749178feb4SKuninori Morimoto }
34759178feb4SKuninori Morimoto 
34769178feb4SKuninori Morimoto static int snd_soc_codec_drv_resume(struct snd_soc_component *component)
34779178feb4SKuninori Morimoto {
34789178feb4SKuninori Morimoto 	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
34799178feb4SKuninori Morimoto 
34809178feb4SKuninori Morimoto 	return codec->driver->resume(codec);
34819178feb4SKuninori Morimoto }
34829178feb4SKuninori Morimoto 
3483e2c330b9SLars-Peter Clausen static int snd_soc_codec_drv_write(struct snd_soc_component *component,
3484e2c330b9SLars-Peter Clausen 	unsigned int reg, unsigned int val)
3485e2c330b9SLars-Peter Clausen {
3486e2c330b9SLars-Peter Clausen 	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
3487e2c330b9SLars-Peter Clausen 
3488e2c330b9SLars-Peter Clausen 	return codec->driver->write(codec, reg, val);
3489e2c330b9SLars-Peter Clausen }
3490e2c330b9SLars-Peter Clausen 
3491e2c330b9SLars-Peter Clausen static int snd_soc_codec_drv_read(struct snd_soc_component *component,
3492e2c330b9SLars-Peter Clausen 	unsigned int reg, unsigned int *val)
3493e2c330b9SLars-Peter Clausen {
3494e2c330b9SLars-Peter Clausen 	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
3495e2c330b9SLars-Peter Clausen 
3496e2c330b9SLars-Peter Clausen 	*val = codec->driver->read(codec, reg);
3497e2c330b9SLars-Peter Clausen 
3498e2c330b9SLars-Peter Clausen 	return 0;
3499e2c330b9SLars-Peter Clausen }
3500e2c330b9SLars-Peter Clausen 
350171ccef0dSKuninori Morimoto static int snd_soc_codec_set_sysclk_(struct snd_soc_component *component,
350271ccef0dSKuninori Morimoto 			  int clk_id, int source, unsigned int freq, int dir)
350371ccef0dSKuninori Morimoto {
350471ccef0dSKuninori Morimoto 	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
350571ccef0dSKuninori Morimoto 
350671ccef0dSKuninori Morimoto 	return snd_soc_codec_set_sysclk(codec, clk_id, source, freq, dir);
350771ccef0dSKuninori Morimoto }
350871ccef0dSKuninori Morimoto 
3509ef641e5dSKuninori Morimoto static int snd_soc_codec_set_pll_(struct snd_soc_component *component,
3510ef641e5dSKuninori Morimoto 				  int pll_id, int source, unsigned int freq_in,
3511ef641e5dSKuninori Morimoto 				  unsigned int freq_out)
3512ef641e5dSKuninori Morimoto {
3513ef641e5dSKuninori Morimoto 	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
3514ef641e5dSKuninori Morimoto 
3515ef641e5dSKuninori Morimoto 	return snd_soc_codec_set_pll(codec, pll_id, source, freq_in, freq_out);
3516ef641e5dSKuninori Morimoto }
3517ef641e5dSKuninori Morimoto 
351844c07365SKuninori Morimoto static int snd_soc_codec_set_jack_(struct snd_soc_component *component,
351944c07365SKuninori Morimoto 			       struct snd_soc_jack *jack, void *data)
352044c07365SKuninori Morimoto {
352144c07365SKuninori Morimoto 	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
352244c07365SKuninori Morimoto 
352344c07365SKuninori Morimoto 	return snd_soc_codec_set_jack(codec, jack, data);
352444c07365SKuninori Morimoto }
352544c07365SKuninori Morimoto 
352668f831c2SLars-Peter Clausen static int snd_soc_codec_set_bias_level(struct snd_soc_dapm_context *dapm,
352768f831c2SLars-Peter Clausen 	enum snd_soc_bias_level level)
352868f831c2SLars-Peter Clausen {
352968f831c2SLars-Peter Clausen 	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
353068f831c2SLars-Peter Clausen 
353168f831c2SLars-Peter Clausen 	return codec->driver->set_bias_level(codec, level);
353268f831c2SLars-Peter Clausen }
353368f831c2SLars-Peter Clausen 
35340d0cf00aSMark Brown /**
35350d0cf00aSMark Brown  * snd_soc_register_codec - Register a codec with the ASoC core
35360d0cf00aSMark Brown  *
3537628536eaSJonathan Corbet  * @dev: The parent device for this codec
3538628536eaSJonathan Corbet  * @codec_drv: Codec driver
3539628536eaSJonathan Corbet  * @dai_drv: The associated DAI driver
3540628536eaSJonathan Corbet  * @num_dai: Number of DAIs
35410d0cf00aSMark Brown  */
3542f0fba2adSLiam Girdwood int snd_soc_register_codec(struct device *dev,
3543001ae4c0SMark Brown 			   const struct snd_soc_codec_driver *codec_drv,
3544001ae4c0SMark Brown 			   struct snd_soc_dai_driver *dai_drv,
3545001ae4c0SMark Brown 			   int num_dai)
35460d0cf00aSMark Brown {
35474890140fSLars-Peter Clausen 	struct snd_soc_dapm_context *dapm;
3548f0fba2adSLiam Girdwood 	struct snd_soc_codec *codec;
3549bb13109dSLars-Peter Clausen 	struct snd_soc_dai *dai;
3550f0fba2adSLiam Girdwood 	int ret, i;
3551151ab22cSMark Brown 
3552f0fba2adSLiam Girdwood 	dev_dbg(dev, "codec register %s\n", dev_name(dev));
35530d0cf00aSMark Brown 
3554f0fba2adSLiam Girdwood 	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
3555f0fba2adSLiam Girdwood 	if (codec == NULL)
3556f0fba2adSLiam Girdwood 		return -ENOMEM;
35570d0cf00aSMark Brown 
3558f1d45cc3SLars-Peter Clausen 	codec->component.codec = codec;
3559ce0fc93aSLars-Peter Clausen 
3560bb13109dSLars-Peter Clausen 	ret = snd_soc_component_initialize(&codec->component,
3561bb13109dSLars-Peter Clausen 			&codec_drv->component_driver, dev);
3562bb13109dSLars-Peter Clausen 	if (ret)
3563bb13109dSLars-Peter Clausen 		goto err_free;
3564151ab22cSMark Brown 
3565f1d45cc3SLars-Peter Clausen 	if (codec_drv->probe)
3566f1d45cc3SLars-Peter Clausen 		codec->component.probe = snd_soc_codec_drv_probe;
3567f1d45cc3SLars-Peter Clausen 	if (codec_drv->remove)
3568f1d45cc3SLars-Peter Clausen 		codec->component.remove = snd_soc_codec_drv_remove;
35699178feb4SKuninori Morimoto 	if (codec_drv->suspend)
35709178feb4SKuninori Morimoto 		codec->component.suspend = snd_soc_codec_drv_suspend;
35719178feb4SKuninori Morimoto 	if (codec_drv->resume)
35729178feb4SKuninori Morimoto 		codec->component.resume = snd_soc_codec_drv_resume;
3573e2c330b9SLars-Peter Clausen 	if (codec_drv->write)
3574e2c330b9SLars-Peter Clausen 		codec->component.write = snd_soc_codec_drv_write;
3575e2c330b9SLars-Peter Clausen 	if (codec_drv->read)
3576e2c330b9SLars-Peter Clausen 		codec->component.read = snd_soc_codec_drv_read;
357771ccef0dSKuninori Morimoto 	if (codec_drv->set_sysclk)
357871ccef0dSKuninori Morimoto 		codec->component.set_sysclk = snd_soc_codec_set_sysclk_;
3579ef641e5dSKuninori Morimoto 	if (codec_drv->set_pll)
3580ef641e5dSKuninori Morimoto 		codec->component.set_pll = snd_soc_codec_set_pll_;
358144c07365SKuninori Morimoto 	if (codec_drv->set_jack)
358244c07365SKuninori Morimoto 		codec->component.set_jack = snd_soc_codec_set_jack_;
35833d59400fSLars-Peter Clausen 	codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
35844890140fSLars-Peter Clausen 
35854890140fSLars-Peter Clausen 	dapm = snd_soc_codec_get_dapm(codec);
35864890140fSLars-Peter Clausen 	dapm->idle_bias_off = codec_drv->idle_bias_off;
35874890140fSLars-Peter Clausen 	dapm->suspend_bias_off = codec_drv->suspend_bias_off;
358814e8bdebSLars-Peter Clausen 	if (codec_drv->seq_notifier)
35894890140fSLars-Peter Clausen 		dapm->seq_notifier = codec_drv->seq_notifier;
359068f831c2SLars-Peter Clausen 	if (codec_drv->set_bias_level)
35914890140fSLars-Peter Clausen 		dapm->set_bias_level = snd_soc_codec_set_bias_level;
3592f0fba2adSLiam Girdwood 	codec->dev = dev;
3593f0fba2adSLiam Girdwood 	codec->driver = codec_drv;
3594e2c330b9SLars-Peter Clausen 	codec->component.val_bytes = codec_drv->reg_word_size;
3595f0fba2adSLiam Girdwood 
359681c7cfd1SLars-Peter Clausen #ifdef CONFIG_DEBUG_FS
359781c7cfd1SLars-Peter Clausen 	codec->component.init_debugfs = soc_init_codec_debugfs;
359881c7cfd1SLars-Peter Clausen 	codec->component.debugfs_prefix = "codec";
359981c7cfd1SLars-Peter Clausen #endif
3600a39f75f7SXiubo Li 
3601a39f75f7SXiubo Li 	if (codec_drv->get_regmap)
3602886f5692SLars-Peter Clausen 		codec->component.regmap = codec_drv->get_regmap(dev);
3603a39f75f7SXiubo Li 
3604f0fba2adSLiam Girdwood 	for (i = 0; i < num_dai; i++) {
3605273d778eSKuninori Morimoto 		convert_endianness_formats(&dai_drv[i].playback);
3606273d778eSKuninori Morimoto 		convert_endianness_formats(&dai_drv[i].capture);
3607f0fba2adSLiam Girdwood 	}
3608f0fba2adSLiam Girdwood 
3609bb13109dSLars-Peter Clausen 	ret = snd_soc_register_dais(&codec->component, dai_drv, num_dai, false);
3610bb13109dSLars-Peter Clausen 	if (ret < 0) {
3611f42cf8d6SMasanari Iida 		dev_err(dev, "ASoC: Failed to register DAIs: %d\n", ret);
3612bb13109dSLars-Peter Clausen 		goto err_cleanup;
3613bb13109dSLars-Peter Clausen 	}
3614bb13109dSLars-Peter Clausen 
3615bb13109dSLars-Peter Clausen 	list_for_each_entry(dai, &codec->component.dai_list, list)
3616bb13109dSLars-Peter Clausen 		dai->codec = codec;
3617bb13109dSLars-Peter Clausen 
3618054880feSMark Brown 	mutex_lock(&client_mutex);
3619bb13109dSLars-Peter Clausen 	snd_soc_component_add_unlocked(&codec->component);
3620054880feSMark Brown 	list_add(&codec->list, &codec_list);
3621054880feSMark Brown 	mutex_unlock(&client_mutex);
3622054880feSMark Brown 
3623f4333203SLars-Peter Clausen 	dev_dbg(codec->dev, "ASoC: Registered codec '%s'\n",
3624f4333203SLars-Peter Clausen 		codec->component.name);
36250d0cf00aSMark Brown 	return 0;
3626f0fba2adSLiam Girdwood 
3627bb13109dSLars-Peter Clausen err_cleanup:
3628bb13109dSLars-Peter Clausen 	snd_soc_component_cleanup(&codec->component);
3629bb13109dSLars-Peter Clausen err_free:
3630f0fba2adSLiam Girdwood 	kfree(codec);
3631f0fba2adSLiam Girdwood 	return ret;
36320d0cf00aSMark Brown }
36330d0cf00aSMark Brown EXPORT_SYMBOL_GPL(snd_soc_register_codec);
36340d0cf00aSMark Brown 
36350d0cf00aSMark Brown /**
36360d0cf00aSMark Brown  * snd_soc_unregister_codec - Unregister a codec from the ASoC core
36370d0cf00aSMark Brown  *
3638628536eaSJonathan Corbet  * @dev: codec to unregister
36390d0cf00aSMark Brown  */
3640f0fba2adSLiam Girdwood void snd_soc_unregister_codec(struct device *dev)
36410d0cf00aSMark Brown {
3642f0fba2adSLiam Girdwood 	struct snd_soc_codec *codec;
3643f0fba2adSLiam Girdwood 
364434e81ab4SLars-Peter Clausen 	mutex_lock(&client_mutex);
3645f0fba2adSLiam Girdwood 	list_for_each_entry(codec, &codec_list, list) {
3646f0fba2adSLiam Girdwood 		if (dev == codec->dev)
3647f0fba2adSLiam Girdwood 			goto found;
3648f0fba2adSLiam Girdwood 	}
364934e81ab4SLars-Peter Clausen 	mutex_unlock(&client_mutex);
3650f0fba2adSLiam Girdwood 	return;
3651f0fba2adSLiam Girdwood 
3652f0fba2adSLiam Girdwood found:
36530d0cf00aSMark Brown 	list_del(&codec->list);
3654bb13109dSLars-Peter Clausen 	snd_soc_component_del_unlocked(&codec->component);
36550d0cf00aSMark Brown 	mutex_unlock(&client_mutex);
36560d0cf00aSMark Brown 
3657f4333203SLars-Peter Clausen 	dev_dbg(codec->dev, "ASoC: Unregistered codec '%s'\n",
3658f4333203SLars-Peter Clausen 			codec->component.name);
3659f0fba2adSLiam Girdwood 
3660bb13109dSLars-Peter Clausen 	snd_soc_component_cleanup(&codec->component);
36617a30a3dbSDimitris Papastamos 	snd_soc_cache_exit(codec);
3662f0fba2adSLiam Girdwood 	kfree(codec);
36630d0cf00aSMark Brown }
36640d0cf00aSMark Brown EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
36650d0cf00aSMark Brown 
3666bec4fa05SStephen Warren /* Retrieve a card's name from device tree */
3667b07609ceSKuninori Morimoto int snd_soc_of_parse_card_name(struct snd_soc_card *card,
3668bec4fa05SStephen Warren 			       const char *propname)
3669bec4fa05SStephen Warren {
3670b07609ceSKuninori Morimoto 	struct device_node *np;
3671bec4fa05SStephen Warren 	int ret;
3672bec4fa05SStephen Warren 
36737e07e7c0STushar Behera 	if (!card->dev) {
36747e07e7c0STushar Behera 		pr_err("card->dev is not set before calling %s\n", __func__);
36757e07e7c0STushar Behera 		return -EINVAL;
36767e07e7c0STushar Behera 	}
36777e07e7c0STushar Behera 
36787e07e7c0STushar Behera 	np = card->dev->of_node;
36797e07e7c0STushar Behera 
3680bec4fa05SStephen Warren 	ret = of_property_read_string_index(np, propname, 0, &card->name);
3681bec4fa05SStephen Warren 	/*
3682bec4fa05SStephen Warren 	 * EINVAL means the property does not exist. This is fine providing
3683bec4fa05SStephen Warren 	 * card->name was previously set, which is checked later in
3684bec4fa05SStephen Warren 	 * snd_soc_register_card.
3685bec4fa05SStephen Warren 	 */
3686bec4fa05SStephen Warren 	if (ret < 0 && ret != -EINVAL) {
3687bec4fa05SStephen Warren 		dev_err(card->dev,
3688f110bfc7SLiam Girdwood 			"ASoC: Property '%s' could not be read: %d\n",
3689bec4fa05SStephen Warren 			propname, ret);
3690bec4fa05SStephen Warren 		return ret;
3691bec4fa05SStephen Warren 	}
3692bec4fa05SStephen Warren 
3693bec4fa05SStephen Warren 	return 0;
3694bec4fa05SStephen Warren }
3695b07609ceSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name);
3696bec4fa05SStephen Warren 
36979a6d4860SXiubo Li static const struct snd_soc_dapm_widget simple_widgets[] = {
36989a6d4860SXiubo Li 	SND_SOC_DAPM_MIC("Microphone", NULL),
36999a6d4860SXiubo Li 	SND_SOC_DAPM_LINE("Line", NULL),
37009a6d4860SXiubo Li 	SND_SOC_DAPM_HP("Headphone", NULL),
37019a6d4860SXiubo Li 	SND_SOC_DAPM_SPK("Speaker", NULL),
37029a6d4860SXiubo Li };
37039a6d4860SXiubo Li 
370421efde50SKuninori Morimoto int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
37059a6d4860SXiubo Li 					  const char *propname)
37069a6d4860SXiubo Li {
370721efde50SKuninori Morimoto 	struct device_node *np = card->dev->of_node;
37089a6d4860SXiubo Li 	struct snd_soc_dapm_widget *widgets;
37099a6d4860SXiubo Li 	const char *template, *wname;
37109a6d4860SXiubo Li 	int i, j, num_widgets, ret;
37119a6d4860SXiubo Li 
37129a6d4860SXiubo Li 	num_widgets = of_property_count_strings(np, propname);
37139a6d4860SXiubo Li 	if (num_widgets < 0) {
37149a6d4860SXiubo Li 		dev_err(card->dev,
37159a6d4860SXiubo Li 			"ASoC: Property '%s' does not exist\n",	propname);
37169a6d4860SXiubo Li 		return -EINVAL;
37179a6d4860SXiubo Li 	}
37189a6d4860SXiubo Li 	if (num_widgets & 1) {
37199a6d4860SXiubo Li 		dev_err(card->dev,
37209a6d4860SXiubo Li 			"ASoC: Property '%s' length is not even\n", propname);
37219a6d4860SXiubo Li 		return -EINVAL;
37229a6d4860SXiubo Li 	}
37239a6d4860SXiubo Li 
37249a6d4860SXiubo Li 	num_widgets /= 2;
37259a6d4860SXiubo Li 	if (!num_widgets) {
37269a6d4860SXiubo Li 		dev_err(card->dev, "ASoC: Property '%s's length is zero\n",
37279a6d4860SXiubo Li 			propname);
37289a6d4860SXiubo Li 		return -EINVAL;
37299a6d4860SXiubo Li 	}
37309a6d4860SXiubo Li 
37319a6d4860SXiubo Li 	widgets = devm_kcalloc(card->dev, num_widgets, sizeof(*widgets),
37329a6d4860SXiubo Li 			       GFP_KERNEL);
37339a6d4860SXiubo Li 	if (!widgets) {
37349a6d4860SXiubo Li 		dev_err(card->dev,
37359a6d4860SXiubo Li 			"ASoC: Could not allocate memory for widgets\n");
37369a6d4860SXiubo Li 		return -ENOMEM;
37379a6d4860SXiubo Li 	}
37389a6d4860SXiubo Li 
37399a6d4860SXiubo Li 	for (i = 0; i < num_widgets; i++) {
37409a6d4860SXiubo Li 		ret = of_property_read_string_index(np, propname,
37419a6d4860SXiubo Li 			2 * i, &template);
37429a6d4860SXiubo Li 		if (ret) {
37439a6d4860SXiubo Li 			dev_err(card->dev,
37449a6d4860SXiubo Li 				"ASoC: Property '%s' index %d read error:%d\n",
37459a6d4860SXiubo Li 				propname, 2 * i, ret);
37469a6d4860SXiubo Li 			return -EINVAL;
37479a6d4860SXiubo Li 		}
37489a6d4860SXiubo Li 
37499a6d4860SXiubo Li 		for (j = 0; j < ARRAY_SIZE(simple_widgets); j++) {
37509a6d4860SXiubo Li 			if (!strncmp(template, simple_widgets[j].name,
37519a6d4860SXiubo Li 				     strlen(simple_widgets[j].name))) {
37529a6d4860SXiubo Li 				widgets[i] = simple_widgets[j];
37539a6d4860SXiubo Li 				break;
37549a6d4860SXiubo Li 			}
37559a6d4860SXiubo Li 		}
37569a6d4860SXiubo Li 
37579a6d4860SXiubo Li 		if (j >= ARRAY_SIZE(simple_widgets)) {
37589a6d4860SXiubo Li 			dev_err(card->dev,
37599a6d4860SXiubo Li 				"ASoC: DAPM widget '%s' is not supported\n",
37609a6d4860SXiubo Li 				template);
37619a6d4860SXiubo Li 			return -EINVAL;
37629a6d4860SXiubo Li 		}
37639a6d4860SXiubo Li 
37649a6d4860SXiubo Li 		ret = of_property_read_string_index(np, propname,
37659a6d4860SXiubo Li 						    (2 * i) + 1,
37669a6d4860SXiubo Li 						    &wname);
37679a6d4860SXiubo Li 		if (ret) {
37689a6d4860SXiubo Li 			dev_err(card->dev,
37699a6d4860SXiubo Li 				"ASoC: Property '%s' index %d read error:%d\n",
37709a6d4860SXiubo Li 				propname, (2 * i) + 1, ret);
37719a6d4860SXiubo Li 			return -EINVAL;
37729a6d4860SXiubo Li 		}
37739a6d4860SXiubo Li 
37749a6d4860SXiubo Li 		widgets[i].name = wname;
37759a6d4860SXiubo Li 	}
37769a6d4860SXiubo Li 
3777f23e860eSNicolin Chen 	card->of_dapm_widgets = widgets;
3778f23e860eSNicolin Chen 	card->num_of_dapm_widgets = num_widgets;
37799a6d4860SXiubo Li 
37809a6d4860SXiubo Li 	return 0;
37819a6d4860SXiubo Li }
378221efde50SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets);
37839a6d4860SXiubo Li 
37846131084aSJyri Sarha static int snd_soc_of_get_slot_mask(struct device_node *np,
37856131084aSJyri Sarha 				    const char *prop_name,
37866131084aSJyri Sarha 				    unsigned int *mask)
37876131084aSJyri Sarha {
37886131084aSJyri Sarha 	u32 val;
37896c84e591SJyri Sarha 	const __be32 *of_slot_mask = of_get_property(np, prop_name, &val);
37906131084aSJyri Sarha 	int i;
37916131084aSJyri Sarha 
37926131084aSJyri Sarha 	if (!of_slot_mask)
37936131084aSJyri Sarha 		return 0;
37946131084aSJyri Sarha 	val /= sizeof(u32);
37956131084aSJyri Sarha 	for (i = 0; i < val; i++)
37966131084aSJyri Sarha 		if (be32_to_cpup(&of_slot_mask[i]))
37976131084aSJyri Sarha 			*mask |= (1 << i);
37986131084aSJyri Sarha 
37996131084aSJyri Sarha 	return val;
38006131084aSJyri Sarha }
38016131084aSJyri Sarha 
380289c67857SXiubo Li int snd_soc_of_parse_tdm_slot(struct device_node *np,
38036131084aSJyri Sarha 			      unsigned int *tx_mask,
38046131084aSJyri Sarha 			      unsigned int *rx_mask,
380589c67857SXiubo Li 			      unsigned int *slots,
380689c67857SXiubo Li 			      unsigned int *slot_width)
380789c67857SXiubo Li {
380889c67857SXiubo Li 	u32 val;
380989c67857SXiubo Li 	int ret;
381089c67857SXiubo Li 
38116131084aSJyri Sarha 	if (tx_mask)
38126131084aSJyri Sarha 		snd_soc_of_get_slot_mask(np, "dai-tdm-slot-tx-mask", tx_mask);
38136131084aSJyri Sarha 	if (rx_mask)
38146131084aSJyri Sarha 		snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", rx_mask);
38156131084aSJyri Sarha 
381689c67857SXiubo Li 	if (of_property_read_bool(np, "dai-tdm-slot-num")) {
381789c67857SXiubo Li 		ret = of_property_read_u32(np, "dai-tdm-slot-num", &val);
381889c67857SXiubo Li 		if (ret)
381989c67857SXiubo Li 			return ret;
382089c67857SXiubo Li 
382189c67857SXiubo Li 		if (slots)
382289c67857SXiubo Li 			*slots = val;
382389c67857SXiubo Li 	}
382489c67857SXiubo Li 
382589c67857SXiubo Li 	if (of_property_read_bool(np, "dai-tdm-slot-width")) {
382689c67857SXiubo Li 		ret = of_property_read_u32(np, "dai-tdm-slot-width", &val);
382789c67857SXiubo Li 		if (ret)
382889c67857SXiubo Li 			return ret;
382989c67857SXiubo Li 
383089c67857SXiubo Li 		if (slot_width)
383189c67857SXiubo Li 			*slot_width = val;
383289c67857SXiubo Li 	}
383389c67857SXiubo Li 
383489c67857SXiubo Li 	return 0;
383589c67857SXiubo Li }
383689c67857SXiubo Li EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot);
383789c67857SXiubo Li 
3838440a3006SKuninori Morimoto void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
38395e3cdaa2SKuninori Morimoto 				   struct snd_soc_codec_conf *codec_conf,
38405e3cdaa2SKuninori Morimoto 				   struct device_node *of_node,
38415e3cdaa2SKuninori Morimoto 				   const char *propname)
38425e3cdaa2SKuninori Morimoto {
3843440a3006SKuninori Morimoto 	struct device_node *np = card->dev->of_node;
38445e3cdaa2SKuninori Morimoto 	const char *str;
38455e3cdaa2SKuninori Morimoto 	int ret;
38465e3cdaa2SKuninori Morimoto 
38475e3cdaa2SKuninori Morimoto 	ret = of_property_read_string(np, propname, &str);
38485e3cdaa2SKuninori Morimoto 	if (ret < 0) {
38495e3cdaa2SKuninori Morimoto 		/* no prefix is not error */
38505e3cdaa2SKuninori Morimoto 		return;
38515e3cdaa2SKuninori Morimoto 	}
38525e3cdaa2SKuninori Morimoto 
38535e3cdaa2SKuninori Morimoto 	codec_conf->of_node	= of_node;
38545e3cdaa2SKuninori Morimoto 	codec_conf->name_prefix	= str;
38555e3cdaa2SKuninori Morimoto }
3856440a3006SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix);
38575e3cdaa2SKuninori Morimoto 
38582bc644afSKuninori Morimoto int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
3859a4a54dd5SStephen Warren 				   const char *propname)
3860a4a54dd5SStephen Warren {
38612bc644afSKuninori Morimoto 	struct device_node *np = card->dev->of_node;
3862e3b1e6a1SMark Brown 	int num_routes;
3863a4a54dd5SStephen Warren 	struct snd_soc_dapm_route *routes;
3864a4a54dd5SStephen Warren 	int i, ret;
3865a4a54dd5SStephen Warren 
3866a4a54dd5SStephen Warren 	num_routes = of_property_count_strings(np, propname);
3867c34ce320SRichard Zhao 	if (num_routes < 0 || num_routes & 1) {
386810e8aa9aSMichał Mirosław 		dev_err(card->dev,
386910e8aa9aSMichał Mirosław 			"ASoC: Property '%s' does not exist or its length is not even\n",
387010e8aa9aSMichał Mirosław 			propname);
3871a4a54dd5SStephen Warren 		return -EINVAL;
3872a4a54dd5SStephen Warren 	}
3873a4a54dd5SStephen Warren 	num_routes /= 2;
3874a4a54dd5SStephen Warren 	if (!num_routes) {
3875f110bfc7SLiam Girdwood 		dev_err(card->dev, "ASoC: Property '%s's length is zero\n",
3876a4a54dd5SStephen Warren 			propname);
3877a4a54dd5SStephen Warren 		return -EINVAL;
3878a4a54dd5SStephen Warren 	}
3879a4a54dd5SStephen Warren 
3880e3b1e6a1SMark Brown 	routes = devm_kzalloc(card->dev, num_routes * sizeof(*routes),
3881a4a54dd5SStephen Warren 			      GFP_KERNEL);
3882a4a54dd5SStephen Warren 	if (!routes) {
3883a4a54dd5SStephen Warren 		dev_err(card->dev,
3884f110bfc7SLiam Girdwood 			"ASoC: Could not allocate DAPM route table\n");
3885a4a54dd5SStephen Warren 		return -EINVAL;
3886a4a54dd5SStephen Warren 	}
3887a4a54dd5SStephen Warren 
3888a4a54dd5SStephen Warren 	for (i = 0; i < num_routes; i++) {
3889a4a54dd5SStephen Warren 		ret = of_property_read_string_index(np, propname,
3890e3b1e6a1SMark Brown 			2 * i, &routes[i].sink);
3891a4a54dd5SStephen Warren 		if (ret) {
3892c871bd0bSMark Brown 			dev_err(card->dev,
3893c871bd0bSMark Brown 				"ASoC: Property '%s' index %d could not be read: %d\n",
3894c871bd0bSMark Brown 				propname, 2 * i, ret);
3895a4a54dd5SStephen Warren 			return -EINVAL;
3896a4a54dd5SStephen Warren 		}
3897a4a54dd5SStephen Warren 		ret = of_property_read_string_index(np, propname,
3898e3b1e6a1SMark Brown 			(2 * i) + 1, &routes[i].source);
3899a4a54dd5SStephen Warren 		if (ret) {
3900a4a54dd5SStephen Warren 			dev_err(card->dev,
3901c871bd0bSMark Brown 				"ASoC: Property '%s' index %d could not be read: %d\n",
3902c871bd0bSMark Brown 				propname, (2 * i) + 1, ret);
3903a4a54dd5SStephen Warren 			return -EINVAL;
3904a4a54dd5SStephen Warren 		}
3905a4a54dd5SStephen Warren 	}
3906a4a54dd5SStephen Warren 
3907f23e860eSNicolin Chen 	card->num_of_dapm_routes = num_routes;
3908f23e860eSNicolin Chen 	card->of_dapm_routes = routes;
3909a4a54dd5SStephen Warren 
3910a4a54dd5SStephen Warren 	return 0;
3911a4a54dd5SStephen Warren }
39122bc644afSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing);
3913a4a54dd5SStephen Warren 
3914a7930ed4SKuninori Morimoto unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
3915389cb834SJyri Sarha 				     const char *prefix,
3916389cb834SJyri Sarha 				     struct device_node **bitclkmaster,
3917389cb834SJyri Sarha 				     struct device_node **framemaster)
3918a7930ed4SKuninori Morimoto {
3919a7930ed4SKuninori Morimoto 	int ret, i;
3920a7930ed4SKuninori Morimoto 	char prop[128];
3921a7930ed4SKuninori Morimoto 	unsigned int format = 0;
3922a7930ed4SKuninori Morimoto 	int bit, frame;
3923a7930ed4SKuninori Morimoto 	const char *str;
3924a7930ed4SKuninori Morimoto 	struct {
3925a7930ed4SKuninori Morimoto 		char *name;
3926a7930ed4SKuninori Morimoto 		unsigned int val;
3927a7930ed4SKuninori Morimoto 	} of_fmt_table[] = {
3928a7930ed4SKuninori Morimoto 		{ "i2s",	SND_SOC_DAIFMT_I2S },
3929a7930ed4SKuninori Morimoto 		{ "right_j",	SND_SOC_DAIFMT_RIGHT_J },
3930a7930ed4SKuninori Morimoto 		{ "left_j",	SND_SOC_DAIFMT_LEFT_J },
3931a7930ed4SKuninori Morimoto 		{ "dsp_a",	SND_SOC_DAIFMT_DSP_A },
3932a7930ed4SKuninori Morimoto 		{ "dsp_b",	SND_SOC_DAIFMT_DSP_B },
3933a7930ed4SKuninori Morimoto 		{ "ac97",	SND_SOC_DAIFMT_AC97 },
3934a7930ed4SKuninori Morimoto 		{ "pdm",	SND_SOC_DAIFMT_PDM},
3935a7930ed4SKuninori Morimoto 		{ "msb",	SND_SOC_DAIFMT_MSB },
3936a7930ed4SKuninori Morimoto 		{ "lsb",	SND_SOC_DAIFMT_LSB },
3937a7930ed4SKuninori Morimoto 	};
3938a7930ed4SKuninori Morimoto 
3939a7930ed4SKuninori Morimoto 	if (!prefix)
3940a7930ed4SKuninori Morimoto 		prefix = "";
3941a7930ed4SKuninori Morimoto 
3942a7930ed4SKuninori Morimoto 	/*
39435711c979SKuninori Morimoto 	 * check "dai-format = xxx"
39445711c979SKuninori Morimoto 	 * or    "[prefix]format = xxx"
3945a7930ed4SKuninori Morimoto 	 * SND_SOC_DAIFMT_FORMAT_MASK area
3946a7930ed4SKuninori Morimoto 	 */
39475711c979SKuninori Morimoto 	ret = of_property_read_string(np, "dai-format", &str);
39485711c979SKuninori Morimoto 	if (ret < 0) {
3949a7930ed4SKuninori Morimoto 		snprintf(prop, sizeof(prop), "%sformat", prefix);
3950a7930ed4SKuninori Morimoto 		ret = of_property_read_string(np, prop, &str);
39515711c979SKuninori Morimoto 	}
3952a7930ed4SKuninori Morimoto 	if (ret == 0) {
3953a7930ed4SKuninori Morimoto 		for (i = 0; i < ARRAY_SIZE(of_fmt_table); i++) {
3954a7930ed4SKuninori Morimoto 			if (strcmp(str, of_fmt_table[i].name) == 0) {
3955a7930ed4SKuninori Morimoto 				format |= of_fmt_table[i].val;
3956a7930ed4SKuninori Morimoto 				break;
3957a7930ed4SKuninori Morimoto 			}
3958a7930ed4SKuninori Morimoto 		}
3959a7930ed4SKuninori Morimoto 	}
3960a7930ed4SKuninori Morimoto 
3961a7930ed4SKuninori Morimoto 	/*
39628c2d6a9fSKuninori Morimoto 	 * check "[prefix]continuous-clock"
3963a7930ed4SKuninori Morimoto 	 * SND_SOC_DAIFMT_CLOCK_MASK area
3964a7930ed4SKuninori Morimoto 	 */
39658c2d6a9fSKuninori Morimoto 	snprintf(prop, sizeof(prop), "%scontinuous-clock", prefix);
396651930295SJulia Lawall 	if (of_property_read_bool(np, prop))
39678c2d6a9fSKuninori Morimoto 		format |= SND_SOC_DAIFMT_CONT;
39688c2d6a9fSKuninori Morimoto 	else
39698c2d6a9fSKuninori Morimoto 		format |= SND_SOC_DAIFMT_GATED;
3970a7930ed4SKuninori Morimoto 
3971a7930ed4SKuninori Morimoto 	/*
3972a7930ed4SKuninori Morimoto 	 * check "[prefix]bitclock-inversion"
3973a7930ed4SKuninori Morimoto 	 * check "[prefix]frame-inversion"
3974a7930ed4SKuninori Morimoto 	 * SND_SOC_DAIFMT_INV_MASK area
3975a7930ed4SKuninori Morimoto 	 */
3976a7930ed4SKuninori Morimoto 	snprintf(prop, sizeof(prop), "%sbitclock-inversion", prefix);
3977a7930ed4SKuninori Morimoto 	bit = !!of_get_property(np, prop, NULL);
3978a7930ed4SKuninori Morimoto 
3979a7930ed4SKuninori Morimoto 	snprintf(prop, sizeof(prop), "%sframe-inversion", prefix);
3980a7930ed4SKuninori Morimoto 	frame = !!of_get_property(np, prop, NULL);
3981a7930ed4SKuninori Morimoto 
3982a7930ed4SKuninori Morimoto 	switch ((bit << 4) + frame) {
3983a7930ed4SKuninori Morimoto 	case 0x11:
3984a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_IB_IF;
3985a7930ed4SKuninori Morimoto 		break;
3986a7930ed4SKuninori Morimoto 	case 0x10:
3987a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_IB_NF;
3988a7930ed4SKuninori Morimoto 		break;
3989a7930ed4SKuninori Morimoto 	case 0x01:
3990a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_NB_IF;
3991a7930ed4SKuninori Morimoto 		break;
3992a7930ed4SKuninori Morimoto 	default:
3993a7930ed4SKuninori Morimoto 		/* SND_SOC_DAIFMT_NB_NF is default */
3994a7930ed4SKuninori Morimoto 		break;
3995a7930ed4SKuninori Morimoto 	}
3996a7930ed4SKuninori Morimoto 
3997a7930ed4SKuninori Morimoto 	/*
3998a7930ed4SKuninori Morimoto 	 * check "[prefix]bitclock-master"
3999a7930ed4SKuninori Morimoto 	 * check "[prefix]frame-master"
4000a7930ed4SKuninori Morimoto 	 * SND_SOC_DAIFMT_MASTER_MASK area
4001a7930ed4SKuninori Morimoto 	 */
4002a7930ed4SKuninori Morimoto 	snprintf(prop, sizeof(prop), "%sbitclock-master", prefix);
4003a7930ed4SKuninori Morimoto 	bit = !!of_get_property(np, prop, NULL);
4004389cb834SJyri Sarha 	if (bit && bitclkmaster)
4005389cb834SJyri Sarha 		*bitclkmaster = of_parse_phandle(np, prop, 0);
4006a7930ed4SKuninori Morimoto 
4007a7930ed4SKuninori Morimoto 	snprintf(prop, sizeof(prop), "%sframe-master", prefix);
4008a7930ed4SKuninori Morimoto 	frame = !!of_get_property(np, prop, NULL);
4009389cb834SJyri Sarha 	if (frame && framemaster)
4010389cb834SJyri Sarha 		*framemaster = of_parse_phandle(np, prop, 0);
4011a7930ed4SKuninori Morimoto 
4012a7930ed4SKuninori Morimoto 	switch ((bit << 4) + frame) {
4013a7930ed4SKuninori Morimoto 	case 0x11:
4014a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_CBM_CFM;
4015a7930ed4SKuninori Morimoto 		break;
4016a7930ed4SKuninori Morimoto 	case 0x10:
4017a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_CBM_CFS;
4018a7930ed4SKuninori Morimoto 		break;
4019a7930ed4SKuninori Morimoto 	case 0x01:
4020a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_CBS_CFM;
4021a7930ed4SKuninori Morimoto 		break;
4022a7930ed4SKuninori Morimoto 	default:
4023a7930ed4SKuninori Morimoto 		format |= SND_SOC_DAIFMT_CBS_CFS;
4024a7930ed4SKuninori Morimoto 		break;
4025a7930ed4SKuninori Morimoto 	}
4026a7930ed4SKuninori Morimoto 
4027a7930ed4SKuninori Morimoto 	return format;
4028a7930ed4SKuninori Morimoto }
4029a7930ed4SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt);
4030a7930ed4SKuninori Morimoto 
4031a180e8b9SKuninori Morimoto int snd_soc_get_dai_id(struct device_node *ep)
4032a180e8b9SKuninori Morimoto {
4033a180e8b9SKuninori Morimoto 	struct snd_soc_component *pos;
4034a180e8b9SKuninori Morimoto 	struct device_node *node;
4035a180e8b9SKuninori Morimoto 	int ret;
4036a180e8b9SKuninori Morimoto 
4037a180e8b9SKuninori Morimoto 	node = of_graph_get_port_parent(ep);
4038a180e8b9SKuninori Morimoto 
4039a180e8b9SKuninori Morimoto 	/*
4040a180e8b9SKuninori Morimoto 	 * For example HDMI case, HDMI has video/sound port,
4041a180e8b9SKuninori Morimoto 	 * but ALSA SoC needs sound port number only.
4042a180e8b9SKuninori Morimoto 	 * Thus counting HDMI DT port/endpoint doesn't work.
4043a180e8b9SKuninori Morimoto 	 * Then, it should have .of_xlate_dai_id
4044a180e8b9SKuninori Morimoto 	 */
4045a180e8b9SKuninori Morimoto 	ret = -ENOTSUPP;
4046a180e8b9SKuninori Morimoto 	mutex_lock(&client_mutex);
4047a180e8b9SKuninori Morimoto 	list_for_each_entry(pos, &component_list, list) {
4048a180e8b9SKuninori Morimoto 		struct device_node *component_of_node = pos->dev->of_node;
4049a180e8b9SKuninori Morimoto 
4050a180e8b9SKuninori Morimoto 		if (!component_of_node && pos->dev->parent)
4051a180e8b9SKuninori Morimoto 			component_of_node = pos->dev->parent->of_node;
4052a180e8b9SKuninori Morimoto 
4053a180e8b9SKuninori Morimoto 		if (component_of_node != node)
4054a180e8b9SKuninori Morimoto 			continue;
4055a180e8b9SKuninori Morimoto 
4056a180e8b9SKuninori Morimoto 		if (pos->driver->of_xlate_dai_id)
4057a180e8b9SKuninori Morimoto 			ret = pos->driver->of_xlate_dai_id(pos, ep);
4058a180e8b9SKuninori Morimoto 
4059a180e8b9SKuninori Morimoto 		break;
4060a180e8b9SKuninori Morimoto 	}
4061a180e8b9SKuninori Morimoto 	mutex_unlock(&client_mutex);
4062a180e8b9SKuninori Morimoto 
4063c0a480d1STony Lindgren 	of_node_put(node);
4064c0a480d1STony Lindgren 
4065a180e8b9SKuninori Morimoto 	return ret;
4066a180e8b9SKuninori Morimoto }
4067a180e8b9SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_get_dai_id);
4068a180e8b9SKuninori Morimoto 
40691ad8ec53SKuninori Morimoto int snd_soc_get_dai_name(struct of_phandle_args *args,
4070cb470087SKuninori Morimoto 				const char **dai_name)
4071cb470087SKuninori Morimoto {
4072cb470087SKuninori Morimoto 	struct snd_soc_component *pos;
40733e0aa8d8SJyri Sarha 	struct device_node *component_of_node;
407493b0f3eeSJean-Francois Moine 	int ret = -EPROBE_DEFER;
4075cb470087SKuninori Morimoto 
4076cb470087SKuninori Morimoto 	mutex_lock(&client_mutex);
4077cb470087SKuninori Morimoto 	list_for_each_entry(pos, &component_list, list) {
40783e0aa8d8SJyri Sarha 		component_of_node = pos->dev->of_node;
40793e0aa8d8SJyri Sarha 		if (!component_of_node && pos->dev->parent)
40803e0aa8d8SJyri Sarha 			component_of_node = pos->dev->parent->of_node;
40813e0aa8d8SJyri Sarha 
40823e0aa8d8SJyri Sarha 		if (component_of_node != args->np)
4083cb470087SKuninori Morimoto 			continue;
4084cb470087SKuninori Morimoto 
40856833c452SKuninori Morimoto 		if (pos->driver->of_xlate_dai_name) {
408693b0f3eeSJean-Francois Moine 			ret = pos->driver->of_xlate_dai_name(pos,
408793b0f3eeSJean-Francois Moine 							     args,
408893b0f3eeSJean-Francois Moine 							     dai_name);
40896833c452SKuninori Morimoto 		} else {
409058bf4179SKuninori Morimoto 			struct snd_soc_dai *dai;
40916833c452SKuninori Morimoto 			int id = -1;
40926833c452SKuninori Morimoto 
409393b0f3eeSJean-Francois Moine 			switch (args->args_count) {
40946833c452SKuninori Morimoto 			case 0:
40956833c452SKuninori Morimoto 				id = 0; /* same as dai_drv[0] */
40966833c452SKuninori Morimoto 				break;
40976833c452SKuninori Morimoto 			case 1:
409893b0f3eeSJean-Francois Moine 				id = args->args[0];
40996833c452SKuninori Morimoto 				break;
41006833c452SKuninori Morimoto 			default:
41016833c452SKuninori Morimoto 				/* not supported */
4102cb470087SKuninori Morimoto 				break;
4103cb470087SKuninori Morimoto 			}
4104cb470087SKuninori Morimoto 
41056833c452SKuninori Morimoto 			if (id < 0 || id >= pos->num_dai) {
41066833c452SKuninori Morimoto 				ret = -EINVAL;
41073dcba280SNicolin Chen 				continue;
41086833c452SKuninori Morimoto 			}
4109e41975edSXiubo Li 
4110e41975edSXiubo Li 			ret = 0;
4111e41975edSXiubo Li 
411258bf4179SKuninori Morimoto 			/* find target DAI */
411358bf4179SKuninori Morimoto 			list_for_each_entry(dai, &pos->dai_list, list) {
411458bf4179SKuninori Morimoto 				if (id == 0)
411558bf4179SKuninori Morimoto 					break;
411658bf4179SKuninori Morimoto 				id--;
411758bf4179SKuninori Morimoto 			}
411858bf4179SKuninori Morimoto 
411958bf4179SKuninori Morimoto 			*dai_name = dai->driver->name;
4120e41975edSXiubo Li 			if (!*dai_name)
4121e41975edSXiubo Li 				*dai_name = pos->name;
41226833c452SKuninori Morimoto 		}
41236833c452SKuninori Morimoto 
4124cb470087SKuninori Morimoto 		break;
4125cb470087SKuninori Morimoto 	}
4126cb470087SKuninori Morimoto 	mutex_unlock(&client_mutex);
412793b0f3eeSJean-Francois Moine 	return ret;
412893b0f3eeSJean-Francois Moine }
41291ad8ec53SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_get_dai_name);
413093b0f3eeSJean-Francois Moine 
413193b0f3eeSJean-Francois Moine int snd_soc_of_get_dai_name(struct device_node *of_node,
413293b0f3eeSJean-Francois Moine 			    const char **dai_name)
413393b0f3eeSJean-Francois Moine {
413493b0f3eeSJean-Francois Moine 	struct of_phandle_args args;
413593b0f3eeSJean-Francois Moine 	int ret;
413693b0f3eeSJean-Francois Moine 
413793b0f3eeSJean-Francois Moine 	ret = of_parse_phandle_with_args(of_node, "sound-dai",
413893b0f3eeSJean-Francois Moine 					 "#sound-dai-cells", 0, &args);
413993b0f3eeSJean-Francois Moine 	if (ret)
414093b0f3eeSJean-Francois Moine 		return ret;
414193b0f3eeSJean-Francois Moine 
414293b0f3eeSJean-Francois Moine 	ret = snd_soc_get_dai_name(&args, dai_name);
4143cb470087SKuninori Morimoto 
4144cb470087SKuninori Morimoto 	of_node_put(args.np);
4145cb470087SKuninori Morimoto 
4146cb470087SKuninori Morimoto 	return ret;
4147cb470087SKuninori Morimoto }
4148cb470087SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name);
4149cb470087SKuninori Morimoto 
415093b0f3eeSJean-Francois Moine /*
415194685763SSylwester Nawrocki  * snd_soc_of_put_dai_link_codecs - Dereference device nodes in the codecs array
415294685763SSylwester Nawrocki  * @dai_link: DAI link
415394685763SSylwester Nawrocki  *
415494685763SSylwester Nawrocki  * Dereference device nodes acquired by snd_soc_of_get_dai_link_codecs().
415594685763SSylwester Nawrocki  */
415694685763SSylwester Nawrocki void snd_soc_of_put_dai_link_codecs(struct snd_soc_dai_link *dai_link)
415794685763SSylwester Nawrocki {
415894685763SSylwester Nawrocki 	struct snd_soc_dai_link_component *component = dai_link->codecs;
415994685763SSylwester Nawrocki 	int index;
416094685763SSylwester Nawrocki 
416194685763SSylwester Nawrocki 	for (index = 0; index < dai_link->num_codecs; index++, component++) {
416294685763SSylwester Nawrocki 		if (!component->of_node)
416394685763SSylwester Nawrocki 			break;
416494685763SSylwester Nawrocki 		of_node_put(component->of_node);
416594685763SSylwester Nawrocki 		component->of_node = NULL;
416694685763SSylwester Nawrocki 	}
416794685763SSylwester Nawrocki }
416894685763SSylwester Nawrocki EXPORT_SYMBOL_GPL(snd_soc_of_put_dai_link_codecs);
416994685763SSylwester Nawrocki 
417094685763SSylwester Nawrocki /*
417193b0f3eeSJean-Francois Moine  * snd_soc_of_get_dai_link_codecs - Parse a list of CODECs in the devicetree
417293b0f3eeSJean-Francois Moine  * @dev: Card device
417393b0f3eeSJean-Francois Moine  * @of_node: Device node
417493b0f3eeSJean-Francois Moine  * @dai_link: DAI link
417593b0f3eeSJean-Francois Moine  *
417693b0f3eeSJean-Francois Moine  * Builds an array of CODEC DAI components from the DAI link property
417793b0f3eeSJean-Francois Moine  * 'sound-dai'.
417893b0f3eeSJean-Francois Moine  * The array is set in the DAI link and the number of DAIs is set accordingly.
417994685763SSylwester Nawrocki  * The device nodes in the array (of_node) must be dereferenced by calling
418094685763SSylwester Nawrocki  * snd_soc_of_put_dai_link_codecs() on @dai_link.
418193b0f3eeSJean-Francois Moine  *
418293b0f3eeSJean-Francois Moine  * Returns 0 for success
418393b0f3eeSJean-Francois Moine  */
418493b0f3eeSJean-Francois Moine int snd_soc_of_get_dai_link_codecs(struct device *dev,
418593b0f3eeSJean-Francois Moine 				   struct device_node *of_node,
418693b0f3eeSJean-Francois Moine 				   struct snd_soc_dai_link *dai_link)
418793b0f3eeSJean-Francois Moine {
418893b0f3eeSJean-Francois Moine 	struct of_phandle_args args;
418993b0f3eeSJean-Francois Moine 	struct snd_soc_dai_link_component *component;
419093b0f3eeSJean-Francois Moine 	char *name;
419193b0f3eeSJean-Francois Moine 	int index, num_codecs, ret;
419293b0f3eeSJean-Francois Moine 
419393b0f3eeSJean-Francois Moine 	/* Count the number of CODECs */
419493b0f3eeSJean-Francois Moine 	name = "sound-dai";
419593b0f3eeSJean-Francois Moine 	num_codecs = of_count_phandle_with_args(of_node, name,
419693b0f3eeSJean-Francois Moine 						"#sound-dai-cells");
419793b0f3eeSJean-Francois Moine 	if (num_codecs <= 0) {
419893b0f3eeSJean-Francois Moine 		if (num_codecs == -ENOENT)
419993b0f3eeSJean-Francois Moine 			dev_err(dev, "No 'sound-dai' property\n");
420093b0f3eeSJean-Francois Moine 		else
420193b0f3eeSJean-Francois Moine 			dev_err(dev, "Bad phandle in 'sound-dai'\n");
420293b0f3eeSJean-Francois Moine 		return num_codecs;
420393b0f3eeSJean-Francois Moine 	}
420493b0f3eeSJean-Francois Moine 	component = devm_kzalloc(dev,
420593b0f3eeSJean-Francois Moine 				 sizeof *component * num_codecs,
420693b0f3eeSJean-Francois Moine 				 GFP_KERNEL);
420793b0f3eeSJean-Francois Moine 	if (!component)
420893b0f3eeSJean-Francois Moine 		return -ENOMEM;
420993b0f3eeSJean-Francois Moine 	dai_link->codecs = component;
421093b0f3eeSJean-Francois Moine 	dai_link->num_codecs = num_codecs;
421193b0f3eeSJean-Francois Moine 
421293b0f3eeSJean-Francois Moine 	/* Parse the list */
421393b0f3eeSJean-Francois Moine 	for (index = 0, component = dai_link->codecs;
421493b0f3eeSJean-Francois Moine 	     index < dai_link->num_codecs;
421593b0f3eeSJean-Francois Moine 	     index++, component++) {
421693b0f3eeSJean-Francois Moine 		ret = of_parse_phandle_with_args(of_node, name,
421793b0f3eeSJean-Francois Moine 						 "#sound-dai-cells",
421893b0f3eeSJean-Francois Moine 						  index, &args);
421993b0f3eeSJean-Francois Moine 		if (ret)
422093b0f3eeSJean-Francois Moine 			goto err;
422193b0f3eeSJean-Francois Moine 		component->of_node = args.np;
422293b0f3eeSJean-Francois Moine 		ret = snd_soc_get_dai_name(&args, &component->dai_name);
422393b0f3eeSJean-Francois Moine 		if (ret < 0)
422493b0f3eeSJean-Francois Moine 			goto err;
422593b0f3eeSJean-Francois Moine 	}
422693b0f3eeSJean-Francois Moine 	return 0;
422793b0f3eeSJean-Francois Moine err:
422894685763SSylwester Nawrocki 	snd_soc_of_put_dai_link_codecs(dai_link);
422993b0f3eeSJean-Francois Moine 	dai_link->codecs = NULL;
423093b0f3eeSJean-Francois Moine 	dai_link->num_codecs = 0;
423193b0f3eeSJean-Francois Moine 	return ret;
423293b0f3eeSJean-Francois Moine }
423393b0f3eeSJean-Francois Moine EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_link_codecs);
423493b0f3eeSJean-Francois Moine 
4235c9b3a40fSTakashi Iwai static int __init snd_soc_init(void)
4236db2a4165SFrank Mandarino {
42376553bf06SLars-Peter Clausen 	snd_soc_debugfs_init();
4238fb257897SMark Brown 	snd_soc_util_init();
4239fb257897SMark Brown 
4240db2a4165SFrank Mandarino 	return platform_driver_register(&soc_driver);
4241db2a4165SFrank Mandarino }
42424abe8e16SMark Brown module_init(snd_soc_init);
4243db2a4165SFrank Mandarino 
42447d8c16a6SMark Brown static void __exit snd_soc_exit(void)
4245db2a4165SFrank Mandarino {
4246fb257897SMark Brown 	snd_soc_util_exit();
42476553bf06SLars-Peter Clausen 	snd_soc_debugfs_exit();
4248fb257897SMark Brown 
4249db2a4165SFrank Mandarino 	platform_driver_unregister(&soc_driver);
4250db2a4165SFrank Mandarino }
4251db2a4165SFrank Mandarino module_exit(snd_soc_exit);
4252db2a4165SFrank Mandarino 
4253db2a4165SFrank Mandarino /* Module information */
4254d331124dSLiam Girdwood MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
4255db2a4165SFrank Mandarino MODULE_DESCRIPTION("ALSA SoC Core");
4256db2a4165SFrank Mandarino MODULE_LICENSE("GPL");
4257db2a4165SFrank Mandarino MODULE_ALIAS("platform:soc-audio");
4258