Blame view

sound/soc/soc-core.c 88.2 KB
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1
2
3
4
  /*
   * soc-core.c  --  ALSA SoC Audio Layer
   *
   * Copyright 2005 Wolfson Microelectronics PLC.
0664d888a   Liam Girdwood   [ALSA] Additional...
5
   * Copyright 2005 Openedhand Ltd.
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
6
7
   * Copyright (C) 2010 Slimlogic Ltd.
   * Copyright (C) 2010 Texas Instruments Inc.
0664d888a   Liam Girdwood   [ALSA] Additional...
8
   *
d331124dc   Liam Girdwood   ALSA: ASoC: updat...
9
   * Author: Liam Girdwood <lrg@slimlogic.co.uk>
0664d888a   Liam Girdwood   [ALSA] Additional...
10
11
   *         with code, comments and ideas from :-
   *         Richard Purdie <richard@openedhand.com>
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
12
13
14
15
16
17
   *
   *  This program is free software; you can redistribute  it and/or modify it
   *  under  the terms of  the GNU General  Public License as published by the
   *  Free Software Foundation;  either version 2 of the  License, or (at your
   *  option) any later version.
   *
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
18
19
20
21
22
23
24
25
26
27
28
29
30
   *  TODO:
   *   o Add hw rules to enforce rates, etc.
   *   o More testing with other codecs/machines.
   *   o Add more codecs and platforms to ensure good API coverage.
   *   o Support TDM on PCM and I2S
   */
  
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/init.h>
  #include <linux/delay.h>
  #include <linux/pm.h>
  #include <linux/bitops.h>
12ef193d5   Troy Kisky   ASoC: Allow setti...
31
  #include <linux/debugfs.h>
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
32
  #include <linux/platform_device.h>
f0e8ed858   Mark Brown   ASoC: Ensure we g...
33
  #include <linux/ctype.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
34
  #include <linux/slab.h>
bec4fa05e   Stephen Warren   ASoC: Add utility...
35
  #include <linux/of.h>
474828a40   Marek Vasut   ALSA: Allow passi...
36
  #include <sound/ac97_codec.h>
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
37
  #include <sound/core.h>
3028eb8c5   Mark Brown   ASoC: Add trace e...
38
  #include <sound/jack.h>
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
39
40
41
  #include <sound/pcm.h>
  #include <sound/pcm_params.h>
  #include <sound/soc.h>
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
42
  #include <sound/initval.h>
a8b1d34f3   Mark Brown   ASoC: Add trace e...
43
44
  #define CREATE_TRACE_POINTS
  #include <trace/events/asoc.h>
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
45
  #define NAME_SIZE	32
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
46
  static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq);
384c89e2e   Mark Brown   ASoC: Push debugf...
47
  #ifdef CONFIG_DEBUG_FS
8a9dab1a5   Mark Brown   ASoC: Update name...
48
49
  struct dentry *snd_soc_debugfs_root;
  EXPORT_SYMBOL_GPL(snd_soc_debugfs_root);
384c89e2e   Mark Brown   ASoC: Push debugf...
50
  #endif
c5af3a2e1   Mark Brown   ASoC: Add card re...
51
52
  static DEFINE_MUTEX(client_mutex);
  static LIST_HEAD(card_list);
9115171a6   Mark Brown   ASoC: Add DAI reg...
53
  static LIST_HEAD(dai_list);
12a48a8c0   Mark Brown   ASoC: Add platfor...
54
  static LIST_HEAD(platform_list);
0d0cf00a7   Mark Brown   ASoC: Add codec r...
55
  static LIST_HEAD(codec_list);
c5af3a2e1   Mark Brown   ASoC: Add card re...
56

db2a41655   Frank Mandarino   [ALSA] ASoC: core...
57
58
59
60
61
62
63
64
  /*
   * This is a timeout to do a DAPM powerdown after a stream is closed().
   * It can be used to eliminate pops between different playback streams, e.g.
   * between two audio tracks.
   */
  static int pmdown_time = 5000;
  module_param(pmdown_time, int, 0);
  MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)");
2bc9a81e2   Dimitris Papastamos   ASoC: soc-core: E...
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  /* returns the minimum number of bytes needed to represent
   * a particular given value */
  static int min_bytes_needed(unsigned long val)
  {
  	int c = 0;
  	int i;
  
  	for (i = (sizeof val * 8) - 1; i >= 0; --i, ++c)
  		if (val & (1UL << i))
  			break;
  	c = (sizeof val * 8) - c;
  	if (!c || (c % 8))
  		c = (c + 8) / 8;
  	else
  		c /= 8;
  	return c;
  }
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
82
83
84
85
86
87
  /* fill buf which is 'len' bytes with a formatted
   * string of the form 'reg: value
  ' */
  static int format_register_str(struct snd_soc_codec *codec,
  			       unsigned int reg, char *buf, size_t len)
  {
00b317a41   Stephen Warren   ASoC: format_regi...
88
89
  	int wordsize = min_bytes_needed(codec->driver->reg_cache_size) * 2;
  	int regsize = codec->driver->reg_word_size * 2;
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
90
91
92
93
94
95
96
97
98
99
100
101
  	int ret;
  	char tmpbuf[len + 1];
  	char regbuf[regsize + 1];
  
  	/* since tmpbuf is allocated on the stack, warn the callers if they
  	 * try to abuse this function */
  	WARN_ON(len > 63);
  
  	/* +2 for ': ' and + 1 for '
  ' */
  	if (wordsize + regsize + 2 + 1 != len)
  		return -EINVAL;
25032c119   Mark Brown   ASoC: Trivial for...
102
  	ret = snd_soc_read(codec, reg);
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
  	if (ret < 0) {
  		memset(regbuf, 'X', regsize);
  		regbuf[regsize] = '\0';
  	} else {
  		snprintf(regbuf, regsize + 1, "%.*x", regsize, ret);
  	}
  
  	/* prepare the buffer */
  	snprintf(tmpbuf, len + 1, "%.*x: %s
  ", wordsize, reg, regbuf);
  	/* copy it back to the caller without the '\0' */
  	memcpy(buf, tmpbuf, len);
  
  	return 0;
  }
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
118
  /* codec register dump */
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
119
120
  static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf,
  				  size_t count, loff_t pos)
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
121
  {
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
122
  	int i, step = 1;
2bc9a81e2   Dimitris Papastamos   ASoC: soc-core: E...
123
  	int wordsize, regsize;
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
124
125
126
  	int len;
  	size_t total = 0;
  	loff_t p = 0;
2bc9a81e2   Dimitris Papastamos   ASoC: soc-core: E...
127

00b317a41   Stephen Warren   ASoC: format_regi...
128
129
  	wordsize = min_bytes_needed(codec->driver->reg_cache_size) * 2;
  	regsize = codec->driver->reg_word_size * 2;
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
130

13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
131
  	len = wordsize + regsize + 2 + 1;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
132
  	if (!codec->driver->reg_cache_size)
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
133
  		return 0;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
134
135
  	if (codec->driver->reg_cache_step)
  		step = codec->driver->reg_cache_step;
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
136

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
137
  	for (i = 0; i < codec->driver->reg_cache_size; i += step) {
b92d150ba   Lars-Peter Clausen   ASoC: soc_codec_r...
138
  		if (!snd_soc_codec_readable_register(codec, i))
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
139
  			continue;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
140
141
  		if (codec->driver->display_register) {
  			count += codec->driver->display_register(codec, buf + count,
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
142
  							 PAGE_SIZE - count, i);
5164d74d7   Mark Brown   ASoC: Handle read...
143
  		} else {
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
144
145
146
147
148
149
150
151
152
  			/* only support larger than PAGE_SIZE bytes debugfs
  			 * entries for the default case */
  			if (p >= pos) {
  				if (total + len >= count - 1)
  					break;
  				format_register_str(codec, i, buf + total, len);
  				total += len;
  			}
  			p += len;
5164d74d7   Mark Brown   ASoC: Handle read...
153
  		}
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
154
  	}
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
155
  	total = min(total, count - 1);
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
156

13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
157
  	return total;
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
158
  }
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
159

2624d5fa6   Mark Brown   ASoC: Move sysfs ...
160
161
162
  static ssize_t codec_reg_show(struct device *dev,
  	struct device_attribute *attr, char *buf)
  {
36ae1a96c   Mark Brown   ASoC: Dynamically...
163
  	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
164

13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
165
  	return soc_codec_reg_show(rtd->codec, buf, PAGE_SIZE, 0);
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
166
167
168
  }
  
  static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
dbe21408b   Mark Brown   ASoC: Make pmdown...
169
170
171
  static ssize_t pmdown_time_show(struct device *dev,
  				struct device_attribute *attr, char *buf)
  {
36ae1a96c   Mark Brown   ASoC: Dynamically...
172
  	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
dbe21408b   Mark Brown   ASoC: Make pmdown...
173

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
174
175
  	return sprintf(buf, "%ld
  ", rtd->pmdown_time);
dbe21408b   Mark Brown   ASoC: Make pmdown...
176
177
178
179
180
181
  }
  
  static ssize_t pmdown_time_set(struct device *dev,
  			       struct device_attribute *attr,
  			       const char *buf, size_t count)
  {
36ae1a96c   Mark Brown   ASoC: Dynamically...
182
  	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
c593b520c   Mark Brown   ASoC: Check retur...
183
  	int ret;
dbe21408b   Mark Brown   ASoC: Make pmdown...
184

c593b520c   Mark Brown   ASoC: Check retur...
185
186
187
  	ret = strict_strtol(buf, 10, &rtd->pmdown_time);
  	if (ret)
  		return ret;
dbe21408b   Mark Brown   ASoC: Make pmdown...
188
189
190
191
192
  
  	return count;
  }
  
  static DEVICE_ATTR(pmdown_time, 0644, pmdown_time_show, pmdown_time_set);
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
193
194
195
196
197
198
199
200
  #ifdef CONFIG_DEBUG_FS
  static int codec_reg_open_file(struct inode *inode, struct file *file)
  {
  	file->private_data = inode->i_private;
  	return 0;
  }
  
  static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf,
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
201
  				   size_t count, loff_t *ppos)
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
202
203
204
  {
  	ssize_t ret;
  	struct snd_soc_codec *codec = file->private_data;
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
205
206
207
208
209
210
  	char *buf;
  
  	if (*ppos < 0 || !count)
  		return -EINVAL;
  
  	buf = kmalloc(count, GFP_KERNEL);
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
211
212
  	if (!buf)
  		return -ENOMEM;
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
213
214
215
216
217
218
219
220
221
  
  	ret = soc_codec_reg_show(codec, buf, count, *ppos);
  	if (ret >= 0) {
  		if (copy_to_user(user_buf, buf, ret)) {
  			kfree(buf);
  			return -EFAULT;
  		}
  		*ppos += ret;
  	}
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
222
223
224
225
226
227
228
229
  	kfree(buf);
  	return ret;
  }
  
  static ssize_t codec_reg_write_file(struct file *file,
  		const char __user *user_buf, size_t count, loff_t *ppos)
  {
  	char buf[32];
34e268d87   Stephen Boyd   ASoC: Silence DEB...
230
  	size_t buf_size;
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
231
232
  	char *start = buf;
  	unsigned long reg, value;
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
233
234
235
236
237
238
  	struct snd_soc_codec *codec = file->private_data;
  
  	buf_size = min(count, (sizeof(buf)-1));
  	if (copy_from_user(buf, user_buf, buf_size))
  		return -EFAULT;
  	buf[buf_size] = 0;
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
239
240
241
242
  
  	while (*start == ' ')
  		start++;
  	reg = simple_strtoul(start, &start, 16);
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
243
244
245
246
  	while (*start == ' ')
  		start++;
  	if (strict_strtoul(start, 16, &value))
  		return -EINVAL;
0d51a9cbb   Mark Brown   ASoC: Taint the k...
247
248
249
  
  	/* Userspace has been fiddling around behind the kernel's back */
  	add_taint(TAINT_USER);
e4f078d8c   Dimitris Papastamos   ASoC: soc-core: F...
250
  	snd_soc_write(codec, reg, value);
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
251
252
253
254
255
256
257
  	return buf_size;
  }
  
  static const struct file_operations codec_reg_fops = {
  	.open = codec_reg_open_file,
  	.read = codec_reg_read_file,
  	.write = codec_reg_write_file,
6038f373a   Arnd Bergmann   llseek: automatic...
258
  	.llseek = default_llseek,
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
259
260
261
262
  };
  
  static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
  {
d6ce4cf39   Jarkko Nikula   ASoC: Move codec ...
263
264
265
266
  	struct dentry *debugfs_card_root = codec->card->debugfs_card_root;
  
  	codec->debugfs_codec_root = debugfs_create_dir(codec->name,
  						       debugfs_card_root);
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
267
268
269
270
271
272
  	if (!codec->debugfs_codec_root) {
  		printk(KERN_WARNING
  		       "ASoC: Failed to create codec debugfs directory
  ");
  		return;
  	}
aaee8ef14   Mark Brown   ASoC: Make cache ...
273
274
275
276
  	debugfs_create_bool("cache_sync", 0444, codec->debugfs_codec_root,
  			    &codec->cache_sync);
  	debugfs_create_bool("cache_only", 0444, codec->debugfs_codec_root,
  			    &codec->cache_only);
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
277
278
279
280
281
282
283
  	codec->debugfs_reg = debugfs_create_file("codec_reg", 0644,
  						 codec->debugfs_codec_root,
  						 codec, &codec_reg_fops);
  	if (!codec->debugfs_reg)
  		printk(KERN_WARNING
  		       "ASoC: Failed to create codec register debugfs file
  ");
8eecaf624   Lars-Peter Clausen   ASoC: Move DAPM d...
284
  	snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root);
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
285
286
287
288
289
290
  }
  
  static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
  {
  	debugfs_remove_recursive(codec->debugfs_codec_root);
  }
c3c5a19a5   Mark Brown   ASoC: Add debugfs...
291
292
293
294
  static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
  				    size_t count, loff_t *ppos)
  {
  	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
2b194f9db   Mark Brown   ASoC: Check list ...
295
  	ssize_t len, ret = 0;
c3c5a19a5   Mark Brown   ASoC: Add debugfs...
296
297
298
299
  	struct snd_soc_codec *codec;
  
  	if (!buf)
  		return -ENOMEM;
2b194f9db   Mark Brown   ASoC: Check list ...
300
301
302
303
304
305
306
307
308
309
310
  	list_for_each_entry(codec, &codec_list, list) {
  		len = snprintf(buf + ret, PAGE_SIZE - ret, "%s
  ",
  			       codec->name);
  		if (len >= 0)
  			ret += len;
  		if (ret > PAGE_SIZE) {
  			ret = PAGE_SIZE;
  			break;
  		}
  	}
c3c5a19a5   Mark Brown   ASoC: Add debugfs...
311
312
313
314
315
316
317
318
319
320
321
322
323
  
  	if (ret >= 0)
  		ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
  
  	kfree(buf);
  
  	return ret;
  }
  
  static const struct file_operations codec_list_fops = {
  	.read = codec_list_read_file,
  	.llseek = default_llseek,/* read accesses f_pos */
  };
f32087803   Mark Brown   ASoC: Add DAI lis...
324
325
326
327
  static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
  				  size_t count, loff_t *ppos)
  {
  	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
2b194f9db   Mark Brown   ASoC: Check list ...
328
  	ssize_t len, ret = 0;
f32087803   Mark Brown   ASoC: Add DAI lis...
329
330
331
332
  	struct snd_soc_dai *dai;
  
  	if (!buf)
  		return -ENOMEM;
2b194f9db   Mark Brown   ASoC: Check list ...
333
334
335
336
337
338
339
340
341
342
  	list_for_each_entry(dai, &dai_list, list) {
  		len = snprintf(buf + ret, PAGE_SIZE - ret, "%s
  ", dai->name);
  		if (len >= 0)
  			ret += len;
  		if (ret > PAGE_SIZE) {
  			ret = PAGE_SIZE;
  			break;
  		}
  	}
f32087803   Mark Brown   ASoC: Add DAI lis...
343

2b194f9db   Mark Brown   ASoC: Check list ...
344
  	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
f32087803   Mark Brown   ASoC: Add DAI lis...
345
346
347
348
349
350
351
352
353
354
  
  	kfree(buf);
  
  	return ret;
  }
  
  static const struct file_operations dai_list_fops = {
  	.read = dai_list_read_file,
  	.llseek = default_llseek,/* read accesses f_pos */
  };
19c7ac27a   Mark Brown   ASoC: Add platfor...
355
356
357
358
359
  static ssize_t platform_list_read_file(struct file *file,
  				       char __user *user_buf,
  				       size_t count, loff_t *ppos)
  {
  	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
2b194f9db   Mark Brown   ASoC: Check list ...
360
  	ssize_t len, ret = 0;
19c7ac27a   Mark Brown   ASoC: Add platfor...
361
362
363
364
  	struct snd_soc_platform *platform;
  
  	if (!buf)
  		return -ENOMEM;
2b194f9db   Mark Brown   ASoC: Check list ...
365
366
367
368
369
370
371
372
373
374
375
  	list_for_each_entry(platform, &platform_list, list) {
  		len = snprintf(buf + ret, PAGE_SIZE - ret, "%s
  ",
  			       platform->name);
  		if (len >= 0)
  			ret += len;
  		if (ret > PAGE_SIZE) {
  			ret = PAGE_SIZE;
  			break;
  		}
  	}
19c7ac27a   Mark Brown   ASoC: Add platfor...
376

2b194f9db   Mark Brown   ASoC: Check list ...
377
  	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
19c7ac27a   Mark Brown   ASoC: Add platfor...
378
379
380
381
382
383
384
385
386
387
  
  	kfree(buf);
  
  	return ret;
  }
  
  static const struct file_operations platform_list_fops = {
  	.read = platform_list_read_file,
  	.llseek = default_llseek,/* read accesses f_pos */
  };
a60521549   Jarkko Nikula   ASoC: Add sound c...
388
389
390
  static void soc_init_card_debugfs(struct snd_soc_card *card)
  {
  	card->debugfs_card_root = debugfs_create_dir(card->name,
8a9dab1a5   Mark Brown   ASoC: Update name...
391
  						     snd_soc_debugfs_root);
3a45b8672   Jarkko Nikula   ASoC: Move pop ti...
392
  	if (!card->debugfs_card_root) {
a60521549   Jarkko Nikula   ASoC: Add sound c...
393
  		dev_warn(card->dev,
7c08be84f   Lothar Waßmann   ASoC: Fix an obvi...
394
395
  			 "ASoC: Failed to create card debugfs directory
  ");
3a45b8672   Jarkko Nikula   ASoC: Move pop ti...
396
397
398
399
400
401
402
403
404
405
  		return;
  	}
  
  	card->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0644,
  						    card->debugfs_card_root,
  						    &card->pop_time);
  	if (!card->debugfs_pop_time)
  		dev_warn(card->dev,
  		       "Failed to create pop time debugfs file
  ");
a60521549   Jarkko Nikula   ASoC: Add sound c...
406
407
408
409
410
411
  }
  
  static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
  {
  	debugfs_remove_recursive(card->debugfs_card_root);
  }
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
412
413
414
415
416
417
418
419
420
  #else
  
  static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec)
  {
  }
  
  static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
  {
  }
b95fccbc0   Axel Lin   ASoC: Fix compile...
421
422
423
424
425
426
427
428
  
  static inline void soc_init_card_debugfs(struct snd_soc_card *card)
  {
  }
  
  static inline void soc_cleanup_card_debugfs(struct snd_soc_card *card)
  {
  }
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
429
  #endif
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
  #ifdef CONFIG_SND_SOC_AC97_BUS
  /* unregister ac97 codec */
  static int soc_ac97_dev_unregister(struct snd_soc_codec *codec)
  {
  	if (codec->ac97->dev.bus)
  		device_unregister(&codec->ac97->dev);
  	return 0;
  }
  
  /* stop no dev release warning */
  static void soc_ac97_device_release(struct device *dev){}
  
  /* register ac97 codec to bus */
  static int soc_ac97_dev_register(struct snd_soc_codec *codec)
  {
  	int err;
  
  	codec->ac97->dev.bus = &ac97_bus_type;
4ac5c61f0   Mark Brown   ASoC: Set parent ...
448
  	codec->ac97->dev.parent = codec->card->dev;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
449
  	codec->ac97->dev.release = soc_ac97_device_release;
bb072bf09   Kay Sievers   sound: struct dev...
450
  	dev_set_name(&codec->ac97->dev, "%d-%d:%s",
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
451
  		     codec->card->snd_card->number, 0, codec->name);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
452
453
454
455
456
457
458
459
460
461
  	err = device_register(&codec->ac97->dev);
  	if (err < 0) {
  		snd_printk(KERN_ERR "Can't register ac97 bus
  ");
  		codec->ac97->dev.bus = NULL;
  		return err;
  	}
  	return 0;
  }
  #endif
6f8ab4ac2   Mark Brown   ASoC: Export card...
462
  #ifdef CONFIG_PM_SLEEP
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
463
  /* powers down audio subsystem for suspend */
6f8ab4ac2   Mark Brown   ASoC: Export card...
464
  int snd_soc_suspend(struct device *dev)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
465
  {
6f8ab4ac2   Mark Brown   ASoC: Export card...
466
  	struct snd_soc_card *card = dev_get_drvdata(dev);
2eea392d0   Jarkko Nikula   ASoC: Add support...
467
  	struct snd_soc_codec *codec;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
468
  	int i;
e3509ff0f   Daniel Mack   ASoC: fix NULL po...
469
470
471
  	/* If the initialization of this soc device failed, there is no codec
  	 * associated with it. Just bail out in this case.
  	 */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
472
  	if (list_empty(&card->codec_dev_list))
e3509ff0f   Daniel Mack   ASoC: fix NULL po...
473
  		return 0;
6ed259788   Andy Green   ALSA: ASoC: Don't...
474
475
476
  	/* Due to the resume being scheduled into a workqueue we could
  	* suspend before that's finished - wait for it to complete.
  	 */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
477
478
479
  	snd_power_lock(card->snd_card);
  	snd_power_wait(card->snd_card, SNDRV_CTL_POWER_D0);
  	snd_power_unlock(card->snd_card);
6ed259788   Andy Green   ALSA: ASoC: Don't...
480
481
  
  	/* we're going to block userspace touching us until resume completes */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
482
  	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
6ed259788   Andy Green   ALSA: ASoC: Don't...
483

a00f90f93   Mark Brown   ASoC: Apostrophe ...
484
  	/* mute any active DACs */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
485
486
487
  	for (i = 0; i < card->num_rtd; i++) {
  		struct snd_soc_dai *dai = card->rtd[i].codec_dai;
  		struct snd_soc_dai_driver *drv = dai->driver;
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
488

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
489
  		if (card->rtd[i].dai_link->ignore_suspend)
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
490
  			continue;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
491
492
  		if (drv->ops->digital_mute && dai->playback_active)
  			drv->ops->digital_mute(dai, 1);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
493
  	}
4ccab3e72   Liam Girdwood   [ALSA] soc - Ensu...
494
  	/* suspend all pcms */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
495
496
  	for (i = 0; i < card->num_rtd; i++) {
  		if (card->rtd[i].dai_link->ignore_suspend)
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
497
  			continue;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
498
  		snd_pcm_suspend_all(card->rtd[i].pcm);
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
499
  	}
4ccab3e72   Liam Girdwood   [ALSA] soc - Ensu...
500

875065491   Mark Brown   ASoC: Rename snd_...
501
  	if (card->suspend_pre)
70b2ac126   Mark Brown   ASoC: Use card ra...
502
  		card->suspend_pre(card);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
503

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
504
505
506
  	for (i = 0; i < card->num_rtd; i++) {
  		struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
  		struct snd_soc_platform *platform = card->rtd[i].platform;
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
507

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
508
  		if (card->rtd[i].dai_link->ignore_suspend)
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
509
  			continue;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
510
511
512
513
514
515
  		if (cpu_dai->driver->suspend && !cpu_dai->driver->ac97_control)
  			cpu_dai->driver->suspend(cpu_dai);
  		if (platform->driver->suspend && !platform->suspended) {
  			platform->driver->suspend(cpu_dai);
  			platform->suspended = 1;
  		}
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
516
517
518
  	}
  
  	/* close any waiting streams and save state */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
519
  	for (i = 0; i < card->num_rtd; i++) {
5b84ba26a   Tejun Heo   sound: don't use ...
520
  		flush_delayed_work_sync(&card->rtd[i].delayed_work);
ce6120cca   Liam Girdwood   ASoC: Decouple DA...
521
  		card->rtd[i].codec->dapm.suspend_bias_level = card->rtd[i].codec->dapm.bias_level;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
522
  	}
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
523

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
524
525
  	for (i = 0; i < card->num_rtd; i++) {
  		struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver;
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
526

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
527
  		if (card->rtd[i].dai_link->ignore_suspend)
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
528
  			continue;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
529
530
  		if (driver->playback.stream_name != NULL)
  			snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
531
  				SND_SOC_DAPM_STREAM_SUSPEND);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
532
533
534
  
  		if (driver->capture.stream_name != NULL)
  			snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
535
536
  				SND_SOC_DAPM_STREAM_SUSPEND);
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
537
  	/* suspend all CODECs */
2eea392d0   Jarkko Nikula   ASoC: Add support...
538
  	list_for_each_entry(codec, &card->codec_dev_list, card_list) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
539
540
541
  		/* If there are paths active then the CODEC will be held with
  		 * bias _ON and should not be suspended. */
  		if (!codec->suspended && codec->driver->suspend) {
ce6120cca   Liam Girdwood   ASoC: Decouple DA...
542
  			switch (codec->dapm.bias_level) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
543
544
  			case SND_SOC_BIAS_STANDBY:
  			case SND_SOC_BIAS_OFF:
84b315ee8   Lars-Peter Clausen   ASoC: Drop unused...
545
  				codec->driver->suspend(codec);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
546
  				codec->suspended = 1;
7be4ba24a   Mark Brown   ASoC: Mark cache ...
547
  				codec->cache_sync = 1;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
548
549
550
551
552
553
  				break;
  			default:
  				dev_dbg(codec->dev, "CODEC is on over suspend
  ");
  				break;
  			}
1547aba99   Mark Brown   ASoC: Support lea...
554
555
  		}
  	}
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
556

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
557
558
  	for (i = 0; i < card->num_rtd; i++) {
  		struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
559

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
560
  		if (card->rtd[i].dai_link->ignore_suspend)
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
561
  			continue;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
562
563
  		if (cpu_dai->driver->suspend && cpu_dai->driver->ac97_control)
  			cpu_dai->driver->suspend(cpu_dai);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
564
  	}
875065491   Mark Brown   ASoC: Rename snd_...
565
  	if (card->suspend_post)
70b2ac126   Mark Brown   ASoC: Use card ra...
566
  		card->suspend_post(card);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
567
568
569
  
  	return 0;
  }
6f8ab4ac2   Mark Brown   ASoC: Export card...
570
  EXPORT_SYMBOL_GPL(snd_soc_suspend);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
571

6ed259788   Andy Green   ALSA: ASoC: Don't...
572
573
574
575
  /* deferred resume work, so resume can complete before we finished
   * setting our codec back up, which can be very slow on I2C
   */
  static void soc_resume_deferred(struct work_struct *work)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
576
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
577
578
  	struct snd_soc_card *card =
  			container_of(work, struct snd_soc_card, deferred_resume_work);
2eea392d0   Jarkko Nikula   ASoC: Add support...
579
  	struct snd_soc_codec *codec;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
580
  	int i;
6ed259788   Andy Green   ALSA: ASoC: Don't...
581
582
583
  	/* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
  	 * so userspace apps are blocked from touching us
  	 */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
584
585
  	dev_dbg(card->dev, "starting resume work
  ");
6ed259788   Andy Green   ALSA: ASoC: Don't...
586

9949788b7   Mark Brown   ASoC: Refactor DA...
587
  	/* Bring us up into D2 so that DAPM starts enabling things */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
588
  	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D2);
9949788b7   Mark Brown   ASoC: Refactor DA...
589

875065491   Mark Brown   ASoC: Rename snd_...
590
  	if (card->resume_pre)
70b2ac126   Mark Brown   ASoC: Use card ra...
591
  		card->resume_pre(card);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
592

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
593
594
595
  	/* resume AC97 DAIs */
  	for (i = 0; i < card->num_rtd; i++) {
  		struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
596

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
597
  		if (card->rtd[i].dai_link->ignore_suspend)
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
598
  			continue;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
599
600
601
  		if (cpu_dai->driver->resume && cpu_dai->driver->ac97_control)
  			cpu_dai->driver->resume(cpu_dai);
  	}
2eea392d0   Jarkko Nikula   ASoC: Add support...
602
  	list_for_each_entry(codec, &card->codec_dev_list, card_list) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
603
604
605
606
607
  		/* If the CODEC was idle over suspend then it will have been
  		 * left with bias OFF or STANDBY and suspended so we must now
  		 * resume.  Otherwise the suspend was suppressed.
  		 */
  		if (codec->driver->resume && codec->suspended) {
ce6120cca   Liam Girdwood   ASoC: Decouple DA...
608
  			switch (codec->dapm.bias_level) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
609
610
611
612
613
614
615
616
617
618
  			case SND_SOC_BIAS_STANDBY:
  			case SND_SOC_BIAS_OFF:
  				codec->driver->resume(codec);
  				codec->suspended = 0;
  				break;
  			default:
  				dev_dbg(codec->dev, "CODEC was on over suspend
  ");
  				break;
  			}
1547aba99   Mark Brown   ASoC: Support lea...
619
620
  		}
  	}
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
621

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
622
623
  	for (i = 0; i < card->num_rtd; i++) {
  		struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver;
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
624

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
625
  		if (card->rtd[i].dai_link->ignore_suspend)
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
626
  			continue;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
627
628
  		if (driver->playback.stream_name != NULL)
  			snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
629
  				SND_SOC_DAPM_STREAM_RESUME);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
630
631
632
  
  		if (driver->capture.stream_name != NULL)
  			snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
633
634
  				SND_SOC_DAPM_STREAM_RESUME);
  	}
3ff3f64ba   Mark Brown   [ALSA] ASoC: core...
635
  	/* unmute any active DACs */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
636
637
638
  	for (i = 0; i < card->num_rtd; i++) {
  		struct snd_soc_dai *dai = card->rtd[i].codec_dai;
  		struct snd_soc_dai_driver *drv = dai->driver;
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
639

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
640
  		if (card->rtd[i].dai_link->ignore_suspend)
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
641
  			continue;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
642
643
  		if (drv->ops->digital_mute && dai->playback_active)
  			drv->ops->digital_mute(dai, 0);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
644
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
645
646
647
  	for (i = 0; i < card->num_rtd; i++) {
  		struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
  		struct snd_soc_platform *platform = card->rtd[i].platform;
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
648

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
649
  		if (card->rtd[i].dai_link->ignore_suspend)
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
650
  			continue;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
651
652
653
654
655
656
  		if (cpu_dai->driver->resume && !cpu_dai->driver->ac97_control)
  			cpu_dai->driver->resume(cpu_dai);
  		if (platform->driver->resume && platform->suspended) {
  			platform->driver->resume(cpu_dai);
  			platform->suspended = 0;
  		}
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
657
  	}
875065491   Mark Brown   ASoC: Rename snd_...
658
  	if (card->resume_post)
70b2ac126   Mark Brown   ASoC: Use card ra...
659
  		card->resume_post(card);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
660

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
661
662
  	dev_dbg(card->dev, "resume work completed
  ");
6ed259788   Andy Green   ALSA: ASoC: Don't...
663
664
  
  	/* userspace can access us now we are back as we were before */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
665
  	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0);
6ed259788   Andy Green   ALSA: ASoC: Don't...
666
667
668
  }
  
  /* powers up audio subsystem after a suspend */
6f8ab4ac2   Mark Brown   ASoC: Export card...
669
  int snd_soc_resume(struct device *dev)
6ed259788   Andy Green   ALSA: ASoC: Don't...
670
  {
6f8ab4ac2   Mark Brown   ASoC: Export card...
671
  	struct snd_soc_card *card = dev_get_drvdata(dev);
82e14e8bd   Stephen Warren   ASoC: core: Don't...
672
  	int i, ac97_control = 0;
b9dd94a87   Peter Ujfalusi   ASoC: core: On re...
673

5ff1ddf22   Eric Miao   ASoC: skip resume...
674
675
676
677
678
  	/* If the initialization of this soc device failed, there is no codec
  	 * associated with it. Just bail out in this case.
  	 */
  	if (list_empty(&card->codec_dev_list))
  		return 0;
64ab9baa0   Mark Brown   ASoC: Don't defer...
679
680
681
682
683
  	/* AC97 devices might have other drivers hanging off them so
  	 * need to resume immediately.  Other drivers don't have that
  	 * problem and may take a substantial amount of time to resume
  	 * due to I/O costs and anti-pop so handle them out of line.
  	 */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
684
685
  	for (i = 0; i < card->num_rtd; i++) {
  		struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
82e14e8bd   Stephen Warren   ASoC: core: Don't...
686
687
688
689
690
691
692
693
694
695
696
697
  		ac97_control |= cpu_dai->driver->ac97_control;
  	}
  	if (ac97_control) {
  		dev_dbg(dev, "Resuming AC97 immediately
  ");
  		soc_resume_deferred(&card->deferred_resume_work);
  	} else {
  		dev_dbg(dev, "Scheduling resume work
  ");
  		if (!schedule_work(&card->deferred_resume_work))
  			dev_err(dev, "resume work item may be lost
  ");
64ab9baa0   Mark Brown   ASoC: Don't defer...
698
  	}
6ed259788   Andy Green   ALSA: ASoC: Don't...
699

db2a41655   Frank Mandarino   [ALSA] ASoC: core...
700
701
  	return 0;
  }
6f8ab4ac2   Mark Brown   ASoC: Export card...
702
  EXPORT_SYMBOL_GPL(snd_soc_resume);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
703
  #else
6f8ab4ac2   Mark Brown   ASoC: Export card...
704
705
  #define snd_soc_suspend NULL
  #define snd_soc_resume NULL
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
706
  #endif
85e7652d8   Lars-Peter Clausen   ASoC: Constify sn...
707
  static const struct snd_soc_dai_ops null_dai_ops = {
02a06d304   Barry Song   ASoC: Fix possibl...
708
  };
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
709
  static int soc_bind_dai_link(struct snd_soc_card *card, int num)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
710
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
711
712
  	struct snd_soc_dai_link *dai_link = &card->dai_link[num];
  	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
fe3e78e07   Mark Brown   ASoC: Factor out ...
713
  	struct snd_soc_codec *codec;
435c5e258   Mark Brown   ASoC: Initial fra...
714
  	struct snd_soc_platform *platform;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
715
  	struct snd_soc_dai *codec_dai, *cpu_dai;
848dd8bee   Mark Brown   ASoC: Add more na...
716
  	const char *platform_name;
435c5e258   Mark Brown   ASoC: Initial fra...
717

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
718
719
720
721
  	if (rtd->complete)
  		return 1;
  	dev_dbg(card->dev, "binding %s at idx %d
  ", dai_link->name, num);
435c5e258   Mark Brown   ASoC: Initial fra...
722

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
723
724
725
726
727
728
  	/* do we already have the CPU DAI for this link ? */
  	if (rtd->cpu_dai) {
  		goto find_codec;
  	}
  	/* no, then find CPU DAI from registered DAIs*/
  	list_for_each_entry(cpu_dai, &dai_list, list) {
5a5049637   Stephen Warren   ASoC: Allow DAI l...
729
730
731
732
733
734
735
  		if (dai_link->cpu_dai_of_node) {
  			if (cpu_dai->dev->of_node != dai_link->cpu_dai_of_node)
  				continue;
  		} else {
  			if (strcmp(cpu_dai->name, dai_link->cpu_dai_name))
  				continue;
  		}
2610ab776   Stephen Warren   ASoC: Refactor so...
736
737
738
  
  		rtd->cpu_dai = cpu_dai;
  		goto find_codec;
435c5e258   Mark Brown   ASoC: Initial fra...
739
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
740
741
742
  	dev_dbg(card->dev, "CPU DAI %s not registered
  ",
  			dai_link->cpu_dai_name);
6308419a1   Mark Brown   ASoC: Push workqu...
743

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
744
745
746
747
748
749
750
751
  find_codec:
  	/* do we already have the CODEC for this link ? */
  	if (rtd->codec) {
  		goto find_platform;
  	}
  
  	/* no, then find CODEC from registered CODECs*/
  	list_for_each_entry(codec, &codec_list, list) {
5a5049637   Stephen Warren   ASoC: Allow DAI l...
752
753
754
755
756
757
758
  		if (dai_link->codec_of_node) {
  			if (codec->dev->of_node != dai_link->codec_of_node)
  				continue;
  		} else {
  			if (strcmp(codec->name, dai_link->codec_name))
  				continue;
  		}
2610ab776   Stephen Warren   ASoC: Refactor so...
759
760
761
762
763
764
765
766
767
768
769
  
  		rtd->codec = codec;
  
  		/*
  		 * CODEC found, so find CODEC DAI from registered DAIs from
  		 * this CODEC
  		 */
  		list_for_each_entry(codec_dai, &dai_list, list) {
  			if (codec->dev == codec_dai->dev &&
  				!strcmp(codec_dai->name,
  					dai_link->codec_dai_name)) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
770

2610ab776   Stephen Warren   ASoC: Refactor so...
771
772
773
  				rtd->codec_dai = codec_dai;
  				goto find_platform;
  			}
435c5e258   Mark Brown   ASoC: Initial fra...
774
  		}
2610ab776   Stephen Warren   ASoC: Refactor so...
775
776
777
778
779
  		dev_dbg(card->dev, "CODEC DAI %s not registered
  ",
  				dai_link->codec_dai_name);
  
  		goto find_platform;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
780
781
782
783
  	}
  	dev_dbg(card->dev, "CODEC %s not registered
  ",
  			dai_link->codec_name);
6b05eda63   Mark Brown   ASoC: Wait for no...
784

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
785
  find_platform:
848dd8bee   Mark Brown   ASoC: Add more na...
786
787
  	/* do we need a platform? */
  	if (rtd->platform)
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
788
  		goto out;
848dd8bee   Mark Brown   ASoC: Add more na...
789
790
791
  
  	/* if there's no platform we match on the empty platform */
  	platform_name = dai_link->platform_name;
5a5049637   Stephen Warren   ASoC: Allow DAI l...
792
  	if (!platform_name && !dai_link->platform_of_node)
848dd8bee   Mark Brown   ASoC: Add more na...
793
794
795
  		platform_name = "snd-soc-dummy";
  
  	/* no, then find one from the set of registered platforms */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
796
  	list_for_each_entry(platform, &platform_list, list) {
5a5049637   Stephen Warren   ASoC: Allow DAI l...
797
798
799
800
801
802
803
804
  		if (dai_link->platform_of_node) {
  			if (platform->dev->of_node !=
  			    dai_link->platform_of_node)
  				continue;
  		} else {
  			if (strcmp(platform->name, platform_name))
  				continue;
  		}
2610ab776   Stephen Warren   ASoC: Refactor so...
805
806
807
  
  		rtd->platform = platform;
  		goto out;
02a06d304   Barry Song   ASoC: Fix possibl...
808
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
809
810
811
812
813
814
815
816
817
818
819
820
821
  	dev_dbg(card->dev, "platform %s not registered
  ",
  			dai_link->platform_name);
  	return 0;
  
  out:
  	/* mark rtd as complete if we found all 4 of our client devices */
  	if (rtd->codec && rtd->codec_dai && rtd->platform && rtd->cpu_dai) {
  		rtd->complete = 1;
  		card->num_rtd++;
  	}
  	return 1;
  }
589c3563f   Jarkko Nikula   ASoC: Merge commo...
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
  static void soc_remove_codec(struct snd_soc_codec *codec)
  {
  	int err;
  
  	if (codec->driver->remove) {
  		err = codec->driver->remove(codec);
  		if (err < 0)
  			dev_err(codec->dev,
  				"asoc: failed to remove %s: %d
  ",
  				codec->name, err);
  	}
  
  	/* Make sure all DAPM widgets are freed */
  	snd_soc_dapm_free(&codec->dapm);
  
  	soc_cleanup_codec_debugfs(codec);
  	codec->probed = 0;
  	list_del(&codec->card_list);
  	module_put(codec->dev->driver->owner);
  }
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
843
  static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order)
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
844
845
846
847
848
849
850
851
852
  {
  	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
  	struct snd_soc_codec *codec = rtd->codec;
  	struct snd_soc_platform *platform = rtd->platform;
  	struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
  	int err;
  
  	/* unregister the rtd device */
  	if (rtd->dev_registered) {
36ae1a96c   Mark Brown   ASoC: Dynamically...
853
854
855
  		device_remove_file(rtd->dev, &dev_attr_pmdown_time);
  		device_remove_file(rtd->dev, &dev_attr_codec_reg);
  		device_unregister(rtd->dev);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
856
857
858
859
  		rtd->dev_registered = 0;
  	}
  
  	/* remove the CODEC DAI */
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
860
861
  	if (codec_dai && codec_dai->probed &&
  			codec_dai->driver->remove_order == order) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
862
863
864
865
866
  		if (codec_dai->driver->remove) {
  			err = codec_dai->driver->remove(codec_dai);
  			if (err < 0)
  				printk(KERN_ERR "asoc: failed to remove %s
  ", codec_dai->name);
6b05eda63   Mark Brown   ASoC: Wait for no...
867
  		}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
868
869
870
  		codec_dai->probed = 0;
  		list_del(&codec_dai->card_list);
  	}
6b05eda63   Mark Brown   ASoC: Wait for no...
871

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
872
  	/* remove the platform */
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
873
874
  	if (platform && platform->probed &&
  			platform->driver->remove_order == order) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
875
876
877
878
879
880
881
882
883
884
  		if (platform->driver->remove) {
  			err = platform->driver->remove(platform);
  			if (err < 0)
  				printk(KERN_ERR "asoc: failed to remove %s
  ", platform->name);
  		}
  		platform->probed = 0;
  		list_del(&platform->card_list);
  		module_put(platform->dev->driver->owner);
  	}
435c5e258   Mark Brown   ASoC: Initial fra...
885

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
886
  	/* remove the CODEC */
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
887
888
  	if (codec && codec->probed &&
  			codec->driver->remove_order == order)
589c3563f   Jarkko Nikula   ASoC: Merge commo...
889
  		soc_remove_codec(codec);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
890

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
891
  	/* remove the cpu_dai */
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
892
893
  	if (cpu_dai && cpu_dai->probed &&
  			cpu_dai->driver->remove_order == order) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
894
895
896
897
898
  		if (cpu_dai->driver->remove) {
  			err = cpu_dai->driver->remove(cpu_dai);
  			if (err < 0)
  				printk(KERN_ERR "asoc: failed to remove %s
  ", cpu_dai->name);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
899
  		}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
900
901
902
  		cpu_dai->probed = 0;
  		list_del(&cpu_dai->card_list);
  		module_put(cpu_dai->dev->driver->owner);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
903
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
904
  }
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
905

0671fd8ef   Kuninori Morimoto   ASoC: Add soc_rem...
906
907
  static void soc_remove_dai_links(struct snd_soc_card *card)
  {
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
908
  	int dai, order;
0671fd8ef   Kuninori Morimoto   ASoC: Add soc_rem...
909

0168bf0d1   Liam Girdwood   ASoC: core - Allo...
910
911
912
913
914
  	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
  			order++) {
  		for (dai = 0; dai < card->num_rtd; dai++)
  			soc_remove_dai_link(card, dai, order);
  	}
0671fd8ef   Kuninori Morimoto   ASoC: Add soc_rem...
915
916
  	card->num_rtd = 0;
  }
ead9b9199   Jarkko Nikula   ASoC: Add optiona...
917
918
919
920
  static void soc_set_name_prefix(struct snd_soc_card *card,
  				struct snd_soc_codec *codec)
  {
  	int i;
ff819b835   Dimitris Papastamos   ASoC: soc-core: G...
921
  	if (card->codec_conf == NULL)
ead9b9199   Jarkko Nikula   ASoC: Add optiona...
922
  		return;
ff819b835   Dimitris Papastamos   ASoC: soc-core: G...
923
924
  	for (i = 0; i < card->num_configs; i++) {
  		struct snd_soc_codec_conf *map = &card->codec_conf[i];
ead9b9199   Jarkko Nikula   ASoC: Add optiona...
925
926
927
928
929
930
  		if (map->dev_name && !strcmp(codec->name, map->dev_name)) {
  			codec->name_prefix = map->name_prefix;
  			break;
  		}
  	}
  }
589c3563f   Jarkko Nikula   ASoC: Merge commo...
931
932
933
934
  static int soc_probe_codec(struct snd_soc_card *card,
  			   struct snd_soc_codec *codec)
  {
  	int ret = 0;
89b95ac09   Mark Brown   ASoC: Add DAPM wi...
935
  	const struct snd_soc_codec_driver *driver = codec->driver;
589c3563f   Jarkko Nikula   ASoC: Merge commo...
936
937
938
939
  
  	codec->card = card;
  	codec->dapm.card = card;
  	soc_set_name_prefix(card, codec);
70d29331a   Jarkko Nikula   ASoC: soc-core: I...
940
941
  	if (!try_module_get(codec->dev->driver->owner))
  		return -ENODEV;
d5d1e0bef   Lars-Peter Clausen   ASoC: Move DAPM w...
942
  	soc_init_codec_debugfs(codec);
77530150f   Lars-Peter Clausen   ASoC: Create code...
943
944
945
  	if (driver->dapm_widgets)
  		snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets,
  					  driver->num_dapm_widgets);
33c5f969b   Mark Brown   ASoC: Allow idle_...
946
  	codec->dapm.idle_bias_off = driver->idle_bias_off;
89b95ac09   Mark Brown   ASoC: Add DAPM wi...
947
948
  	if (driver->probe) {
  		ret = driver->probe(codec);
589c3563f   Jarkko Nikula   ASoC: Merge commo...
949
950
951
952
953
  		if (ret < 0) {
  			dev_err(codec->dev,
  				"asoc: failed to probe CODEC %s: %d
  ",
  				codec->name, ret);
70d29331a   Jarkko Nikula   ASoC: soc-core: I...
954
  			goto err_probe;
589c3563f   Jarkko Nikula   ASoC: Merge commo...
955
956
  		}
  	}
b7af1dafd   Mark Brown   ASoC: Add data ba...
957
958
959
  	if (driver->controls)
  		snd_soc_add_controls(codec, driver->controls,
  				     driver->num_controls);
89b95ac09   Mark Brown   ASoC: Add DAPM wi...
960
961
962
  	if (driver->dapm_routes)
  		snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes,
  					driver->num_dapm_routes);
589c3563f   Jarkko Nikula   ASoC: Merge commo...
963
964
965
  	/* mark codec as probed and add to card codec list */
  	codec->probed = 1;
  	list_add(&codec->card_list, &card->codec_dev_list);
7be31be88   Jarkko Nikula   ASoC: Extend DAPM...
966
  	list_add(&codec->dapm.list, &card->dapm_list);
589c3563f   Jarkko Nikula   ASoC: Merge commo...
967

70d29331a   Jarkko Nikula   ASoC: soc-core: I...
968
969
970
  	return 0;
  
  err_probe:
d5d1e0bef   Lars-Peter Clausen   ASoC: Move DAPM w...
971
  	soc_cleanup_codec_debugfs(codec);
70d29331a   Jarkko Nikula   ASoC: soc-core: I...
972
  	module_put(codec->dev->driver->owner);
589c3563f   Jarkko Nikula   ASoC: Merge commo...
973
974
  	return ret;
  }
956245e9c   Liam Girdwood   ASoC: core - Make...
975
976
977
978
979
980
981
  static int soc_probe_platform(struct snd_soc_card *card,
  			   struct snd_soc_platform *platform)
  {
  	int ret = 0;
  	const struct snd_soc_platform_driver *driver = platform->driver;
  
  	platform->card = card;
b79506413   Liam Girdwood   ASoC: core - Add ...
982
  	platform->dapm.card = card;
956245e9c   Liam Girdwood   ASoC: core - Make...
983
984
985
  
  	if (!try_module_get(platform->dev->driver->owner))
  		return -ENODEV;
cb2cf612f   Liam Girdwood   ASoC: core - Add ...
986
987
988
  	if (driver->dapm_widgets)
  		snd_soc_dapm_new_controls(&platform->dapm,
  			driver->dapm_widgets, driver->num_dapm_widgets);
956245e9c   Liam Girdwood   ASoC: core - Make...
989
990
991
992
993
994
995
996
997
998
  	if (driver->probe) {
  		ret = driver->probe(platform);
  		if (ret < 0) {
  			dev_err(platform->dev,
  				"asoc: failed to probe platform %s: %d
  ",
  				platform->name, ret);
  			goto err_probe;
  		}
  	}
cb2cf612f   Liam Girdwood   ASoC: core - Add ...
999
1000
1001
1002
1003
1004
  	if (driver->controls)
  		snd_soc_add_platform_controls(platform, driver->controls,
  				     driver->num_controls);
  	if (driver->dapm_routes)
  		snd_soc_dapm_add_routes(&platform->dapm, driver->dapm_routes,
  					driver->num_dapm_routes);
956245e9c   Liam Girdwood   ASoC: core - Make...
1005
1006
1007
  	/* mark platform as probed and add to card platform list */
  	platform->probed = 1;
  	list_add(&platform->card_list, &card->platform_dev_list);
b79506413   Liam Girdwood   ASoC: core - Add ...
1008
  	list_add(&platform->dapm.list, &card->dapm_list);
956245e9c   Liam Girdwood   ASoC: core - Make...
1009
1010
1011
1012
1013
1014
1015
1016
  
  	return 0;
  
  err_probe:
  	module_put(platform->dev->driver->owner);
  
  	return ret;
  }
36ae1a96c   Mark Brown   ASoC: Dynamically...
1017
1018
1019
1020
  static void rtd_release(struct device *dev)
  {
  	kfree(dev);
  }
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1021

589c3563f   Jarkko Nikula   ASoC: Merge commo...
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
  static int soc_post_component_init(struct snd_soc_card *card,
  				   struct snd_soc_codec *codec,
  				   int num, int dailess)
  {
  	struct snd_soc_dai_link *dai_link = NULL;
  	struct snd_soc_aux_dev *aux_dev = NULL;
  	struct snd_soc_pcm_runtime *rtd;
  	const char *temp, *name;
  	int ret = 0;
  
  	if (!dailess) {
  		dai_link = &card->dai_link[num];
  		rtd = &card->rtd[num];
  		name = dai_link->name;
  	} else {
  		aux_dev = &card->aux_dev[num];
  		rtd = &card->rtd_aux[num];
  		name = aux_dev->name;
  	}
0962bb217   Janusz Krzysztofik   ASoC: fill in snd...
1041
  	rtd->card = card;
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1042

4b1cfcb4f   Mark Brown   ASoC: Fix prefixi...
1043
1044
  	/* Make sure all DAPM widgets are instantiated */
  	snd_soc_dapm_new_widgets(&codec->dapm);
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
  	/* machine controls, routes and widgets are not prefixed */
  	temp = codec->name_prefix;
  	codec->name_prefix = NULL;
  
  	/* do machine specific initialization */
  	if (!dailess && dai_link->init)
  		ret = dai_link->init(rtd);
  	else if (dailess && aux_dev->init)
  		ret = aux_dev->init(&codec->dapm);
  	if (ret < 0) {
  		dev_err(card->dev, "asoc: failed to init %s: %d
  ", name, ret);
  		return ret;
  	}
  	codec->name_prefix = temp;
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1060
1061
  	/* register the rtd device */
  	rtd->codec = codec;
36ae1a96c   Mark Brown   ASoC: Dynamically...
1062
1063
1064
1065
1066
1067
1068
1069
1070
  
  	rtd->dev = kzalloc(sizeof(struct device), GFP_KERNEL);
  	if (!rtd->dev)
  		return -ENOMEM;
  	device_initialize(rtd->dev);
  	rtd->dev->parent = card->dev;
  	rtd->dev->release = rtd_release;
  	rtd->dev->init_name = name;
  	dev_set_drvdata(rtd->dev, rtd);
b8c0dab9b   Liam Girdwood   ASoC: core - PCM ...
1071
  	mutex_init(&rtd->pcm_mutex);
36ae1a96c   Mark Brown   ASoC: Dynamically...
1072
  	ret = device_add(rtd->dev);
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1073
1074
1075
1076
1077
1078
1079
1080
1081
  	if (ret < 0) {
  		dev_err(card->dev,
  			"asoc: failed to register runtime device: %d
  ", ret);
  		return ret;
  	}
  	rtd->dev_registered = 1;
  
  	/* add DAPM sysfs entries for this codec */
36ae1a96c   Mark Brown   ASoC: Dynamically...
1082
  	ret = snd_soc_dapm_sys_add(rtd->dev);
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1083
1084
1085
1086
1087
1088
1089
  	if (ret < 0)
  		dev_err(codec->dev,
  			"asoc: failed to add codec dapm sysfs entries: %d
  ",
  			ret);
  
  	/* add codec sysfs entries */
36ae1a96c   Mark Brown   ASoC: Dynamically...
1090
  	ret = device_create_file(rtd->dev, &dev_attr_codec_reg);
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1091
1092
1093
1094
1095
1096
1097
  	if (ret < 0)
  		dev_err(codec->dev,
  			"asoc: failed to add codec sysfs files: %d
  ", ret);
  
  	return 0;
  }
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
1098
  static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1099
1100
1101
1102
1103
1104
1105
  {
  	struct snd_soc_dai_link *dai_link = &card->dai_link[num];
  	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
  	struct snd_soc_codec *codec = rtd->codec;
  	struct snd_soc_platform *platform = rtd->platform;
  	struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
  	int ret;
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
1106
1107
1108
  	dev_dbg(card->dev, "probe %s dai link %d late %d
  ",
  			card->name, num, order);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1109
1110
1111
  
  	/* config components */
  	codec_dai->codec = codec;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1112
  	cpu_dai->platform = platform;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1113
1114
1115
1116
1117
1118
1119
  	codec_dai->card = card;
  	cpu_dai->card = card;
  
  	/* set default power off timeout */
  	rtd->pmdown_time = pmdown_time;
  
  	/* probe the cpu_dai */
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
1120
1121
  	if (!cpu_dai->probed &&
  			cpu_dai->driver->probe_order == order) {
61b61e3c5   Liam Girdwood   ASoC: core - fix ...
1122
1123
  		if (!try_module_get(cpu_dai->dev->driver->owner))
  			return -ENODEV;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1124
1125
1126
1127
1128
1129
  		if (cpu_dai->driver->probe) {
  			ret = cpu_dai->driver->probe(cpu_dai);
  			if (ret < 0) {
  				printk(KERN_ERR "asoc: failed to probe CPU DAI %s
  ",
  						cpu_dai->name);
61b61e3c5   Liam Girdwood   ASoC: core - fix ...
1130
  				module_put(cpu_dai->dev->driver->owner);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1131
1132
1133
1134
  				return ret;
  			}
  		}
  		cpu_dai->probed = 1;
1c8371d61   Wolfram Sang   ASoC: core: make ...
1135
  		/* mark cpu_dai as probed and add to card dai list */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1136
  		list_add(&cpu_dai->card_list, &card->dai_dev_list);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1137
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1138
  	/* probe the CODEC */
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
1139
1140
  	if (!codec->probed &&
  			codec->driver->probe_order == order) {
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1141
1142
1143
  		ret = soc_probe_codec(card, codec);
  		if (ret < 0)
  			return ret;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1144
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1145
  	/* probe the platform */
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
1146
1147
  	if (!platform->probed &&
  			platform->driver->probe_order == order) {
956245e9c   Liam Girdwood   ASoC: core - Make...
1148
1149
1150
  		ret = soc_probe_platform(card, platform);
  		if (ret < 0)
  			return ret;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1151
  	}
6ed259788   Andy Green   ALSA: ASoC: Don't...
1152

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1153
  	/* probe the CODEC DAI */
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
1154
  	if (!codec_dai->probed && codec_dai->driver->probe_order == order) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1155
1156
  		if (codec_dai->driver->probe) {
  			ret = codec_dai->driver->probe(codec_dai);
fe3e78e07   Mark Brown   ASoC: Factor out ...
1157
  			if (ret < 0) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1158
1159
1160
1161
  				printk(KERN_ERR "asoc: failed to probe CODEC DAI %s
  ",
  						codec_dai->name);
  				return ret;
fe3e78e07   Mark Brown   ASoC: Factor out ...
1162
1163
  			}
  		}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1164

1c8371d61   Wolfram Sang   ASoC: core: make ...
1165
  		/* mark codec_dai as probed and add to card dai list */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1166
1167
  		codec_dai->probed = 1;
  		list_add(&codec_dai->card_list, &card->dai_dev_list);
fe3e78e07   Mark Brown   ASoC: Factor out ...
1168
  	}
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
1169
1170
1171
  	/* complete DAI probe during last probe */
  	if (order != SND_SOC_COMP_ORDER_LAST)
  		return 0;
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1172
1173
  	ret = soc_post_component_init(card, codec, num, 0);
  	if (ret)
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1174
  		return ret;
fe3e78e07   Mark Brown   ASoC: Factor out ...
1175

36ae1a96c   Mark Brown   ASoC: Dynamically...
1176
  	ret = device_create_file(rtd->dev, &dev_attr_pmdown_time);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1177
1178
1179
  	if (ret < 0)
  		printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs
  ");
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
  	/* create the pcm */
  	ret = soc_new_pcm(rtd, num);
  	if (ret < 0) {
  		printk(KERN_ERR "asoc: can't create pcm %s
  ", dai_link->stream_name);
  		return ret;
  	}
  
  	/* add platform data for AC97 devices */
  	if (rtd->codec_dai->driver->ac97_control)
  		snd_ac97_dev_add_pdata(codec->ac97, rtd->cpu_dai->ac97_pdata);
  
  	return 0;
  }
fe3e78e07   Mark Brown   ASoC: Factor out ...
1194
  #ifdef CONFIG_SND_SOC_AC97_BUS
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1195
1196
1197
  static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
  {
  	int ret;
fe3e78e07   Mark Brown   ASoC: Factor out ...
1198
1199
1200
  	/* Only instantiate AC97 if not already done by the adaptor
  	 * for the generic AC97 subsystem.
  	 */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1201
  	if (rtd->codec_dai->driver->ac97_control && !rtd->codec->ac97_registered) {
0562f7882   Mika Westerberg   ASoC: don't regis...
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
  		/*
  		 * It is possible that the AC97 device is already registered to
  		 * the device subsystem. This happens when the device is created
  		 * via snd_ac97_mixer(). Currently only SoC codec that does so
  		 * is the generic AC97 glue but others migh emerge.
  		 *
  		 * In those cases we don't try to register the device again.
  		 */
  		if (!rtd->codec->ac97_created)
  			return 0;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1212
1213
  
  		ret = soc_ac97_dev_register(rtd->codec);
fe3e78e07   Mark Brown   ASoC: Factor out ...
1214
1215
1216
  		if (ret < 0) {
  			printk(KERN_ERR "asoc: AC97 device register failed
  ");
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1217
  			return ret;
fe3e78e07   Mark Brown   ASoC: Factor out ...
1218
  		}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1219
1220
  
  		rtd->codec->ac97_registered = 1;
fe3e78e07   Mark Brown   ASoC: Factor out ...
1221
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
  	return 0;
  }
  
  static void soc_unregister_ac97_dai_link(struct snd_soc_codec *codec)
  {
  	if (codec->ac97_registered) {
  		soc_ac97_dev_unregister(codec);
  		codec->ac97_registered = 0;
  	}
  }
fe3e78e07   Mark Brown   ASoC: Factor out ...
1232
  #endif
2eea392d0   Jarkko Nikula   ASoC: Add support...
1233
1234
1235
  static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
  {
  	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
2eea392d0   Jarkko Nikula   ASoC: Add support...
1236
  	struct snd_soc_codec *codec;
676ad98a0   Jarkko Nikula   ASoC: Don't oops ...
1237
  	int ret = -ENODEV;
2eea392d0   Jarkko Nikula   ASoC: Add support...
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
  
  	/* find CODEC from registered CODECs*/
  	list_for_each_entry(codec, &codec_list, list) {
  		if (!strcmp(codec->name, aux_dev->codec_name)) {
  			if (codec->probed) {
  				dev_err(codec->dev,
  					"asoc: codec already probed");
  				ret = -EBUSY;
  				goto out;
  			}
676ad98a0   Jarkko Nikula   ASoC: Don't oops ...
1248
  			goto found;
2eea392d0   Jarkko Nikula   ASoC: Add support...
1249
1250
  		}
  	}
676ad98a0   Jarkko Nikula   ASoC: Don't oops ...
1251
1252
1253
  	/* codec not found */
  	dev_err(card->dev, "asoc: codec %s not found", aux_dev->codec_name);
  	goto out;
2eea392d0   Jarkko Nikula   ASoC: Add support...
1254

676ad98a0   Jarkko Nikula   ASoC: Don't oops ...
1255
  found:
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1256
  	ret = soc_probe_codec(card, codec);
2eea392d0   Jarkko Nikula   ASoC: Add support...
1257
  	if (ret < 0)
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1258
  		return ret;
2eea392d0   Jarkko Nikula   ASoC: Add support...
1259

589c3563f   Jarkko Nikula   ASoC: Merge commo...
1260
  	ret = soc_post_component_init(card, codec, num, 1);
2eea392d0   Jarkko Nikula   ASoC: Add support...
1261
1262
1263
1264
1265
1266
1267
1268
1269
  
  out:
  	return ret;
  }
  
  static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
  {
  	struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
  	struct snd_soc_codec *codec = rtd->codec;
2eea392d0   Jarkko Nikula   ASoC: Add support...
1270
1271
1272
  
  	/* unregister the rtd device */
  	if (rtd->dev_registered) {
36ae1a96c   Mark Brown   ASoC: Dynamically...
1273
1274
  		device_remove_file(rtd->dev, &dev_attr_codec_reg);
  		device_del(rtd->dev);
2eea392d0   Jarkko Nikula   ASoC: Add support...
1275
1276
  		rtd->dev_registered = 0;
  	}
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1277
1278
  	if (codec && codec->probed)
  		soc_remove_codec(codec);
2eea392d0   Jarkko Nikula   ASoC: Add support...
1279
  }
fdf0f54da   Dimitris Papastamos   ASoC: soc-core: A...
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
  static int snd_soc_init_codec_cache(struct snd_soc_codec *codec,
  				    enum snd_soc_compress_type compress_type)
  {
  	int ret;
  
  	if (codec->cache_init)
  		return 0;
  
  	/* override the compress_type if necessary */
  	if (compress_type && codec->compress_type != compress_type)
  		codec->compress_type = compress_type;
fdf0f54da   Dimitris Papastamos   ASoC: soc-core: A...
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
  	ret = snd_soc_cache_init(codec);
  	if (ret < 0) {
  		dev_err(codec->dev, "Failed to set cache compression type: %d
  ",
  			ret);
  		return ret;
  	}
  	codec->cache_init = 1;
  	return 0;
  }
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1301
1302
  static void snd_soc_instantiate_card(struct snd_soc_card *card)
  {
fdf0f54da   Dimitris Papastamos   ASoC: soc-core: A...
1303
1304
1305
  	struct snd_soc_codec *codec;
  	struct snd_soc_codec_conf *codec_conf;
  	enum snd_soc_compress_type compress_type;
75d9ac46b   Mark Brown   ASoC: Allow DAI f...
1306
  	struct snd_soc_dai_link *dai_link;
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
1307
  	int ret, i, order;
fe3e78e07   Mark Brown   ASoC: Factor out ...
1308

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1309
  	mutex_lock(&card->mutex);
dbe21408b   Mark Brown   ASoC: Make pmdown...
1310

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1311
1312
1313
1314
  	if (card->instantiated) {
  		mutex_unlock(&card->mutex);
  		return;
  	}
fe3e78e07   Mark Brown   ASoC: Factor out ...
1315

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1316
1317
1318
  	/* bind DAIs */
  	for (i = 0; i < card->num_links; i++)
  		soc_bind_dai_link(card, i);
fe3e78e07   Mark Brown   ASoC: Factor out ...
1319

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1320
1321
1322
1323
1324
  	/* bind completed ? */
  	if (card->num_rtd != card->num_links) {
  		mutex_unlock(&card->mutex);
  		return;
  	}
435c5e258   Mark Brown   ASoC: Initial fra...
1325

fdf0f54da   Dimitris Papastamos   ASoC: soc-core: A...
1326
1327
1328
1329
  	/* initialize the register cache for each available codec */
  	list_for_each_entry(codec, &codec_list, list) {
  		if (codec->cache_init)
  			continue;
861f2faf4   Dimitris Papastamos   ASoC: soc-core: S...
1330
1331
  		/* by default we don't override the compress_type */
  		compress_type = 0;
fdf0f54da   Dimitris Papastamos   ASoC: soc-core: A...
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
  		/* check to see if we need to override the compress_type */
  		for (i = 0; i < card->num_configs; ++i) {
  			codec_conf = &card->codec_conf[i];
  			if (!strcmp(codec->name, codec_conf->dev_name)) {
  				compress_type = codec_conf->compress_type;
  				if (compress_type && compress_type
  				    != codec->compress_type)
  					break;
  			}
  		}
fdf0f54da   Dimitris Papastamos   ASoC: soc-core: A...
1342
1343
1344
1345
1346
1347
  		ret = snd_soc_init_codec_cache(codec, compress_type);
  		if (ret < 0) {
  			mutex_unlock(&card->mutex);
  			return;
  		}
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
  	/* card bind complete so register a sound card */
  	ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
  			card->owner, 0, &card->snd_card);
  	if (ret < 0) {
  		printk(KERN_ERR "asoc: can't create sound card for card %s
  ",
  			card->name);
  		mutex_unlock(&card->mutex);
  		return;
  	}
  	card->snd_card->dev = card->dev;
e37a4970c   Mark Brown   ASoC: Add a per-c...
1359
1360
1361
1362
  	card->dapm.bias_level = SND_SOC_BIAS_OFF;
  	card->dapm.dev = card->dev;
  	card->dapm.card = card;
  	list_add(&card->dapm.list, &card->dapm_list);
d5d1e0bef   Lars-Peter Clausen   ASoC: Move DAPM w...
1363
1364
1365
  #ifdef CONFIG_DEBUG_FS
  	snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root);
  #endif
88ee1c611   Mark Brown   ASoC: Update PM i...
1366
  #ifdef CONFIG_PM_SLEEP
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1367
1368
1369
  	/* deferred resume work */
  	INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
  #endif
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1370

9a841ebb9   Mark Brown   ASoC: Create card...
1371
1372
1373
  	if (card->dapm_widgets)
  		snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
  					  card->num_dapm_widgets);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1374
1375
  	/* initialise the sound card only once */
  	if (card->probe) {
e7361ec49   Mark Brown   ASoC: Replace pde...
1376
  		ret = card->probe(card);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1377
1378
1379
  		if (ret < 0)
  			goto card_probe_error;
  	}
fe3e78e07   Mark Brown   ASoC: Factor out ...
1380

0168bf0d1   Liam Girdwood   ASoC: core - Allo...
1381
1382
1383
1384
1385
1386
1387
1388
  	/* early DAI link probe */
  	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
  			order++) {
  		for (i = 0; i < card->num_links; i++) {
  			ret = soc_probe_dai_link(card, i, order);
  			if (ret < 0) {
  				pr_err("asoc: failed to instantiate card %s: %d
  ",
321de0d05   Mark Brown   ASoC: Report erro...
1389
  			       card->name, ret);
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
1390
1391
  				goto probe_dai_err;
  			}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1392
1393
  		}
  	}
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1394

2eea392d0   Jarkko Nikula   ASoC: Add support...
1395
1396
1397
1398
1399
1400
1401
1402
1403
  	for (i = 0; i < card->num_aux_devs; i++) {
  		ret = soc_probe_aux_dev(card, i);
  		if (ret < 0) {
  			pr_err("asoc: failed to add auxiliary devices %s: %d
  ",
  			       card->name, ret);
  			goto probe_aux_dev_err;
  		}
  	}
b7af1dafd   Mark Brown   ASoC: Add data ba...
1404
1405
1406
1407
1408
1409
1410
  	/* We should have a non-codec control add function but we don't */
  	if (card->controls)
  		snd_soc_add_controls(list_first_entry(&card->codec_dev_list,
  						      struct snd_soc_codec,
  						      card_list),
  				     card->controls,
  				     card->num_controls);
b8ad29deb   Mark Brown   ASoC: Allow card ...
1411
1412
1413
  	if (card->dapm_routes)
  		snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
  					card->num_dapm_routes);
b90d2f908   Mark Brown   ASoC: Instantiate...
1414
  	snd_soc_dapm_new_widgets(&card->dapm);
75d9ac46b   Mark Brown   ASoC: Allow DAI f...
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
  	for (i = 0; i < card->num_links; i++) {
  		dai_link = &card->dai_link[i];
  
  		if (dai_link->dai_fmt) {
  			ret = snd_soc_dai_set_fmt(card->rtd[i].codec_dai,
  						  dai_link->dai_fmt);
  			if (ret != 0)
  				dev_warn(card->rtd[i].codec_dai->dev,
  					 "Failed to set DAI format: %d
  ",
  					 ret);
  
  			ret = snd_soc_dai_set_fmt(card->rtd[i].cpu_dai,
  						  dai_link->dai_fmt);
  			if (ret != 0)
  				dev_warn(card->rtd[i].cpu_dai->dev,
  					 "Failed to set DAI format: %d
  ",
  					 ret);
  		}
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1436
  	snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1437
  		 "%s", card->name);
22de71ba0   Liam Girdwood   ASoC: core - allo...
1438
1439
  	snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
  		 "%s", card->long_name ? card->long_name : card->name);
f0e8ed858   Mark Brown   ASoC: Ensure we g...
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
  	snprintf(card->snd_card->driver, sizeof(card->snd_card->driver),
  		 "%s", card->driver_name ? card->driver_name : card->name);
  	for (i = 0; i < ARRAY_SIZE(card->snd_card->driver); i++) {
  		switch (card->snd_card->driver[i]) {
  		case '_':
  		case '-':
  		case '\0':
  			break;
  		default:
  			if (!isalnum(card->snd_card->driver[i]))
  				card->snd_card->driver[i] = '_';
  			break;
  		}
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1454

28e9ad921   Mark Brown   ASoC: Add a late_...
1455
1456
1457
1458
1459
1460
1461
1462
1463
  	if (card->late_probe) {
  		ret = card->late_probe(card);
  		if (ret < 0) {
  			dev_err(card->dev, "%s late_probe() failed: %d
  ",
  				card->name, ret);
  			goto probe_aux_dev_err;
  		}
  	}
2dc00213b   Mark Brown   ASoC: Ensure all ...
1464
  	snd_soc_dapm_new_widgets(&card->dapm);
1633281b7   Stephen Warren   ASoC: Implement f...
1465
  	if (card->fully_routed)
b05d8dc15   Mark Brown   ASoC: Fix CODEC e...
1466
  		list_for_each_entry(codec, &card->codec_dev_list, card_list)
1633281b7   Stephen Warren   ASoC: Implement f...
1467
  			snd_soc_dapm_auto_nc_codec_pins(codec);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1468
1469
1470
1471
  	ret = snd_card_register(card->snd_card);
  	if (ret < 0) {
  		printk(KERN_ERR "asoc: failed to register soundcard for %s
  ", card->name);
6b3ed7853   Axel Lin   ASoC: Fix snd_soc...
1472
  		goto probe_aux_dev_err;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1473
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1474
1475
1476
  #ifdef CONFIG_SND_SOC_AC97_BUS
  	/* register any AC97 codecs */
  	for (i = 0; i < card->num_rtd; i++) {
6b3ed7853   Axel Lin   ASoC: Fix snd_soc...
1477
1478
1479
1480
1481
  		ret = soc_register_ac97_dai_link(&card->rtd[i]);
  		if (ret < 0) {
  			printk(KERN_ERR "asoc: failed to register AC97 %s
  ", card->name);
  			while (--i >= 0)
7d8316df4   Mark Brown   ASoC: Fix AC'97 r...
1482
  				soc_unregister_ac97_dai_link(card->rtd[i].codec);
6b3ed7853   Axel Lin   ASoC: Fix snd_soc...
1483
  			goto probe_aux_dev_err;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1484
  		}
6b3ed7853   Axel Lin   ASoC: Fix snd_soc...
1485
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1486
1487
1488
  #endif
  
  	card->instantiated = 1;
4f4c00722   Mark Brown   ASoC: Suppress ea...
1489
  	snd_soc_dapm_sync(&card->dapm);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1490
1491
  	mutex_unlock(&card->mutex);
  	return;
2eea392d0   Jarkko Nikula   ASoC: Add support...
1492
1493
1494
  probe_aux_dev_err:
  	for (i = 0; i < card->num_aux_devs; i++)
  		soc_remove_aux_dev(card, i);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1495
  probe_dai_err:
0671fd8ef   Kuninori Morimoto   ASoC: Add soc_rem...
1496
  	soc_remove_dai_links(card);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1497
1498
  
  card_probe_error:
875065491   Mark Brown   ASoC: Rename snd_...
1499
  	if (card->remove)
e7361ec49   Mark Brown   ASoC: Replace pde...
1500
  		card->remove(card);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1501
1502
1503
1504
  
  	snd_card_free(card->snd_card);
  
  	mutex_unlock(&card->mutex);
435c5e258   Mark Brown   ASoC: Initial fra...
1505
  }
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1506

435c5e258   Mark Brown   ASoC: Initial fra...
1507
  /*
421f91d21   Uwe Kleine-König   fix typos concern...
1508
   * Attempt to initialise any uninitialised cards.  Must be called with
435c5e258   Mark Brown   ASoC: Initial fra...
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
   * client_mutex.
   */
  static void snd_soc_instantiate_cards(void)
  {
  	struct snd_soc_card *card;
  	list_for_each_entry(card, &card_list, list)
  		snd_soc_instantiate_card(card);
  }
  
  /* probes a new socdev */
  static int soc_probe(struct platform_device *pdev)
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1521
  	struct snd_soc_card *card = platform_get_drvdata(pdev);
435c5e258   Mark Brown   ASoC: Initial fra...
1522
  	int ret = 0;
435c5e258   Mark Brown   ASoC: Initial fra...
1523

70a7ca34d   Vinod Koul   ASoC: soc core al...
1524
1525
1526
1527
1528
1529
  	/*
  	 * no card, so machine driver should be registering card
  	 * we should not be here in that case so ret error
  	 */
  	if (!card)
  		return -EINVAL;
435c5e258   Mark Brown   ASoC: Initial fra...
1530
1531
  	/* Bodge while we unpick instantiation */
  	card->dev = &pdev->dev;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1532

435c5e258   Mark Brown   ASoC: Initial fra...
1533
1534
1535
1536
1537
1538
1539
1540
  	ret = snd_soc_register_card(card);
  	if (ret != 0) {
  		dev_err(&pdev->dev, "Failed to register card
  ");
  		return ret;
  	}
  
  	return 0;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1541
  }
b0e264855   Vinod Koul   ASoC: soc core mo...
1542
  static int soc_cleanup_card_resources(struct snd_soc_card *card)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1543
1544
  {
  	int i;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1545

b0e264855   Vinod Koul   ASoC: soc core mo...
1546
1547
1548
1549
1550
  	/* make sure any delayed work runs */
  	for (i = 0; i < card->num_rtd; i++) {
  		struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
  		flush_delayed_work_sync(&rtd->delayed_work);
  	}
914dc1825   Mike Rapoport   ASoC: soc-core: f...
1551

b0e264855   Vinod Koul   ASoC: soc core mo...
1552
1553
1554
  	/* remove auxiliary devices */
  	for (i = 0; i < card->num_aux_devs; i++)
  		soc_remove_aux_dev(card, i);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1555

b0e264855   Vinod Koul   ASoC: soc core mo...
1556
  	/* remove and free each DAI */
0671fd8ef   Kuninori Morimoto   ASoC: Add soc_rem...
1557
  	soc_remove_dai_links(card);
2eea392d0   Jarkko Nikula   ASoC: Add support...
1558

b0e264855   Vinod Koul   ASoC: soc core mo...
1559
  	soc_cleanup_card_debugfs(card);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1560

b0e264855   Vinod Koul   ASoC: soc core mo...
1561
1562
  	/* remove the card */
  	if (card->remove)
e7361ec49   Mark Brown   ASoC: Replace pde...
1563
  		card->remove(card);
a60521549   Jarkko Nikula   ASoC: Add sound c...
1564

0aaae527c   Lars-Peter Clausen   ASoC: Free the ca...
1565
  	snd_soc_dapm_free(&card->dapm);
b0e264855   Vinod Koul   ASoC: soc core mo...
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
  	kfree(card->rtd);
  	snd_card_free(card->snd_card);
  	return 0;
  
  }
  
  /* removes a socdev */
  static int soc_remove(struct platform_device *pdev)
  {
  	struct snd_soc_card *card = platform_get_drvdata(pdev);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1576

c5af3a2e1   Mark Brown   ASoC: Add card re...
1577
  	snd_soc_unregister_card(card);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1578
1579
  	return 0;
  }
6f8ab4ac2   Mark Brown   ASoC: Export card...
1580
  int snd_soc_poweroff(struct device *dev)
517374704   Mark Brown   ASoC: Add a shutd...
1581
  {
6f8ab4ac2   Mark Brown   ASoC: Export card...
1582
  	struct snd_soc_card *card = dev_get_drvdata(dev);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1583
  	int i;
517374704   Mark Brown   ASoC: Add a shutd...
1584
1585
  
  	if (!card->instantiated)
416356fcf   Mark Brown   ASoC: Convert to ...
1586
  		return 0;
517374704   Mark Brown   ASoC: Add a shutd...
1587
1588
1589
  
  	/* Flush out pmdown_time work - we actually do want to run it
  	 * now, we're shutting down so no imminent restart. */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1590
1591
  	for (i = 0; i < card->num_rtd; i++) {
  		struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
5b84ba26a   Tejun Heo   sound: don't use ...
1592
  		flush_delayed_work_sync(&rtd->delayed_work);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1593
  	}
517374704   Mark Brown   ASoC: Add a shutd...
1594

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1595
  	snd_soc_dapm_shutdown(card);
416356fcf   Mark Brown   ASoC: Convert to ...
1596
1597
  
  	return 0;
517374704   Mark Brown   ASoC: Add a shutd...
1598
  }
6f8ab4ac2   Mark Brown   ASoC: Export card...
1599
  EXPORT_SYMBOL_GPL(snd_soc_poweroff);
517374704   Mark Brown   ASoC: Add a shutd...
1600

6f8ab4ac2   Mark Brown   ASoC: Export card...
1601
1602
1603
1604
  const struct dev_pm_ops snd_soc_pm_ops = {
  	.suspend = snd_soc_suspend,
  	.resume = snd_soc_resume,
  	.poweroff = snd_soc_poweroff,
416356fcf   Mark Brown   ASoC: Convert to ...
1605
  };
deb2607e6   Stephen Warren   ASoC: Tegra: Susp...
1606
  EXPORT_SYMBOL_GPL(snd_soc_pm_ops);
416356fcf   Mark Brown   ASoC: Convert to ...
1607

db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1608
1609
1610
1611
  /* ASoC platform driver */
  static struct platform_driver soc_driver = {
  	.driver		= {
  		.name		= "soc-audio",
8b45a2099   Kay Sievers   [ALSA] sound: fix...
1612
  		.owner		= THIS_MODULE,
6f8ab4ac2   Mark Brown   ASoC: Export card...
1613
  		.pm		= &snd_soc_pm_ops,
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1614
1615
1616
  	},
  	.probe		= soc_probe,
  	.remove		= soc_remove,
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1617
  };
096e49d5e   Mark Brown   ASoC: Add CODEC v...
1618
1619
1620
1621
1622
1623
1624
1625
  /**
   * snd_soc_codec_volatile_register: Report if a register is volatile.
   *
   * @codec: CODEC to query.
   * @reg: Register to query.
   *
   * Boolean function indiciating if a CODEC register is volatile.
   */
181e055e6   Mark Brown   ASoC: Fix type fo...
1626
1627
  int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
  				    unsigned int reg)
096e49d5e   Mark Brown   ASoC: Add CODEC v...
1628
  {
1500b7b5f   Dimitris Papastamos   ASoC: Automatical...
1629
1630
  	if (codec->volatile_register)
  		return codec->volatile_register(codec, reg);
096e49d5e   Mark Brown   ASoC: Add CODEC v...
1631
1632
1633
1634
  	else
  		return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_codec_volatile_register);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1635
  /**
239c97062   Dimitris Papastamos   ASoC: Add snd_soc...
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
   * snd_soc_codec_readable_register: Report if a register is readable.
   *
   * @codec: CODEC to query.
   * @reg: Register to query.
   *
   * Boolean function indicating if a CODEC register is readable.
   */
  int snd_soc_codec_readable_register(struct snd_soc_codec *codec,
  				    unsigned int reg)
  {
  	if (codec->readable_register)
  		return codec->readable_register(codec, reg);
  	else
63fa0a288   Lars-Peter Clausen   ASoC: snd_soc_cod...
1649
  		return 1;
239c97062   Dimitris Papastamos   ASoC: Add snd_soc...
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
  }
  EXPORT_SYMBOL_GPL(snd_soc_codec_readable_register);
  
  /**
   * snd_soc_codec_writable_register: Report if a register is writable.
   *
   * @codec: CODEC to query.
   * @reg: Register to query.
   *
   * Boolean function indicating if a CODEC register is writable.
   */
  int snd_soc_codec_writable_register(struct snd_soc_codec *codec,
  				    unsigned int reg)
  {
  	if (codec->writable_register)
  		return codec->writable_register(codec, reg);
  	else
63fa0a288   Lars-Peter Clausen   ASoC: snd_soc_cod...
1667
  		return 1;
239c97062   Dimitris Papastamos   ASoC: Add snd_soc...
1668
1669
  }
  EXPORT_SYMBOL_GPL(snd_soc_codec_writable_register);
f1442bc1e   Liam Girdwood   ASoC: core - Add ...
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
  int snd_soc_platform_read(struct snd_soc_platform *platform,
  					unsigned int reg)
  {
  	unsigned int ret;
  
  	if (!platform->driver->read) {
  		dev_err(platform->dev, "platform has no read back
  ");
  		return -1;
  	}
  
  	ret = platform->driver->read(platform, reg);
  	dev_dbg(platform->dev, "read %x => %x
  ", reg, ret);
a82ce2ae0   Liam Girdwood   ASoC: core - Add ...
1684
  	trace_snd_soc_preg_read(platform, reg, ret);
f1442bc1e   Liam Girdwood   ASoC: core - Add ...
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
  
  	return ret;
  }
  EXPORT_SYMBOL_GPL(snd_soc_platform_read);
  
  int snd_soc_platform_write(struct snd_soc_platform *platform,
  					 unsigned int reg, unsigned int val)
  {
  	if (!platform->driver->write) {
  		dev_err(platform->dev, "platform has no write back
  ");
  		return -1;
  	}
  
  	dev_dbg(platform->dev, "write %x = %x
  ", reg, val);
a82ce2ae0   Liam Girdwood   ASoC: core - Add ...
1701
  	trace_snd_soc_preg_write(platform, reg, val);
f1442bc1e   Liam Girdwood   ASoC: core - Add ...
1702
1703
1704
  	return platform->driver->write(platform, reg, val);
  }
  EXPORT_SYMBOL_GPL(snd_soc_platform_write);
239c97062   Dimitris Papastamos   ASoC: Add snd_soc...
1705
  /**
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
   * snd_soc_new_ac97_codec - initailise AC97 device
   * @codec: audio codec
   * @ops: AC97 bus operations
   * @num: AC97 codec number
   *
   * Initialises AC97 codec resources for use by ad-hoc devices only.
   */
  int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
  	struct snd_ac97_bus_ops *ops, int num)
  {
  	mutex_lock(&codec->mutex);
  
  	codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL);
  	if (codec->ac97 == NULL) {
  		mutex_unlock(&codec->mutex);
  		return -ENOMEM;
  	}
  
  	codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL);
  	if (codec->ac97->bus == NULL) {
  		kfree(codec->ac97);
  		codec->ac97 = NULL;
  		mutex_unlock(&codec->mutex);
  		return -ENOMEM;
  	}
  
  	codec->ac97->bus->ops = ops;
  	codec->ac97->num = num;
0562f7882   Mika Westerberg   ASoC: don't regis...
1734
1735
1736
1737
1738
1739
  
  	/*
  	 * Mark the AC97 device to be created by us. This way we ensure that the
  	 * device will be registered with the device subsystem later on.
  	 */
  	codec->ac97_created = 1;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
  	mutex_unlock(&codec->mutex);
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
  
  /**
   * snd_soc_free_ac97_codec - free AC97 codec device
   * @codec: audio codec
   *
   * Frees AC97 codec device resources.
   */
  void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
  {
  	mutex_lock(&codec->mutex);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1754
1755
1756
  #ifdef CONFIG_SND_SOC_AC97_BUS
  	soc_unregister_ac97_dai_link(codec);
  #endif
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1757
1758
1759
  	kfree(codec->ac97->bus);
  	kfree(codec->ac97);
  	codec->ac97 = NULL;
0562f7882   Mika Westerberg   ASoC: don't regis...
1760
  	codec->ac97_created = 0;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1761
1762
1763
  	mutex_unlock(&codec->mutex);
  }
  EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
c37537079   Mark Brown   ASoC: Push snd_so...
1764
1765
1766
  unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg)
  {
  	unsigned int ret;
c3acec267   Mark Brown   ASoC: Move active...
1767
  	ret = codec->read(codec, reg);
c37537079   Mark Brown   ASoC: Push snd_so...
1768
1769
  	dev_dbg(codec->dev, "read %x => %x
  ", reg, ret);
a8b1d34f3   Mark Brown   ASoC: Add trace e...
1770
  	trace_snd_soc_reg_read(codec, reg, ret);
c37537079   Mark Brown   ASoC: Push snd_so...
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
  
  	return ret;
  }
  EXPORT_SYMBOL_GPL(snd_soc_read);
  
  unsigned int snd_soc_write(struct snd_soc_codec *codec,
  			   unsigned int reg, unsigned int val)
  {
  	dev_dbg(codec->dev, "write %x = %x
  ", reg, val);
a8b1d34f3   Mark Brown   ASoC: Add trace e...
1781
  	trace_snd_soc_reg_write(codec, reg, val);
c3acec267   Mark Brown   ASoC: Move active...
1782
  	return codec->write(codec, reg, val);
c37537079   Mark Brown   ASoC: Push snd_so...
1783
1784
  }
  EXPORT_SYMBOL_GPL(snd_soc_write);
5fb609d43   Dimitris Papastamos   ASoC: soc-cache: ...
1785
1786
1787
1788
1789
1790
  unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec,
  				    unsigned int reg, const void *data, size_t len)
  {
  	return codec->bulk_write_raw(codec, reg, data, len);
  }
  EXPORT_SYMBOL_GPL(snd_soc_bulk_write_raw);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1791
1792
1793
1794
1795
1796
1797
1798
1799
  /**
   * snd_soc_update_bits - update codec register bits
   * @codec: audio codec
   * @reg: codec register
   * @mask: register mask
   * @value: new value
   *
   * Writes new register value.
   *
180c329d6   Timur Tabi   ASoC: let snd_soc...
1800
   * Returns 1 for change, 0 for no change, or negative error code.
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1801
1802
   */
  int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
46f5822f7   Daniel Ribeiro   ASoC: Allow 32 bi...
1803
  				unsigned int mask, unsigned int value)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1804
1805
  {
  	int change;
46f5822f7   Daniel Ribeiro   ASoC: Allow 32 bi...
1806
  	unsigned int old, new;
180c329d6   Timur Tabi   ASoC: let snd_soc...
1807
1808
1809
1810
1811
  	int ret;
  
  	ret = snd_soc_read(codec, reg);
  	if (ret < 0)
  		return ret;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1812

180c329d6   Timur Tabi   ASoC: let snd_soc...
1813
  	old = ret;
78bf3c9ab   Mark Brown   ASoC: Enforce the...
1814
  	new = (old & ~mask) | (value & mask);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1815
  	change = old != new;
180c329d6   Timur Tabi   ASoC: let snd_soc...
1816
1817
1818
1819
1820
  	if (change) {
  		ret = snd_soc_write(codec, reg, new);
  		if (ret < 0)
  			return ret;
  	}
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1821

db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1822
1823
1824
1825
1826
  	return change;
  }
  EXPORT_SYMBOL_GPL(snd_soc_update_bits);
  
  /**
6c508c62f   Eero Nurkkala   ASoC: refactor sn...
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
   * snd_soc_update_bits_locked - update codec register bits
   * @codec: audio codec
   * @reg: codec register
   * @mask: register mask
   * @value: new value
   *
   * Writes new register value, and takes the codec mutex.
   *
   * Returns 1 for change else 0.
   */
dd1b3d53c   Mark Brown   ASoC: Export snd_...
1837
1838
1839
  int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
  			       unsigned short reg, unsigned int mask,
  			       unsigned int value)
6c508c62f   Eero Nurkkala   ASoC: refactor sn...
1840
1841
1842
1843
1844
1845
1846
1847
1848
  {
  	int change;
  
  	mutex_lock(&codec->mutex);
  	change = snd_soc_update_bits(codec, reg, mask, value);
  	mutex_unlock(&codec->mutex);
  
  	return change;
  }
dd1b3d53c   Mark Brown   ASoC: Export snd_...
1849
  EXPORT_SYMBOL_GPL(snd_soc_update_bits_locked);
6c508c62f   Eero Nurkkala   ASoC: refactor sn...
1850
1851
  
  /**
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
   * snd_soc_test_bits - test register for change
   * @codec: audio codec
   * @reg: codec register
   * @mask: register mask
   * @value: new value
   *
   * Tests a register with a new value and checks if the new value is
   * different from the old value.
   *
   * Returns 1 for change else 0.
   */
  int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
46f5822f7   Daniel Ribeiro   ASoC: Allow 32 bi...
1864
  				unsigned int mask, unsigned int value)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1865
1866
  {
  	int change;
46f5822f7   Daniel Ribeiro   ASoC: Allow 32 bi...
1867
  	unsigned int old, new;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1868

db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1869
1870
1871
  	old = snd_soc_read(codec, reg);
  	new = (old & ~mask) | value;
  	change = old != new;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1872
1873
1874
1875
1876
1877
  
  	return change;
  }
  EXPORT_SYMBOL_GPL(snd_soc_test_bits);
  
  /**
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
   * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
   * @substream: the pcm substream
   * @hw: the hardware parameters
   *
   * Sets the substream runtime hardware parameters.
   */
  int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
  	const struct snd_pcm_hardware *hw)
  {
  	struct snd_pcm_runtime *runtime = substream->runtime;
  	runtime->hw.info = hw->info;
  	runtime->hw.formats = hw->formats;
  	runtime->hw.period_bytes_min = hw->period_bytes_min;
  	runtime->hw.period_bytes_max = hw->period_bytes_max;
  	runtime->hw.periods_min = hw->periods_min;
  	runtime->hw.periods_max = hw->periods_max;
  	runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
  	runtime->hw.fifo_size = hw->fifo_size;
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
  
  /**
   * snd_soc_cnew - create new control
   * @_template: control template
   * @data: control private data
ac11a2b35   Mark Brown   ASoC: Clean up ke...
1904
   * @long_name: control long name
efb7ac3f9   Mark Brown   ASoC: Fix prefixi...
1905
   * @prefix: control name prefix
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1906
1907
1908
1909
1910
1911
   *
   * Create a new mixer control from a template control.
   *
   * Returns 0 for success, else error.
   */
  struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
efb7ac3f9   Mark Brown   ASoC: Fix prefixi...
1912
1913
  				  void *data, char *long_name,
  				  const char *prefix)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1914
1915
  {
  	struct snd_kcontrol_new template;
efb7ac3f9   Mark Brown   ASoC: Fix prefixi...
1916
1917
1918
  	struct snd_kcontrol *kcontrol;
  	char *name = NULL;
  	int name_len;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1919
1920
  
  	memcpy(&template, _template, sizeof(template));
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1921
  	template.index = 0;
efb7ac3f9   Mark Brown   ASoC: Fix prefixi...
1922
1923
1924
1925
1926
  	if (!long_name)
  		long_name = template.name;
  
  	if (prefix) {
  		name_len = strlen(long_name) + strlen(prefix) + 2;
57cf9d451   Axel Lin   ASoC: soc-core: u...
1927
  		name = kmalloc(name_len, GFP_KERNEL);
efb7ac3f9   Mark Brown   ASoC: Fix prefixi...
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
  		if (!name)
  			return NULL;
  
  		snprintf(name, name_len, "%s %s", prefix, long_name);
  
  		template.name = name;
  	} else {
  		template.name = long_name;
  	}
  
  	kcontrol = snd_ctl_new1(&template, data);
  
  	kfree(name);
  
  	return kcontrol;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1943
1944
1945
1946
  }
  EXPORT_SYMBOL_GPL(snd_soc_cnew);
  
  /**
3e8e1952e   Ian Molton   ASoC: cleanup dup...
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
   * snd_soc_add_controls - add an array of controls to a codec.
   * Convienience function to add a list of controls. Many codecs were
   * duplicating this code.
   *
   * @codec: codec to add controls to
   * @controls: array of controls to add
   * @num_controls: number of elements in the array
   *
   * Return 0 for success, else error.
   */
  int snd_soc_add_controls(struct snd_soc_codec *codec,
  	const struct snd_kcontrol_new *controls, int num_controls)
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1960
  	struct snd_card *card = codec->card->snd_card;
3e8e1952e   Ian Molton   ASoC: cleanup dup...
1961
1962
1963
1964
  	int err, i;
  
  	for (i = 0; i < num_controls; i++) {
  		const struct snd_kcontrol_new *control = &controls[i];
efb7ac3f9   Mark Brown   ASoC: Fix prefixi...
1965
1966
1967
  		err = snd_ctl_add(card, snd_soc_cnew(control, codec,
  						     control->name,
  						     codec->name_prefix));
3e8e1952e   Ian Molton   ASoC: cleanup dup...
1968
  		if (err < 0) {
082100dc9   Mark Brown   ASoC: Report erro...
1969
1970
  			dev_err(codec->dev, "%s: Failed to add %s: %d
  ",
efb7ac3f9   Mark Brown   ASoC: Fix prefixi...
1971
  				codec->name, control->name, err);
3e8e1952e   Ian Molton   ASoC: cleanup dup...
1972
1973
1974
1975
1976
1977
1978
1979
1980
  			return err;
  		}
  	}
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_add_controls);
  
  /**
a491a5c84   Liam Girdwood   ASoC: core - Add ...
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
   * snd_soc_add_platform_controls - add an array of controls to a platform.
   * Convienience function to add a list of controls.
   *
   * @platform: platform to add controls to
   * @controls: array of controls to add
   * @num_controls: number of elements in the array
   *
   * Return 0 for success, else error.
   */
  int snd_soc_add_platform_controls(struct snd_soc_platform *platform,
  	const struct snd_kcontrol_new *controls, int num_controls)
  {
  	struct snd_card *card = platform->card->snd_card;
  	int err, i;
  
  	for (i = 0; i < num_controls; i++) {
  		const struct snd_kcontrol_new *control = &controls[i];
  		err = snd_ctl_add(card, snd_soc_cnew(control, platform,
  				control->name, NULL));
  		if (err < 0) {
  			dev_err(platform->dev, "Failed to add %s %d
  ",control->name, err);
  			return err;
  		}
  	}
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_add_platform_controls);
  
  /**
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
   * snd_soc_info_enum_double - enumerated double mixer info callback
   * @kcontrol: mixer control
   * @uinfo: control element information
   *
   * Callback to provide information about a double enumerated
   * mixer control.
   *
   * Returns 0 for success.
   */
  int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
  	struct snd_ctl_elem_info *uinfo)
  {
  	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
  
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
  	uinfo->count = e->shift_l == e->shift_r ? 1 : 2;
f8ba0b7bf   Jon Smirl   ALSA: ASoC: Renam...
2028
  	uinfo->value.enumerated.items = e->max;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2029

f8ba0b7bf   Jon Smirl   ALSA: ASoC: Renam...
2030
2031
  	if (uinfo->value.enumerated.item > e->max - 1)
  		uinfo->value.enumerated.item = e->max - 1;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2032
2033
2034
2035
2036
2037
2038
2039
2040
  	strcpy(uinfo->value.enumerated.name,
  		e->texts[uinfo->value.enumerated.item]);
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_info_enum_double);
  
  /**
   * snd_soc_get_enum_double - enumerated double mixer get callback
   * @kcontrol: mixer control
ac11a2b35   Mark Brown   ASoC: Clean up ke...
2041
   * @ucontrol: control element information
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
   *
   * Callback to get the value of a double enumerated mixer.
   *
   * Returns 0 for success.
   */
  int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
  	struct snd_ctl_elem_value *ucontrol)
  {
  	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
  	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
46f5822f7   Daniel Ribeiro   ASoC: Allow 32 bi...
2052
  	unsigned int val, bitmask;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2053

f8ba0b7bf   Jon Smirl   ALSA: ASoC: Renam...
2054
  	for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2055
2056
  		;
  	val = snd_soc_read(codec, e->reg);
3ff3f64ba   Mark Brown   [ALSA] ASoC: core...
2057
2058
  	ucontrol->value.enumerated.item[0]
  		= (val >> e->shift_l) & (bitmask - 1);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
  	if (e->shift_l != e->shift_r)
  		ucontrol->value.enumerated.item[1] =
  			(val >> e->shift_r) & (bitmask - 1);
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_get_enum_double);
  
  /**
   * snd_soc_put_enum_double - enumerated double mixer put callback
   * @kcontrol: mixer control
ac11a2b35   Mark Brown   ASoC: Clean up ke...
2070
   * @ucontrol: control element information
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
   *
   * Callback to set the value of a double enumerated mixer.
   *
   * Returns 0 for success.
   */
  int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
  	struct snd_ctl_elem_value *ucontrol)
  {
  	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
  	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
46f5822f7   Daniel Ribeiro   ASoC: Allow 32 bi...
2081
2082
  	unsigned int val;
  	unsigned int mask, bitmask;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2083

f8ba0b7bf   Jon Smirl   ALSA: ASoC: Renam...
2084
  	for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2085
  		;
f8ba0b7bf   Jon Smirl   ALSA: ASoC: Renam...
2086
  	if (ucontrol->value.enumerated.item[0] > e->max - 1)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2087
2088
2089
2090
  		return -EINVAL;
  	val = ucontrol->value.enumerated.item[0] << e->shift_l;
  	mask = (bitmask - 1) << e->shift_l;
  	if (e->shift_l != e->shift_r) {
f8ba0b7bf   Jon Smirl   ALSA: ASoC: Renam...
2091
  		if (ucontrol->value.enumerated.item[1] > e->max - 1)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2092
2093
2094
2095
  			return -EINVAL;
  		val |= ucontrol->value.enumerated.item[1] << e->shift_r;
  		mask |= (bitmask - 1) << e->shift_r;
  	}
6c508c62f   Eero Nurkkala   ASoC: refactor sn...
2096
  	return snd_soc_update_bits_locked(codec, e->reg, mask, val);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2097
2098
2099
2100
  }
  EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
  
  /**
2e72f8e37   Peter Ujfalusi   ASoC: New enum ty...
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
   * snd_soc_get_value_enum_double - semi enumerated double mixer get callback
   * @kcontrol: mixer control
   * @ucontrol: control element information
   *
   * Callback to get the value of a double semi enumerated mixer.
   *
   * Semi enumerated mixer: the enumerated items are referred as values. Can be
   * used for handling bitfield coded enumeration for example.
   *
   * Returns 0 for success.
   */
  int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol,
  	struct snd_ctl_elem_value *ucontrol)
  {
  	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
741555568   Peter Ujfalusi   ASoC: Merge the s...
2116
  	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
46f5822f7   Daniel Ribeiro   ASoC: Allow 32 bi...
2117
  	unsigned int reg_val, val, mux;
2e72f8e37   Peter Ujfalusi   ASoC: New enum ty...
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
  
  	reg_val = snd_soc_read(codec, e->reg);
  	val = (reg_val >> e->shift_l) & e->mask;
  	for (mux = 0; mux < e->max; mux++) {
  		if (val == e->values[mux])
  			break;
  	}
  	ucontrol->value.enumerated.item[0] = mux;
  	if (e->shift_l != e->shift_r) {
  		val = (reg_val >> e->shift_r) & e->mask;
  		for (mux = 0; mux < e->max; mux++) {
  			if (val == e->values[mux])
  				break;
  		}
  		ucontrol->value.enumerated.item[1] = mux;
  	}
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_get_value_enum_double);
  
  /**
   * snd_soc_put_value_enum_double - semi enumerated double mixer put callback
   * @kcontrol: mixer control
   * @ucontrol: control element information
   *
   * Callback to set the value of a double semi enumerated mixer.
   *
   * Semi enumerated mixer: the enumerated items are referred as values. Can be
   * used for handling bitfield coded enumeration for example.
   *
   * Returns 0 for success.
   */
  int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
  	struct snd_ctl_elem_value *ucontrol)
  {
  	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
741555568   Peter Ujfalusi   ASoC: Merge the s...
2155
  	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
46f5822f7   Daniel Ribeiro   ASoC: Allow 32 bi...
2156
2157
  	unsigned int val;
  	unsigned int mask;
2e72f8e37   Peter Ujfalusi   ASoC: New enum ty...
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
  
  	if (ucontrol->value.enumerated.item[0] > e->max - 1)
  		return -EINVAL;
  	val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l;
  	mask = e->mask << e->shift_l;
  	if (e->shift_l != e->shift_r) {
  		if (ucontrol->value.enumerated.item[1] > e->max - 1)
  			return -EINVAL;
  		val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r;
  		mask |= e->mask << e->shift_r;
  	}
6c508c62f   Eero Nurkkala   ASoC: refactor sn...
2169
  	return snd_soc_update_bits_locked(codec, e->reg, mask, val);
2e72f8e37   Peter Ujfalusi   ASoC: New enum ty...
2170
2171
2172
2173
  }
  EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double);
  
  /**
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
   * snd_soc_info_enum_ext - external enumerated single mixer info callback
   * @kcontrol: mixer control
   * @uinfo: control element information
   *
   * Callback to provide information about an external enumerated
   * single mixer.
   *
   * Returns 0 for success.
   */
  int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
  	struct snd_ctl_elem_info *uinfo)
  {
  	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
  
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
  	uinfo->count = 1;
f8ba0b7bf   Jon Smirl   ALSA: ASoC: Renam...
2190
  	uinfo->value.enumerated.items = e->max;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2191

f8ba0b7bf   Jon Smirl   ALSA: ASoC: Renam...
2192
2193
  	if (uinfo->value.enumerated.item > e->max - 1)
  		uinfo->value.enumerated.item = e->max - 1;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
  	strcpy(uinfo->value.enumerated.name,
  		e->texts[uinfo->value.enumerated.item]);
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_info_enum_ext);
  
  /**
   * snd_soc_info_volsw_ext - external single mixer info callback
   * @kcontrol: mixer control
   * @uinfo: control element information
   *
   * Callback to provide information about a single external mixer control.
   *
   * Returns 0 for success.
   */
  int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
  	struct snd_ctl_elem_info *uinfo)
  {
a7a4ac86b   Philipp Zabel   [ALSA] ASoC TLV s...
2212
  	int max = kcontrol->private_value;
fd5dfad9c   Mark Brown   ASoC: Volume cont...
2213
  	if (max == 1 && !strstr(kcontrol->id.name, " Volume"))
a7a4ac86b   Philipp Zabel   [ALSA] ASoC TLV s...
2214
2215
2216
  		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
  	else
  		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2217

db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2218
2219
  	uinfo->count = 1;
  	uinfo->value.integer.min = 0;
a7a4ac86b   Philipp Zabel   [ALSA] ASoC TLV s...
2220
  	uinfo->value.integer.max = max;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2221
2222
2223
2224
2225
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext);
  
  /**
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2226
2227
2228
2229
   * snd_soc_info_volsw - single mixer info callback
   * @kcontrol: mixer control
   * @uinfo: control element information
   *
e8f5a1030   Peter Ujfalusi   ASoC: core: Combi...
2230
2231
   * Callback to provide information about a single mixer control, or a double
   * mixer control that spans 2 registers.
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2232
2233
2234
2235
2236
2237
   *
   * Returns 0 for success.
   */
  int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
  	struct snd_ctl_elem_info *uinfo)
  {
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2238
2239
  	struct soc_mixer_control *mc =
  		(struct soc_mixer_control *)kcontrol->private_value;
d11bb4a92   Peter Ujfalusi   ASoC: core: Fix f...
2240
  	int platform_max;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2241

d11bb4a92   Peter Ujfalusi   ASoC: core: Fix f...
2242
2243
2244
2245
2246
  	if (!mc->platform_max)
  		mc->platform_max = mc->max;
  	platform_max = mc->platform_max;
  
  	if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume"))
a7a4ac86b   Philipp Zabel   [ALSA] ASoC TLV s...
2247
2248
2249
  		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
  	else
  		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
e8f5a1030   Peter Ujfalusi   ASoC: core: Combi...
2250
  	uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2251
  	uinfo->value.integer.min = 0;
d11bb4a92   Peter Ujfalusi   ASoC: core: Fix f...
2252
  	uinfo->value.integer.max = platform_max;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2253
2254
2255
2256
2257
2258
2259
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
  
  /**
   * snd_soc_get_volsw - single mixer get callback
   * @kcontrol: mixer control
ac11a2b35   Mark Brown   ASoC: Clean up ke...
2260
   * @ucontrol: control element information
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2261
   *
f7915d997   Peter Ujfalusi   ASoC: core: Combi...
2262
2263
   * Callback to get the value of a single mixer control, or a double mixer
   * control that spans 2 registers.
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2264
2265
2266
2267
2268
2269
   *
   * Returns 0 for success.
   */
  int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
  	struct snd_ctl_elem_value *ucontrol)
  {
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2270
2271
  	struct soc_mixer_control *mc =
  		(struct soc_mixer_control *)kcontrol->private_value;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2272
  	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
815ecf8de   Jon Smirl   ALSA: ASoC: conve...
2273
  	unsigned int reg = mc->reg;
f7915d997   Peter Ujfalusi   ASoC: core: Combi...
2274
  	unsigned int reg2 = mc->rreg;
815ecf8de   Jon Smirl   ALSA: ASoC: conve...
2275
2276
  	unsigned int shift = mc->shift;
  	unsigned int rshift = mc->rshift;
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2277
  	int max = mc->max;
815ecf8de   Jon Smirl   ALSA: ASoC: conve...
2278
2279
  	unsigned int mask = (1 << fls(max)) - 1;
  	unsigned int invert = mc->invert;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2280
2281
2282
  
  	ucontrol->value.integer.value[0] =
  		(snd_soc_read(codec, reg) >> shift) & mask;
f7915d997   Peter Ujfalusi   ASoC: core: Combi...
2283
  	if (invert)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2284
  		ucontrol->value.integer.value[0] =
a7a4ac86b   Philipp Zabel   [ALSA] ASoC TLV s...
2285
  			max - ucontrol->value.integer.value[0];
f7915d997   Peter Ujfalusi   ASoC: core: Combi...
2286
2287
2288
2289
2290
2291
2292
2293
2294
  
  	if (snd_soc_volsw_is_stereo(mc)) {
  		if (reg == reg2)
  			ucontrol->value.integer.value[1] =
  				(snd_soc_read(codec, reg) >> rshift) & mask;
  		else
  			ucontrol->value.integer.value[1] =
  				(snd_soc_read(codec, reg2) >> shift) & mask;
  		if (invert)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2295
  			ucontrol->value.integer.value[1] =
a7a4ac86b   Philipp Zabel   [ALSA] ASoC TLV s...
2296
  				max - ucontrol->value.integer.value[1];
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2297
2298
2299
2300
2301
2302
2303
2304
2305
  	}
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_get_volsw);
  
  /**
   * snd_soc_put_volsw - single mixer put callback
   * @kcontrol: mixer control
ac11a2b35   Mark Brown   ASoC: Clean up ke...
2306
   * @ucontrol: control element information
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2307
   *
974815ba4   Peter Ujfalusi   ASoC: core: Combi...
2308
2309
   * Callback to set the value of a single mixer control, or a double mixer
   * control that spans 2 registers.
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2310
2311
2312
2313
2314
2315
   *
   * Returns 0 for success.
   */
  int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
  	struct snd_ctl_elem_value *ucontrol)
  {
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2316
2317
  	struct soc_mixer_control *mc =
  		(struct soc_mixer_control *)kcontrol->private_value;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2318
  	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
815ecf8de   Jon Smirl   ALSA: ASoC: conve...
2319
  	unsigned int reg = mc->reg;
974815ba4   Peter Ujfalusi   ASoC: core: Combi...
2320
  	unsigned int reg2 = mc->rreg;
815ecf8de   Jon Smirl   ALSA: ASoC: conve...
2321
2322
  	unsigned int shift = mc->shift;
  	unsigned int rshift = mc->rshift;
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2323
  	int max = mc->max;
815ecf8de   Jon Smirl   ALSA: ASoC: conve...
2324
2325
  	unsigned int mask = (1 << fls(max)) - 1;
  	unsigned int invert = mc->invert;
974815ba4   Peter Ujfalusi   ASoC: core: Combi...
2326
2327
2328
2329
  	int err;
  	bool type_2r = 0;
  	unsigned int val2 = 0;
  	unsigned int val, val_mask;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2330
2331
2332
  
  	val = (ucontrol->value.integer.value[0] & mask);
  	if (invert)
a7a4ac86b   Philipp Zabel   [ALSA] ASoC TLV s...
2333
  		val = max - val;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2334
2335
  	val_mask = mask << shift;
  	val = val << shift;
974815ba4   Peter Ujfalusi   ASoC: core: Combi...
2336
  	if (snd_soc_volsw_is_stereo(mc)) {
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2337
2338
  		val2 = (ucontrol->value.integer.value[1] & mask);
  		if (invert)
a7a4ac86b   Philipp Zabel   [ALSA] ASoC TLV s...
2339
  			val2 = max - val2;
974815ba4   Peter Ujfalusi   ASoC: core: Combi...
2340
2341
2342
2343
2344
2345
2346
  		if (reg == reg2) {
  			val_mask |= mask << rshift;
  			val |= val2 << rshift;
  		} else {
  			val2 = val2 << shift;
  			type_2r = 1;
  		}
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2347
  	}
6c508c62f   Eero Nurkkala   ASoC: refactor sn...
2348
  	err = snd_soc_update_bits_locked(codec, reg, val_mask, val);
3ff3f64ba   Mark Brown   [ALSA] ASoC: core...
2349
  	if (err < 0)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2350
  		return err;
974815ba4   Peter Ujfalusi   ASoC: core: Combi...
2351
2352
  	if (type_2r)
  		err = snd_soc_update_bits_locked(codec, reg2, val_mask, val2);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2353
2354
  	return err;
  }
974815ba4   Peter Ujfalusi   ASoC: core: Combi...
2355
  EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2356

e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
  /**
   * snd_soc_info_volsw_s8 - signed mixer info callback
   * @kcontrol: mixer control
   * @uinfo: control element information
   *
   * Callback to provide information about a signed mixer control.
   *
   * Returns 0 for success.
   */
  int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol,
  	struct snd_ctl_elem_info *uinfo)
  {
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2369
2370
  	struct soc_mixer_control *mc =
  		(struct soc_mixer_control *)kcontrol->private_value;
d11bb4a92   Peter Ujfalusi   ASoC: core: Fix f...
2371
  	int platform_max;
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2372
  	int min = mc->min;
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2373

d11bb4a92   Peter Ujfalusi   ASoC: core: Fix f...
2374
2375
2376
  	if (!mc->platform_max)
  		mc->platform_max = mc->max;
  	platform_max = mc->platform_max;
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2377
2378
2379
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  	uinfo->count = 2;
  	uinfo->value.integer.min = 0;
d11bb4a92   Peter Ujfalusi   ASoC: core: Fix f...
2380
  	uinfo->value.integer.max = platform_max - min;
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2381
2382
2383
2384
2385
2386
2387
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_info_volsw_s8);
  
  /**
   * snd_soc_get_volsw_s8 - signed mixer get callback
   * @kcontrol: mixer control
ac11a2b35   Mark Brown   ASoC: Clean up ke...
2388
   * @ucontrol: control element information
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2389
2390
2391
2392
2393
2394
2395
2396
   *
   * Callback to get the value of a signed mixer control.
   *
   * Returns 0 for success.
   */
  int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
  	struct snd_ctl_elem_value *ucontrol)
  {
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2397
2398
  	struct soc_mixer_control *mc =
  		(struct soc_mixer_control *)kcontrol->private_value;
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2399
  	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
815ecf8de   Jon Smirl   ALSA: ASoC: conve...
2400
  	unsigned int reg = mc->reg;
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2401
  	int min = mc->min;
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
  	int val = snd_soc_read(codec, reg);
  
  	ucontrol->value.integer.value[0] =
  		((signed char)(val & 0xff))-min;
  	ucontrol->value.integer.value[1] =
  		((signed char)((val >> 8) & 0xff))-min;
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_get_volsw_s8);
  
  /**
   * snd_soc_put_volsw_sgn - signed mixer put callback
   * @kcontrol: mixer control
ac11a2b35   Mark Brown   ASoC: Clean up ke...
2415
   * @ucontrol: control element information
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2416
2417
2418
2419
2420
2421
2422
2423
   *
   * Callback to set the value of a signed mixer control.
   *
   * Returns 0 for success.
   */
  int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
  	struct snd_ctl_elem_value *ucontrol)
  {
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2424
2425
  	struct soc_mixer_control *mc =
  		(struct soc_mixer_control *)kcontrol->private_value;
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2426
  	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
815ecf8de   Jon Smirl   ALSA: ASoC: conve...
2427
  	unsigned int reg = mc->reg;
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2428
  	int min = mc->min;
46f5822f7   Daniel Ribeiro   ASoC: Allow 32 bi...
2429
  	unsigned int val;
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2430
2431
2432
  
  	val = (ucontrol->value.integer.value[0]+min) & 0xff;
  	val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8;
6c508c62f   Eero Nurkkala   ASoC: refactor sn...
2433
  	return snd_soc_update_bits_locked(codec, reg, 0xffff, val);
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2434
2435
  }
  EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8);
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2436
  /**
637d3847b   Peter Ujfalusi   ASoC: core: Suppo...
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
   * snd_soc_limit_volume - Set new limit to an existing volume control.
   *
   * @codec: where to look for the control
   * @name: Name of the control
   * @max: new maximum limit
   *
   * Return 0 for success, else error.
   */
  int snd_soc_limit_volume(struct snd_soc_codec *codec,
  	const char *name, int max)
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2448
  	struct snd_card *card = codec->card->snd_card;
637d3847b   Peter Ujfalusi   ASoC: core: Suppo...
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
  	struct snd_kcontrol *kctl;
  	struct soc_mixer_control *mc;
  	int found = 0;
  	int ret = -EINVAL;
  
  	/* Sanity check for name and max */
  	if (unlikely(!name || max <= 0))
  		return -EINVAL;
  
  	list_for_each_entry(kctl, &card->controls, list) {
  		if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) {
  			found = 1;
  			break;
  		}
  	}
  	if (found) {
  		mc = (struct soc_mixer_control *)kctl->private_value;
  		if (max <= mc->max) {
d11bb4a92   Peter Ujfalusi   ASoC: core: Fix f...
2467
  			mc->platform_max = max;
637d3847b   Peter Ujfalusi   ASoC: core: Suppo...
2468
2469
2470
2471
2472
2473
2474
2475
  			ret = 0;
  		}
  	}
  	return ret;
  }
  EXPORT_SYMBOL_GPL(snd_soc_limit_volume);
  
  /**
b6f4bb383   apatard@mandriva.com   ASoC: Add SOC_DOU...
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
   * snd_soc_info_volsw_2r_sx - double with tlv and variable data size
   *  mixer info callback
   * @kcontrol: mixer control
   * @uinfo: control element information
   *
   * Returns 0 for success.
   */
  int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol,
  			struct snd_ctl_elem_info *uinfo)
  {
  	struct soc_mixer_control *mc =
  		(struct soc_mixer_control *)kcontrol->private_value;
  	int max = mc->max;
  	int min = mc->min;
  
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  	uinfo->count = 2;
  	uinfo->value.integer.min = 0;
  	uinfo->value.integer.max = max-min;
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r_sx);
  
  /**
   * snd_soc_get_volsw_2r_sx - double with tlv and variable data size
   *  mixer get callback
   * @kcontrol: mixer control
   * @uinfo: control element information
   *
   * Returns 0 for success.
   */
  int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol,
  			struct snd_ctl_elem_value *ucontrol)
  {
  	struct soc_mixer_control *mc =
  		(struct soc_mixer_control *)kcontrol->private_value;
  	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
  	unsigned int mask = (1<<mc->shift)-1;
  	int min = mc->min;
  	int val = snd_soc_read(codec, mc->reg) & mask;
  	int valr = snd_soc_read(codec, mc->rreg) & mask;
20630c7f5   Stuart Longland   ASoC: Fix overflo...
2518
2519
  	ucontrol->value.integer.value[0] = ((val & 0xff)-min) & mask;
  	ucontrol->value.integer.value[1] = ((valr & 0xff)-min) & mask;
b6f4bb383   apatard@mandriva.com   ASoC: Add SOC_DOU...
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r_sx);
  
  /**
   * snd_soc_put_volsw_2r_sx - double with tlv and variable data size
   *  mixer put callback
   * @kcontrol: mixer control
   * @uinfo: control element information
   *
   * Returns 0 for success.
   */
  int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
  			struct snd_ctl_elem_value *ucontrol)
  {
  	struct soc_mixer_control *mc =
  		(struct soc_mixer_control *)kcontrol->private_value;
  	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
  	unsigned int mask = (1<<mc->shift)-1;
  	int min = mc->min;
  	int ret;
  	unsigned int val, valr, oval, ovalr;
  
  	val = ((ucontrol->value.integer.value[0]+min) & 0xff);
  	val &= mask;
  	valr = ((ucontrol->value.integer.value[1]+min) & 0xff);
  	valr &= mask;
  
  	oval = snd_soc_read(codec, mc->reg) & mask;
  	ovalr = snd_soc_read(codec, mc->rreg) & mask;
  
  	ret = 0;
  	if (oval != val) {
  		ret = snd_soc_write(codec, mc->reg, val);
  		if (ret < 0)
f1df5aec6   Mark Brown   ASoC: Pay attenti...
2555
  			return ret;
b6f4bb383   apatard@mandriva.com   ASoC: Add SOC_DOU...
2556
2557
2558
2559
  	}
  	if (ovalr != valr) {
  		ret = snd_soc_write(codec, mc->rreg, valr);
  		if (ret < 0)
f1df5aec6   Mark Brown   ASoC: Pay attenti...
2560
  			return ret;
b6f4bb383   apatard@mandriva.com   ASoC: Add SOC_DOU...
2561
2562
2563
2564
2565
2566
2567
  	}
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx);
  
  /**
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
   * snd_soc_dai_set_sysclk - configure DAI system or master clock.
   * @dai: DAI
   * @clk_id: DAI specific clock ID
   * @freq: new clock frequency in Hz
   * @dir: new clock direction - input/output.
   *
   * Configures the DAI master (MCLK) or system (SYSCLK) clocking.
   */
  int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
  	unsigned int freq, int dir)
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2579
2580
  	if (dai->driver && dai->driver->ops->set_sysclk)
  		return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
ec4ee52a8   Mark Brown   ASoC: Provide COD...
2581
  	else if (dai->codec && dai->codec->driver->set_sysclk)
da1c6ea6c   Mark Brown   ASoC: Allow sourc...
2582
  		return dai->codec->driver->set_sysclk(dai->codec, clk_id, 0,
ec4ee52a8   Mark Brown   ASoC: Provide COD...
2583
  						      freq, dir);
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2584
2585
2586
2587
2588
2589
  	else
  		return -EINVAL;
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
  
  /**
ec4ee52a8   Mark Brown   ASoC: Provide COD...
2590
2591
2592
   * snd_soc_codec_set_sysclk - configure CODEC system or master clock.
   * @codec: CODEC
   * @clk_id: DAI specific clock ID
da1c6ea6c   Mark Brown   ASoC: Allow sourc...
2593
   * @source: Source for the clock
ec4ee52a8   Mark Brown   ASoC: Provide COD...
2594
2595
2596
2597
2598
2599
   * @freq: new clock frequency in Hz
   * @dir: new clock direction - input/output.
   *
   * Configures the CODEC master (MCLK) or system (SYSCLK) clocking.
   */
  int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id,
da1c6ea6c   Mark Brown   ASoC: Allow sourc...
2600
  			     int source, unsigned int freq, int dir)
ec4ee52a8   Mark Brown   ASoC: Provide COD...
2601
2602
  {
  	if (codec->driver->set_sysclk)
da1c6ea6c   Mark Brown   ASoC: Allow sourc...
2603
2604
  		return codec->driver->set_sysclk(codec, clk_id, source,
  						 freq, dir);
ec4ee52a8   Mark Brown   ASoC: Provide COD...
2605
2606
2607
2608
2609
2610
  	else
  		return -EINVAL;
  }
  EXPORT_SYMBOL_GPL(snd_soc_codec_set_sysclk);
  
  /**
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2611
2612
   * snd_soc_dai_set_clkdiv - configure DAI clock dividers.
   * @dai: DAI
ac11a2b35   Mark Brown   ASoC: Clean up ke...
2613
   * @div_id: DAI specific clock divider ID
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2614
2615
2616
2617
2618
2619
2620
2621
2622
   * @div: new clock divisor.
   *
   * Configures the clock dividers. This is used to derive the best DAI bit and
   * frame clocks from the system or master clock. It's best to set the DAI bit
   * and frame clocks as low as possible to save system power.
   */
  int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
  	int div_id, int div)
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2623
2624
  	if (dai->driver && dai->driver->ops->set_clkdiv)
  		return dai->driver->ops->set_clkdiv(dai, div_id, div);
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2625
2626
2627
2628
2629
2630
2631
2632
2633
  	else
  		return -EINVAL;
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
  
  /**
   * snd_soc_dai_set_pll - configure DAI PLL.
   * @dai: DAI
   * @pll_id: DAI specific PLL ID
85488037b   Mark Brown   ASoC: Add source ...
2634
   * @source: DAI specific source for the PLL
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2635
2636
2637
2638
2639
   * @freq_in: PLL input clock frequency in Hz
   * @freq_out: requested PLL output clock frequency in Hz
   *
   * Configures and enables PLL to generate output clock based on input clock.
   */
85488037b   Mark Brown   ASoC: Add source ...
2640
2641
  int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
  	unsigned int freq_in, unsigned int freq_out)
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2642
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2643
2644
  	if (dai->driver && dai->driver->ops->set_pll)
  		return dai->driver->ops->set_pll(dai, pll_id, source,
85488037b   Mark Brown   ASoC: Add source ...
2645
  					 freq_in, freq_out);
ec4ee52a8   Mark Brown   ASoC: Provide COD...
2646
2647
2648
  	else if (dai->codec && dai->codec->driver->set_pll)
  		return dai->codec->driver->set_pll(dai->codec, pll_id, source,
  						   freq_in, freq_out);
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2649
2650
2651
2652
  	else
  		return -EINVAL;
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
ec4ee52a8   Mark Brown   ASoC: Provide COD...
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
  /*
   * snd_soc_codec_set_pll - configure codec PLL.
   * @codec: CODEC
   * @pll_id: DAI specific PLL ID
   * @source: DAI specific source for the PLL
   * @freq_in: PLL input clock frequency in Hz
   * @freq_out: requested PLL output clock frequency in Hz
   *
   * Configures and enables PLL to generate output clock based on input clock.
   */
  int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
  			  unsigned int freq_in, unsigned int freq_out)
  {
  	if (codec->driver->set_pll)
  		return codec->driver->set_pll(codec, pll_id, source,
  					      freq_in, freq_out);
  	else
  		return -EINVAL;
  }
  EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll);
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2673
2674
2675
  /**
   * snd_soc_dai_set_fmt - configure DAI hardware audio format.
   * @dai: DAI
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2676
2677
2678
2679
2680
2681
   * @fmt: SND_SOC_DAIFMT_ format value.
   *
   * Configures the DAI hardware format and clocking.
   */
  int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2682
2683
  	if (dai->driver && dai->driver->ops->set_fmt)
  		return dai->driver->ops->set_fmt(dai, fmt);
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2684
2685
2686
2687
2688
2689
2690
2691
  	else
  		return -EINVAL;
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
  
  /**
   * snd_soc_dai_set_tdm_slot - configure DAI TDM.
   * @dai: DAI
a5479e389   Daniel Ribeiro   ASoC: change set_...
2692
2693
   * @tx_mask: bitmask representing active TX slots.
   * @rx_mask: bitmask representing active RX slots.
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2694
   * @slots: Number of slots in use.
a5479e389   Daniel Ribeiro   ASoC: change set_...
2695
   * @slot_width: Width in bits for each slot.
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2696
2697
2698
2699
2700
   *
   * Configures a DAI for TDM operation. Both mask and slots are codec and DAI
   * specific.
   */
  int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
a5479e389   Daniel Ribeiro   ASoC: change set_...
2701
  	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2702
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2703
2704
  	if (dai->driver && dai->driver->ops->set_tdm_slot)
  		return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
a5479e389   Daniel Ribeiro   ASoC: change set_...
2705
  				slots, slot_width);
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2706
2707
2708
2709
2710
2711
  	else
  		return -EINVAL;
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
  
  /**
472df3cba   Barry Song   ASoC: Provide API...
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
   * snd_soc_dai_set_channel_map - configure DAI audio channel map
   * @dai: DAI
   * @tx_num: how many TX channels
   * @tx_slot: pointer to an array which imply the TX slot number channel
   *           0~num-1 uses
   * @rx_num: how many RX channels
   * @rx_slot: pointer to an array which imply the RX slot number channel
   *           0~num-1 uses
   *
   * configure the relationship between channel number and TDM slot number.
   */
  int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
  	unsigned int tx_num, unsigned int *tx_slot,
  	unsigned int rx_num, unsigned int *rx_slot)
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2727
2728
  	if (dai->driver && dai->driver->ops->set_channel_map)
  		return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
472df3cba   Barry Song   ASoC: Provide API...
2729
2730
2731
2732
2733
2734
2735
  			rx_num, rx_slot);
  	else
  		return -EINVAL;
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
  
  /**
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2736
2737
2738
2739
2740
2741
2742
2743
   * snd_soc_dai_set_tristate - configure DAI system or master clock.
   * @dai: DAI
   * @tristate: tristate enable
   *
   * Tristates the DAI so that others can use it.
   */
  int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2744
2745
  	if (dai->driver && dai->driver->ops->set_tristate)
  		return dai->driver->ops->set_tristate(dai, tristate);
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
  	else
  		return -EINVAL;
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
  
  /**
   * snd_soc_dai_digital_mute - configure DAI system or master clock.
   * @dai: DAI
   * @mute: mute enable
   *
   * Mutes the DAI DAC.
   */
  int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute)
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2760
2761
  	if (dai->driver && dai->driver->ops->digital_mute)
  		return dai->driver->ops->digital_mute(dai, mute);
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2762
2763
2764
2765
  	else
  		return -EINVAL;
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
c5af3a2e1   Mark Brown   ASoC: Add card re...
2766
2767
2768
  /**
   * snd_soc_register_card - Register a card with the ASoC core
   *
ac11a2b35   Mark Brown   ASoC: Clean up ke...
2769
   * @card: Card to register
c5af3a2e1   Mark Brown   ASoC: Add card re...
2770
   *
c5af3a2e1   Mark Brown   ASoC: Add card re...
2771
   */
70a7ca34d   Vinod Koul   ASoC: soc core al...
2772
  int snd_soc_register_card(struct snd_soc_card *card)
c5af3a2e1   Mark Brown   ASoC: Add card re...
2773
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2774
  	int i;
c5af3a2e1   Mark Brown   ASoC: Add card re...
2775
2776
  	if (!card->name || !card->dev)
  		return -EINVAL;
5a5049637   Stephen Warren   ASoC: Allow DAI l...
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
  	for (i = 0; i < card->num_links; i++) {
  		struct snd_soc_dai_link *link = &card->dai_link[i];
  
  		/*
  		 * Codec must be specified by 1 of name or OF node,
  		 * not both or neither.
  		 */
  		if (!!link->codec_name == !!link->codec_of_node) {
  			dev_err(card->dev,
  				"Neither/both codec name/of_node are set
  ");
  			return -EINVAL;
  		}
  
  		/*
  		 * Platform may be specified by either name or OF node, but
  		 * can be left unspecified, and a dummy platform will be used.
  		 */
  		if (link->platform_name && link->platform_of_node) {
  			dev_err(card->dev,
  				"Both platform name/of_node are set
  ");
  			return -EINVAL;
  		}
  
  		/*
  		 * CPU DAI must be specified by 1 of name or OF node,
  		 * not both or neither.
  		 */
  		if (!!link->cpu_dai_name == !!link->cpu_dai_of_node) {
  			dev_err(card->dev,
  				"Neither/both cpu_dai name/of_node are set
  ");
  			return -EINVAL;
  		}
  	}
ed77cc122   Mark Brown   ASoC: Don't crash...
2813
  	dev_set_drvdata(card->dev, card);
111c6419f   Stephen Warren   ASoC: Move card l...
2814
  	snd_soc_initialize_card_lists(card);
150dd2f8c   Vinod Koul   ASoC: soc core mo...
2815
  	soc_init_card_debugfs(card);
2eea392d0   Jarkko Nikula   ASoC: Add support...
2816
2817
2818
  	card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) *
  			    (card->num_links + card->num_aux_devs),
  			    GFP_KERNEL);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2819
2820
  	if (card->rtd == NULL)
  		return -ENOMEM;
2eea392d0   Jarkko Nikula   ASoC: Add support...
2821
  	card->rtd_aux = &card->rtd[card->num_links];
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2822
2823
2824
  
  	for (i = 0; i < card->num_links; i++)
  		card->rtd[i].dai_link = &card->dai_link[i];
c5af3a2e1   Mark Brown   ASoC: Add card re...
2825
  	INIT_LIST_HEAD(&card->list);
db432b414   Mark Brown   ASoC: Do DAPM pow...
2826
  	INIT_LIST_HEAD(&card->dapm_dirty);
c5af3a2e1   Mark Brown   ASoC: Add card re...
2827
  	card->instantiated = 0;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2828
  	mutex_init(&card->mutex);
c5af3a2e1   Mark Brown   ASoC: Add card re...
2829
2830
2831
  
  	mutex_lock(&client_mutex);
  	list_add(&card->list, &card_list);
435c5e258   Mark Brown   ASoC: Initial fra...
2832
  	snd_soc_instantiate_cards();
c5af3a2e1   Mark Brown   ASoC: Add card re...
2833
2834
2835
2836
2837
2838
2839
  	mutex_unlock(&client_mutex);
  
  	dev_dbg(card->dev, "Registered card '%s'
  ", card->name);
  
  	return 0;
  }
70a7ca34d   Vinod Koul   ASoC: soc core al...
2840
  EXPORT_SYMBOL_GPL(snd_soc_register_card);
c5af3a2e1   Mark Brown   ASoC: Add card re...
2841
2842
2843
2844
  
  /**
   * snd_soc_unregister_card - Unregister a card with the ASoC core
   *
ac11a2b35   Mark Brown   ASoC: Clean up ke...
2845
   * @card: Card to unregister
c5af3a2e1   Mark Brown   ASoC: Add card re...
2846
   *
c5af3a2e1   Mark Brown   ASoC: Add card re...
2847
   */
70a7ca34d   Vinod Koul   ASoC: soc core al...
2848
  int snd_soc_unregister_card(struct snd_soc_card *card)
c5af3a2e1   Mark Brown   ASoC: Add card re...
2849
  {
b0e264855   Vinod Koul   ASoC: soc core mo...
2850
2851
  	if (card->instantiated)
  		soc_cleanup_card_resources(card);
c5af3a2e1   Mark Brown   ASoC: Add card re...
2852
2853
2854
  	mutex_lock(&client_mutex);
  	list_del(&card->list);
  	mutex_unlock(&client_mutex);
c5af3a2e1   Mark Brown   ASoC: Add card re...
2855
2856
2857
2858
2859
  	dev_dbg(card->dev, "Unregistered card '%s'
  ", card->name);
  
  	return 0;
  }
70a7ca34d   Vinod Koul   ASoC: soc core al...
2860
  EXPORT_SYMBOL_GPL(snd_soc_unregister_card);
c5af3a2e1   Mark Brown   ASoC: Add card re...
2861

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2862
2863
2864
2865
  /*
   * Simplify DAI link configuration by removing ".-1" from device names
   * and sanitizing names.
   */
0b9a214a6   Dimitris Papastamos   ASoC: soc-core: R...
2866
  static char *fmt_single_name(struct device *dev, int *id)
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2867
2868
2869
2870
2871
2872
  {
  	char *found, name[NAME_SIZE];
  	int id1, id2;
  
  	if (dev_name(dev) == NULL)
  		return NULL;
58818a77c   Dimitris Papastamos   ASoC: soc-core: R...
2873
  	strlcpy(name, dev_name(dev), NAME_SIZE);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
  
  	/* are we a "%s.%d" name (platform and SPI components) */
  	found = strstr(name, dev->driver->name);
  	if (found) {
  		/* get ID */
  		if (sscanf(&found[strlen(dev->driver->name)], ".%d", id) == 1) {
  
  			/* discard ID from name if ID == -1 */
  			if (*id == -1)
  				found[strlen(dev->driver->name)] = '\0';
  		}
  
  	} else {
  		/* I2C component devices are named "bus-addr"  */
  		if (sscanf(name, "%x-%x", &id1, &id2) == 2) {
  			char tmp[NAME_SIZE];
  
  			/* create unique ID number from I2C addr and bus */
058994466   Jarkko Nikula   ASoC: Fix I2C com...
2892
  			*id = ((id1 & 0xffff) << 16) + id2;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2893
2894
2895
  
  			/* sanitize component name for DAI link creation */
  			snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, name);
58818a77c   Dimitris Papastamos   ASoC: soc-core: R...
2896
  			strlcpy(name, tmp, NAME_SIZE);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
  		} else
  			*id = 0;
  	}
  
  	return kstrdup(name, GFP_KERNEL);
  }
  
  /*
   * Simplify DAI link naming for single devices with multiple DAIs by removing
   * any ".-1" and using the DAI name (instead of device name).
   */
  static inline char *fmt_multiple_name(struct device *dev,
  		struct snd_soc_dai_driver *dai_drv)
  {
  	if (dai_drv->name == NULL) {
  		printk(KERN_ERR "asoc: error - multiple DAI %s registered with no name
  ",
  				dev_name(dev));
  		return NULL;
  	}
  
  	return kstrdup(dai_drv->name, GFP_KERNEL);
  }
9115171a6   Mark Brown   ASoC: Add DAI reg...
2920
2921
2922
  /**
   * snd_soc_register_dai - Register a DAI with the ASoC core
   *
ac11a2b35   Mark Brown   ASoC: Clean up ke...
2923
   * @dai: DAI to register
9115171a6   Mark Brown   ASoC: Add DAI reg...
2924
   */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2925
2926
  int snd_soc_register_dai(struct device *dev,
  		struct snd_soc_dai_driver *dai_drv)
9115171a6   Mark Brown   ASoC: Add DAI reg...
2927
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2928
2929
2930
2931
  	struct snd_soc_dai *dai;
  
  	dev_dbg(dev, "dai register %s
  ", dev_name(dev));
9115171a6   Mark Brown   ASoC: Add DAI reg...
2932

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2933
2934
  	dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
  	if (dai == NULL)
a73936236   Lu Guanqun   ASoC: fix two ide...
2935
  		return -ENOMEM;
9115171a6   Mark Brown   ASoC: Add DAI reg...
2936

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2937
2938
2939
2940
2941
2942
  	/* create DAI component name */
  	dai->name = fmt_single_name(dev, &dai->id);
  	if (dai->name == NULL) {
  		kfree(dai);
  		return -ENOMEM;
  	}
6335d0554   Eric Miao   ASoC: make ops a ...
2943

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2944
2945
2946
2947
  	dai->dev = dev;
  	dai->driver = dai_drv;
  	if (!dai->driver->ops)
  		dai->driver->ops = &null_dai_ops;
9115171a6   Mark Brown   ASoC: Add DAI reg...
2948
2949
2950
  
  	mutex_lock(&client_mutex);
  	list_add(&dai->list, &dai_list);
435c5e258   Mark Brown   ASoC: Initial fra...
2951
  	snd_soc_instantiate_cards();
9115171a6   Mark Brown   ASoC: Add DAI reg...
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
  	mutex_unlock(&client_mutex);
  
  	pr_debug("Registered DAI '%s'
  ", dai->name);
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_register_dai);
  
  /**
   * snd_soc_unregister_dai - Unregister a DAI from the ASoC core
   *
ac11a2b35   Mark Brown   ASoC: Clean up ke...
2964
   * @dai: DAI to unregister
9115171a6   Mark Brown   ASoC: Add DAI reg...
2965
   */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2966
  void snd_soc_unregister_dai(struct device *dev)
9115171a6   Mark Brown   ASoC: Add DAI reg...
2967
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2968
2969
2970
2971
2972
2973
2974
2975
2976
  	struct snd_soc_dai *dai;
  
  	list_for_each_entry(dai, &dai_list, list) {
  		if (dev == dai->dev)
  			goto found;
  	}
  	return;
  
  found:
9115171a6   Mark Brown   ASoC: Add DAI reg...
2977
2978
2979
2980
2981
2982
  	mutex_lock(&client_mutex);
  	list_del(&dai->list);
  	mutex_unlock(&client_mutex);
  
  	pr_debug("Unregistered DAI '%s'
  ", dai->name);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2983
2984
  	kfree(dai->name);
  	kfree(dai);
9115171a6   Mark Brown   ASoC: Add DAI reg...
2985
2986
2987
2988
2989
2990
  }
  EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
  
  /**
   * snd_soc_register_dais - Register multiple DAIs with the ASoC core
   *
ac11a2b35   Mark Brown   ASoC: Clean up ke...
2991
2992
   * @dai: Array of DAIs to register
   * @count: Number of DAIs
9115171a6   Mark Brown   ASoC: Add DAI reg...
2993
   */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2994
2995
  int snd_soc_register_dais(struct device *dev,
  		struct snd_soc_dai_driver *dai_drv, size_t count)
9115171a6   Mark Brown   ASoC: Add DAI reg...
2996
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2997
2998
  	struct snd_soc_dai *dai;
  	int i, ret = 0;
720ffa4cf   Liam Girdwood   ASoC: core - fix ...
2999
3000
  	dev_dbg(dev, "dai register %s #%Zu
  ", dev_name(dev), count);
9115171a6   Mark Brown   ASoC: Add DAI reg...
3001
3002
  
  	for (i = 0; i < count; i++) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3003
3004
  
  		dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
c46e0079c   Axel Lin   ASoC: Fix snd_soc...
3005
3006
3007
3008
  		if (dai == NULL) {
  			ret = -ENOMEM;
  			goto err;
  		}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3009
3010
3011
3012
3013
3014
  
  		/* create DAI component name */
  		dai->name = fmt_multiple_name(dev, &dai_drv[i]);
  		if (dai->name == NULL) {
  			kfree(dai);
  			ret = -EINVAL;
9115171a6   Mark Brown   ASoC: Add DAI reg...
3015
  			goto err;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3016
3017
3018
  		}
  
  		dai->dev = dev;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3019
  		dai->driver = &dai_drv[i];
0f9141c97   Mark Brown   ASoC: Pay attenti...
3020
3021
3022
3023
  		if (dai->driver->id)
  			dai->id = dai->driver->id;
  		else
  			dai->id = i;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3024
3025
3026
3027
3028
3029
3030
3031
3032
  		if (!dai->driver->ops)
  			dai->driver->ops = &null_dai_ops;
  
  		mutex_lock(&client_mutex);
  		list_add(&dai->list, &dai_list);
  		mutex_unlock(&client_mutex);
  
  		pr_debug("Registered DAI '%s'
  ", dai->name);
9115171a6   Mark Brown   ASoC: Add DAI reg...
3033
  	}
1dcb4f38e   Axel Lin   ASoC: Hold client...
3034
  	mutex_lock(&client_mutex);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3035
  	snd_soc_instantiate_cards();
1dcb4f38e   Axel Lin   ASoC: Hold client...
3036
  	mutex_unlock(&client_mutex);
9115171a6   Mark Brown   ASoC: Add DAI reg...
3037
3038
3039
3040
  	return 0;
  
  err:
  	for (i--; i >= 0; i--)
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3041
  		snd_soc_unregister_dai(dev);
9115171a6   Mark Brown   ASoC: Add DAI reg...
3042
3043
3044
3045
3046
3047
3048
3049
  
  	return ret;
  }
  EXPORT_SYMBOL_GPL(snd_soc_register_dais);
  
  /**
   * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core
   *
ac11a2b35   Mark Brown   ASoC: Clean up ke...
3050
3051
   * @dai: Array of DAIs to unregister
   * @count: Number of DAIs
9115171a6   Mark Brown   ASoC: Add DAI reg...
3052
   */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3053
  void snd_soc_unregister_dais(struct device *dev, size_t count)
9115171a6   Mark Brown   ASoC: Add DAI reg...
3054
3055
3056
3057
  {
  	int i;
  
  	for (i = 0; i < count; i++)
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3058
  		snd_soc_unregister_dai(dev);
9115171a6   Mark Brown   ASoC: Add DAI reg...
3059
3060
  }
  EXPORT_SYMBOL_GPL(snd_soc_unregister_dais);
12a48a8c0   Mark Brown   ASoC: Add platfor...
3061
3062
3063
  /**
   * snd_soc_register_platform - Register a platform with the ASoC core
   *
ac11a2b35   Mark Brown   ASoC: Clean up ke...
3064
   * @platform: platform to register
12a48a8c0   Mark Brown   ASoC: Add platfor...
3065
   */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3066
3067
  int snd_soc_register_platform(struct device *dev,
  		struct snd_soc_platform_driver *platform_drv)
12a48a8c0   Mark Brown   ASoC: Add platfor...
3068
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3069
3070
3071
3072
3073
3074
3075
  	struct snd_soc_platform *platform;
  
  	dev_dbg(dev, "platform register %s
  ", dev_name(dev));
  
  	platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);
  	if (platform == NULL)
a73936236   Lu Guanqun   ASoC: fix two ide...
3076
  		return -ENOMEM;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3077
3078
3079
3080
3081
3082
3083
  
  	/* create platform component name */
  	platform->name = fmt_single_name(dev, &platform->id);
  	if (platform->name == NULL) {
  		kfree(platform);
  		return -ENOMEM;
  	}
12a48a8c0   Mark Brown   ASoC: Add platfor...
3084

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3085
3086
  	platform->dev = dev;
  	platform->driver = platform_drv;
b79506413   Liam Girdwood   ASoC: core - Add ...
3087
3088
  	platform->dapm.dev = dev;
  	platform->dapm.platform = platform;
64a648c22   Liam Girdwood   ASoC: dapm - Add ...
3089
  	platform->dapm.stream_event = platform_drv->stream_event;
12a48a8c0   Mark Brown   ASoC: Add platfor...
3090
3091
3092
  
  	mutex_lock(&client_mutex);
  	list_add(&platform->list, &platform_list);
435c5e258   Mark Brown   ASoC: Initial fra...
3093
  	snd_soc_instantiate_cards();
12a48a8c0   Mark Brown   ASoC: Add platfor...
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
  	mutex_unlock(&client_mutex);
  
  	pr_debug("Registered platform '%s'
  ", platform->name);
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_register_platform);
  
  /**
   * snd_soc_unregister_platform - Unregister a platform from the ASoC core
   *
ac11a2b35   Mark Brown   ASoC: Clean up ke...
3106
   * @platform: platform to unregister
12a48a8c0   Mark Brown   ASoC: Add platfor...
3107
   */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3108
  void snd_soc_unregister_platform(struct device *dev)
12a48a8c0   Mark Brown   ASoC: Add platfor...
3109
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3110
3111
3112
3113
3114
3115
3116
3117
3118
  	struct snd_soc_platform *platform;
  
  	list_for_each_entry(platform, &platform_list, list) {
  		if (dev == platform->dev)
  			goto found;
  	}
  	return;
  
  found:
12a48a8c0   Mark Brown   ASoC: Add platfor...
3119
3120
3121
3122
3123
3124
  	mutex_lock(&client_mutex);
  	list_del(&platform->list);
  	mutex_unlock(&client_mutex);
  
  	pr_debug("Unregistered platform '%s'
  ", platform->name);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3125
3126
  	kfree(platform->name);
  	kfree(platform);
12a48a8c0   Mark Brown   ASoC: Add platfor...
3127
3128
  }
  EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
151ab22cf   Mark Brown   ASoC: Fix up CODE...
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
  static u64 codec_format_map[] = {
  	SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE,
  	SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE,
  	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE,
  	SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE,
  	SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE,
  	SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE,
  	SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3BE,
  	SNDRV_PCM_FMTBIT_U24_3LE | SNDRV_PCM_FMTBIT_U24_3BE,
  	SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE,
  	SNDRV_PCM_FMTBIT_U20_3LE | SNDRV_PCM_FMTBIT_U20_3BE,
  	SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE,
  	SNDRV_PCM_FMTBIT_U18_3LE | SNDRV_PCM_FMTBIT_U18_3BE,
  	SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE,
  	SNDRV_PCM_FMTBIT_FLOAT64_LE | SNDRV_PCM_FMTBIT_FLOAT64_BE,
  	SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE
  	| SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE,
  };
  
  /* Fix up the DAI formats for endianness: codecs don't actually see
   * the endianness of the data but we're using the CPU format
   * definitions which do need to include endianness so we ensure that
   * codec DAIs always have both big and little endian variants set.
   */
  static void fixup_codec_formats(struct snd_soc_pcm_stream *stream)
  {
  	int i;
  
  	for (i = 0; i < ARRAY_SIZE(codec_format_map); i++)
  		if (stream->formats & codec_format_map[i])
  			stream->formats |= codec_format_map[i];
  }
0d0cf00a7   Mark Brown   ASoC: Add codec r...
3161
3162
3163
  /**
   * snd_soc_register_codec - Register a codec with the ASoC core
   *
ac11a2b35   Mark Brown   ASoC: Clean up ke...
3164
   * @codec: codec to register
0d0cf00a7   Mark Brown   ASoC: Add codec r...
3165
   */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3166
  int snd_soc_register_codec(struct device *dev,
001ae4c03   Mark Brown   ASoC: Constify st...
3167
3168
3169
  			   const struct snd_soc_codec_driver *codec_drv,
  			   struct snd_soc_dai_driver *dai_drv,
  			   int num_dai)
0d0cf00a7   Mark Brown   ASoC: Add codec r...
3170
  {
3335ddca9   Dimitris Papastamos   ASoC: soc-cache: ...
3171
  	size_t reg_size;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3172
3173
  	struct snd_soc_codec *codec;
  	int ret, i;
151ab22cf   Mark Brown   ASoC: Fix up CODE...
3174

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3175
3176
3177
3178
3179
3180
  	dev_dbg(dev, "codec register %s
  ", dev_name(dev));
  
  	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
  	if (codec == NULL)
  		return -ENOMEM;
0d0cf00a7   Mark Brown   ASoC: Add codec r...
3181

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3182
3183
3184
3185
3186
3187
  	/* create CODEC component name */
  	codec->name = fmt_single_name(dev, &codec->id);
  	if (codec->name == NULL) {
  		kfree(codec);
  		return -ENOMEM;
  	}
23bbce34f   Dimitris Papastamos   ASoC: Add compres...
3188
3189
3190
3191
  	if (codec_drv->compress_type)
  		codec->compress_type = codec_drv->compress_type;
  	else
  		codec->compress_type = SND_SOC_FLAT_COMPRESSION;
c3acec267   Mark Brown   ASoC: Move active...
3192
3193
  	codec->write = codec_drv->write;
  	codec->read = codec_drv->read;
1500b7b5f   Dimitris Papastamos   ASoC: Automatical...
3194
3195
  	codec->volatile_register = codec_drv->volatile_register;
  	codec->readable_register = codec_drv->readable_register;
8020454c9   Dimitris Papastamos   ASoC: Add default...
3196
  	codec->writable_register = codec_drv->writable_register;
ce6120cca   Liam Girdwood   ASoC: Decouple DA...
3197
3198
3199
  	codec->dapm.bias_level = SND_SOC_BIAS_OFF;
  	codec->dapm.dev = dev;
  	codec->dapm.codec = codec;
474b62d6e   Mark Brown   ASoC: Provide per...
3200
  	codec->dapm.seq_notifier = codec_drv->seq_notifier;
64a648c22   Liam Girdwood   ASoC: dapm - Add ...
3201
  	codec->dapm.stream_event = codec_drv->stream_event;
7a30a3db3   Dimitris Papastamos   ASoC: soc-cache: ...
3202
3203
3204
3205
  	codec->dev = dev;
  	codec->driver = codec_drv;
  	codec->num_dai = num_dai;
  	mutex_init(&codec->mutex);
ce6120cca   Liam Girdwood   ASoC: Decouple DA...
3206

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3207
3208
  	/* allocate CODEC register cache */
  	if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
3335ddca9   Dimitris Papastamos   ASoC: soc-cache: ...
3209
  		reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
aea170a09   Dimitris Papastamos   ASoC: soc-cache: ...
3210
  		codec->reg_size = reg_size;
3335ddca9   Dimitris Papastamos   ASoC: soc-cache: ...
3211
3212
3213
3214
3215
3216
  		/* it is necessary to make a copy of the default register cache
  		 * because in the case of using a compression type that requires
  		 * the default register cache to be marked as __devinitconst the
  		 * kernel might have freed the array by the time we initialize
  		 * the cache.
  		 */
2aa86323d   Dimitris Papastamos   ASoC: soc-core: A...
3217
3218
3219
3220
3221
3222
3223
  		if (codec_drv->reg_cache_default) {
  			codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default,
  						      reg_size, GFP_KERNEL);
  			if (!codec->reg_def_copy) {
  				ret = -ENOMEM;
  				goto fail;
  			}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3224
  		}
151ab22cf   Mark Brown   ASoC: Fix up CODE...
3225
  	}
1500b7b5f   Dimitris Papastamos   ASoC: Automatical...
3226
3227
3228
3229
3230
  	if (codec_drv->reg_access_size && codec_drv->reg_access_default) {
  		if (!codec->volatile_register)
  			codec->volatile_register = snd_soc_default_volatile_register;
  		if (!codec->readable_register)
  			codec->readable_register = snd_soc_default_readable_register;
8020454c9   Dimitris Papastamos   ASoC: Add default...
3231
3232
  		if (!codec->writable_register)
  			codec->writable_register = snd_soc_default_writable_register;
1500b7b5f   Dimitris Papastamos   ASoC: Automatical...
3233
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3234
3235
3236
3237
  	for (i = 0; i < num_dai; i++) {
  		fixup_codec_formats(&dai_drv[i].playback);
  		fixup_codec_formats(&dai_drv[i].capture);
  	}
26b01ccdc   Mark Brown   ASoC: Don't call ...
3238
3239
3240
3241
  	/* register any DAIs */
  	if (num_dai) {
  		ret = snd_soc_register_dais(dev, dai_drv, num_dai);
  		if (ret < 0)
fdf0f54da   Dimitris Papastamos   ASoC: soc-core: A...
3242
  			goto fail;
26b01ccdc   Mark Brown   ASoC: Don't call ...
3243
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3244

0d0cf00a7   Mark Brown   ASoC: Add codec r...
3245
3246
3247
3248
3249
3250
3251
  	mutex_lock(&client_mutex);
  	list_add(&codec->list, &codec_list);
  	snd_soc_instantiate_cards();
  	mutex_unlock(&client_mutex);
  
  	pr_debug("Registered codec '%s'
  ", codec->name);
0d0cf00a7   Mark Brown   ASoC: Add codec r...
3252
  	return 0;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3253

fdf0f54da   Dimitris Papastamos   ASoC: soc-core: A...
3254
  fail:
3335ddca9   Dimitris Papastamos   ASoC: soc-cache: ...
3255
3256
  	kfree(codec->reg_def_copy);
  	codec->reg_def_copy = NULL;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3257
3258
3259
  	kfree(codec->name);
  	kfree(codec);
  	return ret;
0d0cf00a7   Mark Brown   ASoC: Add codec r...
3260
3261
3262
3263
3264
3265
  }
  EXPORT_SYMBOL_GPL(snd_soc_register_codec);
  
  /**
   * snd_soc_unregister_codec - Unregister a codec from the ASoC core
   *
ac11a2b35   Mark Brown   ASoC: Clean up ke...
3266
   * @codec: codec to unregister
0d0cf00a7   Mark Brown   ASoC: Add codec r...
3267
   */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3268
  void snd_soc_unregister_codec(struct device *dev)
0d0cf00a7   Mark Brown   ASoC: Add codec r...
3269
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
  	struct snd_soc_codec *codec;
  	int i;
  
  	list_for_each_entry(codec, &codec_list, list) {
  		if (dev == codec->dev)
  			goto found;
  	}
  	return;
  
  found:
26b01ccdc   Mark Brown   ASoC: Don't call ...
3280
3281
3282
  	if (codec->num_dai)
  		for (i = 0; i < codec->num_dai; i++)
  			snd_soc_unregister_dai(dev);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3283

0d0cf00a7   Mark Brown   ASoC: Add codec r...
3284
3285
3286
3287
3288
3289
  	mutex_lock(&client_mutex);
  	list_del(&codec->list);
  	mutex_unlock(&client_mutex);
  
  	pr_debug("Unregistered codec '%s'
  ", codec->name);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3290

7a30a3db3   Dimitris Papastamos   ASoC: soc-cache: ...
3291
  	snd_soc_cache_exit(codec);
3335ddca9   Dimitris Papastamos   ASoC: soc-cache: ...
3292
  	kfree(codec->reg_def_copy);
1aafcd4d6   Dimitris Papastamos   ASoC: soc-core: F...
3293
  	kfree(codec->name);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3294
  	kfree(codec);
0d0cf00a7   Mark Brown   ASoC: Add codec r...
3295
3296
  }
  EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
bec4fa05e   Stephen Warren   ASoC: Add utility...
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
  /* Retrieve a card's name from device tree */
  int snd_soc_of_parse_card_name(struct snd_soc_card *card,
  			       const char *propname)
  {
  	struct device_node *np = card->dev->of_node;
  	int ret;
  
  	ret = of_property_read_string_index(np, propname, 0, &card->name);
  	/*
  	 * EINVAL means the property does not exist. This is fine providing
  	 * card->name was previously set, which is checked later in
  	 * snd_soc_register_card.
  	 */
  	if (ret < 0 && ret != -EINVAL) {
  		dev_err(card->dev,
  			"Property '%s' could not be read: %d
  ",
  			propname, ret);
  		return ret;
  	}
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name);
a4a54dd5b   Stephen Warren   ASoC: Add utility...
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
  int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
  				   const char *propname)
  {
  	struct device_node *np = card->dev->of_node;
  	int num_routes;
  	struct snd_soc_dapm_route *routes;
  	int i, ret;
  
  	num_routes = of_property_count_strings(np, propname);
  	if (num_routes & 1) {
  		dev_err(card->dev,
  			"Property '%s's length is not even
  ",
  			propname);
  		return -EINVAL;
  	}
  	num_routes /= 2;
  	if (!num_routes) {
  		dev_err(card->dev,
  			"Property '%s's length is zero
  ",
  			propname);
  		return -EINVAL;
  	}
  
  	routes = devm_kzalloc(card->dev, num_routes * sizeof(*routes),
  			      GFP_KERNEL);
  	if (!routes) {
  		dev_err(card->dev,
  			"Could not allocate DAPM route table
  ");
  		return -EINVAL;
  	}
  
  	for (i = 0; i < num_routes; i++) {
  		ret = of_property_read_string_index(np, propname,
  			2 * i, &routes[i].sink);
  		if (ret) {
  			dev_err(card->dev,
  				"Property '%s' index %d could not be read: %d
  ",
  				propname, 2 * i, ret);
  			return -EINVAL;
  		}
  		ret = of_property_read_string_index(np, propname,
  			(2 * i) + 1, &routes[i].source);
  		if (ret) {
  			dev_err(card->dev,
  				"Property '%s' index %d could not be read: %d
  ",
  				propname, (2 * i) + 1, ret);
  			return -EINVAL;
  		}
  	}
  
  	card->num_dapm_routes = num_routes;
  	card->dapm_routes = routes;
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing);
c9b3a40ff   Takashi Iwai   ALSA: ASoC - Fix ...
3382
  static int __init snd_soc_init(void)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
3383
  {
384c89e2e   Mark Brown   ASoC: Push debugf...
3384
  #ifdef CONFIG_DEBUG_FS
8a9dab1a5   Mark Brown   ASoC: Update name...
3385
3386
  	snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL);
  	if (IS_ERR(snd_soc_debugfs_root) || !snd_soc_debugfs_root) {
384c89e2e   Mark Brown   ASoC: Push debugf...
3387
3388
3389
  		printk(KERN_WARNING
  		       "ASoC: Failed to create debugfs directory
  ");
8a9dab1a5   Mark Brown   ASoC: Update name...
3390
  		snd_soc_debugfs_root = NULL;
384c89e2e   Mark Brown   ASoC: Push debugf...
3391
  	}
c3c5a19a5   Mark Brown   ASoC: Add debugfs...
3392

8a9dab1a5   Mark Brown   ASoC: Update name...
3393
  	if (!debugfs_create_file("codecs", 0444, snd_soc_debugfs_root, NULL,
c3c5a19a5   Mark Brown   ASoC: Add debugfs...
3394
3395
3396
  				 &codec_list_fops))
  		pr_warn("ASoC: Failed to create CODEC list debugfs file
  ");
8a9dab1a5   Mark Brown   ASoC: Update name...
3397
  	if (!debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL,
f32087803   Mark Brown   ASoC: Add DAI lis...
3398
3399
3400
  				 &dai_list_fops))
  		pr_warn("ASoC: Failed to create DAI list debugfs file
  ");
19c7ac27a   Mark Brown   ASoC: Add platfor...
3401

8a9dab1a5   Mark Brown   ASoC: Update name...
3402
  	if (!debugfs_create_file("platforms", 0444, snd_soc_debugfs_root, NULL,
19c7ac27a   Mark Brown   ASoC: Add platfor...
3403
3404
3405
  				 &platform_list_fops))
  		pr_warn("ASoC: Failed to create platform list debugfs file
  ");
384c89e2e   Mark Brown   ASoC: Push debugf...
3406
  #endif
fb257897b   Mark Brown   ASoC: Work around...
3407
  	snd_soc_util_init();
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
3408
3409
  	return platform_driver_register(&soc_driver);
  }
4abe8e16a   Mark Brown   ASoC: Move soc-co...
3410
  module_init(snd_soc_init);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
3411

7d8c16a6f   Mark Brown   ASoC: Annotate co...
3412
  static void __exit snd_soc_exit(void)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
3413
  {
fb257897b   Mark Brown   ASoC: Work around...
3414
  	snd_soc_util_exit();
384c89e2e   Mark Brown   ASoC: Push debugf...
3415
  #ifdef CONFIG_DEBUG_FS
8a9dab1a5   Mark Brown   ASoC: Update name...
3416
  	debugfs_remove_recursive(snd_soc_debugfs_root);
384c89e2e   Mark Brown   ASoC: Push debugf...
3417
  #endif
3ff3f64ba   Mark Brown   [ALSA] ASoC: core...
3418
  	platform_driver_unregister(&soc_driver);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
3419
  }
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
3420
3421
3422
  module_exit(snd_soc_exit);
  
  /* Module information */
d331124dc   Liam Girdwood   ALSA: ASoC: updat...
3423
  MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
3424
3425
  MODULE_DESCRIPTION("ALSA SoC Core");
  MODULE_LICENSE("GPL");
8b45a2099   Kay Sievers   [ALSA] sound: fix...
3426
  MODULE_ALIAS("platform:soc-audio");