Blame view

sound/soc/soc-core.c 86.1 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>
5a0e3ad6a   Tejun Heo   include cleanup: ...
33
  #include <linux/slab.h>
474828a40   Marek Vasut   ALSA: Allow passi...
34
  #include <sound/ac97_codec.h>
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
35
  #include <sound/core.h>
3028eb8c5   Mark Brown   ASoC: Add trace e...
36
  #include <sound/jack.h>
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
37
38
39
  #include <sound/pcm.h>
  #include <sound/pcm_params.h>
  #include <sound/soc.h>
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
40
  #include <sound/initval.h>
a8b1d34f3   Mark Brown   ASoC: Add trace e...
41
42
  #define CREATE_TRACE_POINTS
  #include <trace/events/asoc.h>
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
43
  #define NAME_SIZE	32
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
44
  static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq);
384c89e2e   Mark Brown   ASoC: Push debugf...
45
  #ifdef CONFIG_DEBUG_FS
8a9dab1a5   Mark Brown   ASoC: Update name...
46
47
  struct dentry *snd_soc_debugfs_root;
  EXPORT_SYMBOL_GPL(snd_soc_debugfs_root);
384c89e2e   Mark Brown   ASoC: Push debugf...
48
  #endif
c5af3a2e1   Mark Brown   ASoC: Add card re...
49
50
  static DEFINE_MUTEX(client_mutex);
  static LIST_HEAD(card_list);
9115171a6   Mark Brown   ASoC: Add DAI reg...
51
  static LIST_HEAD(dai_list);
12a48a8c0   Mark Brown   ASoC: Add platfor...
52
  static LIST_HEAD(platform_list);
0d0cf00a7   Mark Brown   ASoC: Add codec r...
53
  static LIST_HEAD(codec_list);
c5af3a2e1   Mark Brown   ASoC: Add card re...
54

ddee627cf   Liam Girdwood   ASoC: core - Sepa...
55
  int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
  	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;
  
  	ret = snd_soc_read(codec , reg);
  	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 ...
119
  /* codec register dump */
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
120
121
  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 ...
122
  {
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
123
  	int i, step = 1;
2bc9a81e2   Dimitris Papastamos   ASoC: soc-core: E...
124
  	int wordsize, regsize;
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
125
126
127
  	int len;
  	size_t total = 0;
  	loff_t p = 0;
2bc9a81e2   Dimitris Papastamos   ASoC: soc-core: E...
128

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

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

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
138
  	for (i = 0; i < codec->driver->reg_cache_size; i += step) {
1500b7b5f   Dimitris Papastamos   ASoC: Automatical...
139
  		if (codec->readable_register && !codec->readable_register(codec, i))
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
140
  			continue;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
141
142
  		if (codec->driver->display_register) {
  			count += codec->driver->display_register(codec, buf + count,
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
143
  							 PAGE_SIZE - count, i);
5164d74d7   Mark Brown   ASoC: Handle read...
144
  		} else {
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
145
146
147
148
149
150
151
152
153
  			/* 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...
154
  		}
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
155
  	}
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
156
  	total = min(total, count - 1);
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
157

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

2624d5fa6   Mark Brown   ASoC: Move sysfs ...
161
162
163
  static ssize_t codec_reg_show(struct device *dev,
  	struct device_attribute *attr, char *buf)
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
164
165
  	struct snd_soc_pcm_runtime *rtd =
  			container_of(dev, struct snd_soc_pcm_runtime, dev);
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
166
  	return soc_codec_reg_show(rtd->codec, buf, PAGE_SIZE, 0);
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
167
168
169
  }
  
  static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
dbe21408b   Mark Brown   ASoC: Make pmdown...
170
171
172
  static ssize_t pmdown_time_show(struct device *dev,
  				struct device_attribute *attr, char *buf)
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
173
174
  	struct snd_soc_pcm_runtime *rtd =
  			container_of(dev, struct snd_soc_pcm_runtime, dev);
dbe21408b   Mark Brown   ASoC: Make pmdown...
175

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

c593b520c   Mark Brown   ASoC: Check retur...
188
189
190
  	ret = strict_strtol(buf, 10, &rtd->pmdown_time);
  	if (ret)
  		return ret;
dbe21408b   Mark Brown   ASoC: Make pmdown...
191
192
193
194
195
  
  	return count;
  }
  
  static DEVICE_ATTR(pmdown_time, 0644, pmdown_time_show, pmdown_time_set);
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
196
197
198
199
200
201
202
203
  #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...
204
  				   size_t count, loff_t *ppos)
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
205
206
207
  {
  	ssize_t ret;
  	struct snd_soc_codec *codec = file->private_data;
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
208
209
210
211
212
213
  	char *buf;
  
  	if (*ppos < 0 || !count)
  		return -EINVAL;
  
  	buf = kmalloc(count, GFP_KERNEL);
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
214
215
  	if (!buf)
  		return -ENOMEM;
13fd179f1   Dimitris Papastamos   ASoC: soc-core: S...
216
217
218
219
220
221
222
223
224
  
  	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 ...
225
226
227
228
229
230
231
232
  	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...
233
  	size_t buf_size;
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
234
235
236
237
238
239
240
241
242
  	char *start = buf;
  	unsigned long reg, value;
  	int step = 1;
  	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;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
243
244
  	if (codec->driver->reg_cache_step)
  		step = codec->driver->reg_cache_step;
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
245
246
247
248
  
  	while (*start == ' ')
  		start++;
  	reg = simple_strtoul(start, &start, 16);
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
249
250
251
252
  	while (*start == ' ')
  		start++;
  	if (strict_strtoul(start, 16, &value))
  		return -EINVAL;
0d51a9cbb   Mark Brown   ASoC: Taint the k...
253
254
255
  
  	/* Userspace has been fiddling around behind the kernel's back */
  	add_taint(TAINT_USER);
e4f078d8c   Dimitris Papastamos   ASoC: soc-core: F...
256
  	snd_soc_write(codec, reg, value);
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
257
258
259
260
261
262
263
  	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...
264
  	.llseek = default_llseek,
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
265
266
267
268
  };
  
  static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
  {
d6ce4cf39   Jarkko Nikula   ASoC: Move codec ...
269
270
271
272
  	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 ...
273
274
275
276
277
278
  	if (!codec->debugfs_codec_root) {
  		printk(KERN_WARNING
  		       "ASoC: Failed to create codec debugfs directory
  ");
  		return;
  	}
aaee8ef14   Mark Brown   ASoC: Make cache ...
279
280
281
282
  	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 ...
283
284
285
286
287
288
289
  	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...
290
  	snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root);
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
291
292
293
294
295
296
  }
  
  static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
  {
  	debugfs_remove_recursive(codec->debugfs_codec_root);
  }
c3c5a19a5   Mark Brown   ASoC: Add debugfs...
297
298
299
300
  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 ...
301
  	ssize_t len, ret = 0;
c3c5a19a5   Mark Brown   ASoC: Add debugfs...
302
303
304
305
  	struct snd_soc_codec *codec;
  
  	if (!buf)
  		return -ENOMEM;
2b194f9db   Mark Brown   ASoC: Check list ...
306
307
308
309
310
311
312
313
314
315
316
  	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...
317
318
319
320
321
322
323
324
325
326
327
328
329
  
  	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...
330
331
332
333
  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 ...
334
  	ssize_t len, ret = 0;
f32087803   Mark Brown   ASoC: Add DAI lis...
335
336
337
338
  	struct snd_soc_dai *dai;
  
  	if (!buf)
  		return -ENOMEM;
2b194f9db   Mark Brown   ASoC: Check list ...
339
340
341
342
343
344
345
346
347
348
  	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...
349

2b194f9db   Mark Brown   ASoC: Check list ...
350
  	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
f32087803   Mark Brown   ASoC: Add DAI lis...
351
352
353
354
355
356
357
358
359
360
  
  	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...
361
362
363
364
365
  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 ...
366
  	ssize_t len, ret = 0;
19c7ac27a   Mark Brown   ASoC: Add platfor...
367
368
369
370
  	struct snd_soc_platform *platform;
  
  	if (!buf)
  		return -ENOMEM;
2b194f9db   Mark Brown   ASoC: Check list ...
371
372
373
374
375
376
377
378
379
380
381
  	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...
382

2b194f9db   Mark Brown   ASoC: Check list ...
383
  	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
19c7ac27a   Mark Brown   ASoC: Add platfor...
384
385
386
387
388
389
390
391
392
393
  
  	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...
394
395
396
  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...
397
  						     snd_soc_debugfs_root);
3a45b8672   Jarkko Nikula   ASoC: Move pop ti...
398
  	if (!card->debugfs_card_root) {
a60521549   Jarkko Nikula   ASoC: Add sound c...
399
400
401
  		dev_warn(card->dev,
  			 "ASoC: Failed to create codec debugfs directory
  ");
3a45b8672   Jarkko Nikula   ASoC: Move pop ti...
402
403
404
405
406
407
408
409
410
411
  		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...
412
413
414
415
416
417
  }
  
  static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
  {
  	debugfs_remove_recursive(card->debugfs_card_root);
  }
2624d5fa6   Mark Brown   ASoC: Move sysfs ...
418
419
420
421
422
423
424
425
426
  #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...
427
428
429
430
431
432
433
434
  
  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 ...
435
  #endif
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
  #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 ...
454
  	codec->ac97->dev.parent = codec->card->dev;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
455
  	codec->ac97->dev.release = soc_ac97_device_release;
bb072bf09   Kay Sievers   sound: struct dev...
456
  	dev_set_name(&codec->ac97->dev, "%d-%d:%s",
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
457
  		     codec->card->snd_card->number, 0, codec->name);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
458
459
460
461
462
463
464
465
466
467
  	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...
468
  #ifdef CONFIG_PM_SLEEP
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
469
  /* powers down audio subsystem for suspend */
6f8ab4ac2   Mark Brown   ASoC: Export card...
470
  int snd_soc_suspend(struct device *dev)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
471
  {
6f8ab4ac2   Mark Brown   ASoC: Export card...
472
  	struct snd_soc_card *card = dev_get_drvdata(dev);
2eea392d0   Jarkko Nikula   ASoC: Add support...
473
  	struct snd_soc_codec *codec;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
474
  	int i;
e3509ff0f   Daniel Mack   ASoC: fix NULL po...
475
476
477
  	/* 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...
478
  	if (list_empty(&card->codec_dev_list))
e3509ff0f   Daniel Mack   ASoC: fix NULL po...
479
  		return 0;
6ed259788   Andy Green   ALSA: ASoC: Don't...
480
481
482
  	/* 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...
483
484
485
  	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...
486
487
  
  	/* we're going to block userspace touching us until resume completes */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
488
  	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
6ed259788   Andy Green   ALSA: ASoC: Don't...
489

a00f90f93   Mark Brown   ASoC: Apostrophe ...
490
  	/* mute any active DACs */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
491
492
493
  	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...
494

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

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

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
510
511
512
  	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...
513

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
514
  		if (card->rtd[i].dai_link->ignore_suspend)
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
515
  			continue;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
516
517
518
519
520
521
  		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...
522
523
524
  	}
  
  	/* close any waiting streams and save state */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
525
  	for (i = 0; i < card->num_rtd; i++) {
5b84ba26a   Tejun Heo   sound: don't use ...
526
  		flush_delayed_work_sync(&card->rtd[i].delayed_work);
ce6120cca   Liam Girdwood   ASoC: Decouple DA...
527
  		card->rtd[i].codec->dapm.suspend_bias_level = card->rtd[i].codec->dapm.bias_level;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
528
  	}
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
529

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
530
531
  	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...
532

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
533
  		if (card->rtd[i].dai_link->ignore_suspend)
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
534
  			continue;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
535
536
  		if (driver->playback.stream_name != NULL)
  			snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
537
  				SND_SOC_DAPM_STREAM_SUSPEND);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
538
539
540
  
  		if (driver->capture.stream_name != NULL)
  			snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
541
542
  				SND_SOC_DAPM_STREAM_SUSPEND);
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
543
  	/* suspend all CODECs */
2eea392d0   Jarkko Nikula   ASoC: Add support...
544
  	list_for_each_entry(codec, &card->codec_dev_list, card_list) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
545
546
547
  		/* 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...
548
  			switch (codec->dapm.bias_level) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
549
550
551
552
  			case SND_SOC_BIAS_STANDBY:
  			case SND_SOC_BIAS_OFF:
  				codec->driver->suspend(codec, PMSG_SUSPEND);
  				codec->suspended = 1;
7be4ba24a   Mark Brown   ASoC: Mark cache ...
553
  				codec->cache_sync = 1;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
554
555
556
557
558
559
  				break;
  			default:
  				dev_dbg(codec->dev, "CODEC is on over suspend
  ");
  				break;
  			}
1547aba99   Mark Brown   ASoC: Support lea...
560
561
  		}
  	}
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
562

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
563
564
  	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...
565

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

6ed259788   Andy Green   ALSA: ASoC: Don't...
578
579
580
581
  /* 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...
582
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
583
584
  	struct snd_soc_card *card =
  			container_of(work, struct snd_soc_card, deferred_resume_work);
2eea392d0   Jarkko Nikula   ASoC: Add support...
585
  	struct snd_soc_codec *codec;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
586
  	int i;
6ed259788   Andy Green   ALSA: ASoC: Don't...
587
588
589
  	/* 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...
590
591
  	dev_dbg(card->dev, "starting resume work
  ");
6ed259788   Andy Green   ALSA: ASoC: Don't...
592

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

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

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
599
600
601
  	/* 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...
602

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
603
  		if (card->rtd[i].dai_link->ignore_suspend)
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
604
  			continue;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
605
606
607
  		if (cpu_dai->driver->resume && cpu_dai->driver->ac97_control)
  			cpu_dai->driver->resume(cpu_dai);
  	}
2eea392d0   Jarkko Nikula   ASoC: Add support...
608
  	list_for_each_entry(codec, &card->codec_dev_list, card_list) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
609
610
611
612
613
  		/* 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...
614
  			switch (codec->dapm.bias_level) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
615
616
617
618
619
620
621
622
623
624
  			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...
625
626
  		}
  	}
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
627

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
628
629
  	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...
630

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
631
  		if (card->rtd[i].dai_link->ignore_suspend)
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
632
  			continue;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
633
634
  		if (driver->playback.stream_name != NULL)
  			snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
635
  				SND_SOC_DAPM_STREAM_RESUME);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
636
637
638
  
  		if (driver->capture.stream_name != NULL)
  			snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
639
640
  				SND_SOC_DAPM_STREAM_RESUME);
  	}
3ff3f64ba   Mark Brown   [ALSA] ASoC: core...
641
  	/* unmute any active DACs */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
642
643
644
  	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...
645

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
646
  		if (card->rtd[i].dai_link->ignore_suspend)
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
647
  			continue;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
648
649
  		if (drv->ops->digital_mute && dai->playback_active)
  			drv->ops->digital_mute(dai, 0);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
650
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
651
652
653
  	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...
654

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
655
  		if (card->rtd[i].dai_link->ignore_suspend)
3efab7dcc   Mark Brown   ASoC: Allow DAI l...
656
  			continue;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
657
658
659
660
661
662
  		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...
663
  	}
875065491   Mark Brown   ASoC: Rename snd_...
664
  	if (card->resume_post)
70b2ac126   Mark Brown   ASoC: Use card ra...
665
  		card->resume_post(card);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
666

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

64ab9baa0   Mark Brown   ASoC: Don't defer...
680
681
682
683
684
  	/* 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...
685
686
  	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...
687
688
689
690
691
692
693
694
695
696
697
698
  		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...
699
  	}
6ed259788   Andy Green   ALSA: ASoC: Don't...
700

db2a41655   Frank Mandarino   [ALSA] ASoC: core...
701
702
  	return 0;
  }
6f8ab4ac2   Mark Brown   ASoC: Export card...
703
  EXPORT_SYMBOL_GPL(snd_soc_resume);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
704
  #else
6f8ab4ac2   Mark Brown   ASoC: Export card...
705
706
  #define snd_soc_suspend NULL
  #define snd_soc_resume NULL
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
707
  #endif
02a06d304   Barry Song   ASoC: Fix possibl...
708
709
  static struct snd_soc_dai_ops null_dai_ops = {
  };
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
710
  static int soc_bind_dai_link(struct snd_soc_card *card, int num)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
711
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
712
713
  	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 ...
714
  	struct snd_soc_codec *codec;
435c5e258   Mark Brown   ASoC: Initial fra...
715
  	struct snd_soc_platform *platform;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
716
  	struct snd_soc_dai *codec_dai, *cpu_dai;
848dd8bee   Mark Brown   ASoC: Add more na...
717
  	const char *platform_name;
435c5e258   Mark Brown   ASoC: Initial fra...
718

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

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
724
725
726
727
728
729
730
  	/* 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) {
  		if (!strcmp(cpu_dai->name, dai_link->cpu_dai_name)) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
731
732
  			rtd->cpu_dai = cpu_dai;
  			goto find_codec;
435c5e258   Mark Brown   ASoC: Initial fra...
733
  		}
435c5e258   Mark Brown   ASoC: Initial fra...
734
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
735
736
737
  	dev_dbg(card->dev, "CPU DAI %s not registered
  ",
  			dai_link->cpu_dai_name);
6308419a1   Mark Brown   ASoC: Push workqu...
738

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
739
740
741
742
743
744
745
746
747
748
  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) {
  		if (!strcmp(codec->name, dai_link->codec_name)) {
  			rtd->codec = codec;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
749
750
751
752
753
754
755
  			/* 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)) {
  					rtd->codec_dai = codec_dai;
  					goto find_platform;
  				}
435c5e258   Mark Brown   ASoC: Initial fra...
756
  			}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
757
758
759
760
761
  			dev_dbg(card->dev, "CODEC DAI %s not registered
  ",
  					dai_link->codec_dai_name);
  
  			goto find_platform;
435c5e258   Mark Brown   ASoC: Initial fra...
762
  		}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
763
764
765
766
  	}
  	dev_dbg(card->dev, "CODEC %s not registered
  ",
  			dai_link->codec_name);
6b05eda63   Mark Brown   ASoC: Wait for no...
767

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
768
  find_platform:
848dd8bee   Mark Brown   ASoC: Add more na...
769
770
  	/* do we need a platform? */
  	if (rtd->platform)
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
771
  		goto out;
848dd8bee   Mark Brown   ASoC: Add more na...
772
773
774
775
776
777
778
  
  	/* if there's no platform we match on the empty platform */
  	platform_name = dai_link->platform_name;
  	if (!platform_name)
  		platform_name = "snd-soc-dummy";
  
  	/* no, then find one from the set of registered platforms */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
779
  	list_for_each_entry(platform, &platform_list, list) {
848dd8bee   Mark Brown   ASoC: Add more na...
780
  		if (!strcmp(platform->name, platform_name)) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
781
782
783
  			rtd->platform = platform;
  			goto out;
  		}
02a06d304   Barry Song   ASoC: Fix possibl...
784
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
785
786
787
788
789
790
791
792
793
794
795
796
797
  	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...
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
  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...
819
  static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order)
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
820
821
822
823
824
825
826
827
828
829
  {
  	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) {
  		device_remove_file(&rtd->dev, &dev_attr_pmdown_time);
589c3563f   Jarkko Nikula   ASoC: Merge commo...
830
  		device_remove_file(&rtd->dev, &dev_attr_codec_reg);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
831
832
833
834
835
  		device_unregister(&rtd->dev);
  		rtd->dev_registered = 0;
  	}
  
  	/* remove the CODEC DAI */
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
836
837
  	if (codec_dai && codec_dai->probed &&
  			codec_dai->driver->remove_order == order) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
838
839
840
841
842
  		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...
843
  		}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
844
845
846
  		codec_dai->probed = 0;
  		list_del(&codec_dai->card_list);
  	}
6b05eda63   Mark Brown   ASoC: Wait for no...
847

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
848
  	/* remove the platform */
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
849
850
  	if (platform && platform->probed &&
  			platform->driver->remove_order == order) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
851
852
853
854
855
856
857
858
859
860
  		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...
861

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

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
867
  	/* remove the cpu_dai */
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
868
869
  	if (cpu_dai && cpu_dai->probed &&
  			cpu_dai->driver->remove_order == order) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
870
871
872
873
874
  		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...
875
  		}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
876
877
878
  		cpu_dai->probed = 0;
  		list_del(&cpu_dai->card_list);
  		module_put(cpu_dai->dev->driver->owner);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
879
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
880
  }
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
881

0671fd8ef   Kuninori Morimoto   ASoC: Add soc_rem...
882
883
  static void soc_remove_dai_links(struct snd_soc_card *card)
  {
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
884
  	int dai, order;
0671fd8ef   Kuninori Morimoto   ASoC: Add soc_rem...
885

0168bf0d1   Liam Girdwood   ASoC: core - Allo...
886
887
888
889
890
  	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...
891
892
  	card->num_rtd = 0;
  }
ead9b9199   Jarkko Nikula   ASoC: Add optiona...
893
894
895
896
  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...
897
  	if (card->codec_conf == NULL)
ead9b9199   Jarkko Nikula   ASoC: Add optiona...
898
  		return;
ff819b835   Dimitris Papastamos   ASoC: soc-core: G...
899
900
  	for (i = 0; i < card->num_configs; i++) {
  		struct snd_soc_codec_conf *map = &card->codec_conf[i];
ead9b9199   Jarkko Nikula   ASoC: Add optiona...
901
902
903
904
905
906
  		if (map->dev_name && !strcmp(codec->name, map->dev_name)) {
  			codec->name_prefix = map->name_prefix;
  			break;
  		}
  	}
  }
589c3563f   Jarkko Nikula   ASoC: Merge commo...
907
908
909
910
  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...
911
  	const struct snd_soc_codec_driver *driver = codec->driver;
589c3563f   Jarkko Nikula   ASoC: Merge commo...
912
913
914
915
  
  	codec->card = card;
  	codec->dapm.card = card;
  	soc_set_name_prefix(card, codec);
70d29331a   Jarkko Nikula   ASoC: soc-core: I...
916
917
  	if (!try_module_get(codec->dev->driver->owner))
  		return -ENODEV;
d5d1e0bef   Lars-Peter Clausen   ASoC: Move DAPM w...
918
  	soc_init_codec_debugfs(codec);
77530150f   Lars-Peter Clausen   ASoC: Create code...
919
920
921
  	if (driver->dapm_widgets)
  		snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets,
  					  driver->num_dapm_widgets);
89b95ac09   Mark Brown   ASoC: Add DAPM wi...
922
923
  	if (driver->probe) {
  		ret = driver->probe(codec);
589c3563f   Jarkko Nikula   ASoC: Merge commo...
924
925
926
927
928
  		if (ret < 0) {
  			dev_err(codec->dev,
  				"asoc: failed to probe CODEC %s: %d
  ",
  				codec->name, ret);
70d29331a   Jarkko Nikula   ASoC: soc-core: I...
929
  			goto err_probe;
589c3563f   Jarkko Nikula   ASoC: Merge commo...
930
931
  		}
  	}
b7af1dafd   Mark Brown   ASoC: Add data ba...
932
933
934
  	if (driver->controls)
  		snd_soc_add_controls(codec, driver->controls,
  				     driver->num_controls);
89b95ac09   Mark Brown   ASoC: Add DAPM wi...
935
936
937
  	if (driver->dapm_routes)
  		snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes,
  					driver->num_dapm_routes);
589c3563f   Jarkko Nikula   ASoC: Merge commo...
938
939
940
  	/* 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...
941
  	list_add(&codec->dapm.list, &card->dapm_list);
589c3563f   Jarkko Nikula   ASoC: Merge commo...
942

70d29331a   Jarkko Nikula   ASoC: soc-core: I...
943
944
945
  	return 0;
  
  err_probe:
d5d1e0bef   Lars-Peter Clausen   ASoC: Move DAPM w...
946
  	soc_cleanup_codec_debugfs(codec);
70d29331a   Jarkko Nikula   ASoC: soc-core: I...
947
  	module_put(codec->dev->driver->owner);
589c3563f   Jarkko Nikula   ASoC: Merge commo...
948
949
  	return ret;
  }
956245e9c   Liam Girdwood   ASoC: core - Make...
950
951
952
953
954
955
956
  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 ...
957
  	platform->dapm.card = card;
956245e9c   Liam Girdwood   ASoC: core - Make...
958
959
960
  
  	if (!try_module_get(platform->dev->driver->owner))
  		return -ENODEV;
cb2cf612f   Liam Girdwood   ASoC: core - Add ...
961
962
963
  	if (driver->dapm_widgets)
  		snd_soc_dapm_new_controls(&platform->dapm,
  			driver->dapm_widgets, driver->num_dapm_widgets);
956245e9c   Liam Girdwood   ASoC: core - Make...
964
965
966
967
968
969
970
971
972
973
  	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 ...
974
975
976
977
978
979
  	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...
980
981
982
  	/* 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 ...
983
  	list_add(&platform->dapm.list, &card->dapm_list);
956245e9c   Liam Girdwood   ASoC: core - Make...
984
985
986
987
988
989
990
991
  
  	return 0;
  
  err_probe:
  	module_put(platform->dev->driver->owner);
  
  	return ret;
  }
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
992
  static void rtd_release(struct device *dev) {}
589c3563f   Jarkko Nikula   ASoC: Merge commo...
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
  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...
1012
  	rtd->card = card;
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
  
  	/* 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;
  
  	/* Make sure all DAPM widgets are instantiated */
  	snd_soc_dapm_new_widgets(&codec->dapm);
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1032
1033
1034
  
  	/* register the rtd device */
  	rtd->codec = codec;
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1035
1036
1037
  	rtd->dev.parent = card->dev;
  	rtd->dev.release = rtd_release;
  	rtd->dev.init_name = name;
b8c0dab9b   Liam Girdwood   ASoC: core - PCM ...
1038
  	mutex_init(&rtd->pcm_mutex);
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
  	ret = device_register(&rtd->dev);
  	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 */
  	ret = snd_soc_dapm_sys_add(&rtd->dev);
  	if (ret < 0)
  		dev_err(codec->dev,
  			"asoc: failed to add codec dapm sysfs entries: %d
  ",
  			ret);
  
  	/* add codec sysfs entries */
  	ret = device_create_file(&rtd->dev, &dev_attr_codec_reg);
  	if (ret < 0)
  		dev_err(codec->dev,
  			"asoc: failed to add codec sysfs files: %d
  ", ret);
  
  	return 0;
  }
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
1065
  static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1066
1067
1068
1069
1070
1071
1072
  {
  	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...
1073
1074
1075
  	dev_dbg(card->dev, "probe %s dai link %d late %d
  ",
  			card->name, num, order);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1076
1077
1078
  
  	/* config components */
  	codec_dai->codec = codec;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1079
  	cpu_dai->platform = platform;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1080
1081
1082
1083
1084
1085
1086
  	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...
1087
1088
  	if (!cpu_dai->probed &&
  			cpu_dai->driver->probe_order == order) {
61b61e3c5   Liam Girdwood   ASoC: core - fix ...
1089
1090
  		if (!try_module_get(cpu_dai->dev->driver->owner))
  			return -ENODEV;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1091
1092
1093
1094
1095
1096
  		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 ...
1097
  				module_put(cpu_dai->dev->driver->owner);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1098
1099
1100
1101
  				return ret;
  			}
  		}
  		cpu_dai->probed = 1;
1c8371d61   Wolfram Sang   ASoC: core: make ...
1102
  		/* mark cpu_dai as probed and add to card dai list */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1103
  		list_add(&cpu_dai->card_list, &card->dai_dev_list);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1104
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1105
  	/* probe the CODEC */
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
1106
1107
  	if (!codec->probed &&
  			codec->driver->probe_order == order) {
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1108
1109
1110
  		ret = soc_probe_codec(card, codec);
  		if (ret < 0)
  			return ret;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1111
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1112
  	/* probe the platform */
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
1113
1114
  	if (!platform->probed &&
  			platform->driver->probe_order == order) {
956245e9c   Liam Girdwood   ASoC: core - Make...
1115
1116
1117
  		ret = soc_probe_platform(card, platform);
  		if (ret < 0)
  			return ret;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1118
  	}
6ed259788   Andy Green   ALSA: ASoC: Don't...
1119

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1120
  	/* probe the CODEC DAI */
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
1121
  	if (!codec_dai->probed && codec_dai->driver->probe_order == order) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1122
1123
  		if (codec_dai->driver->probe) {
  			ret = codec_dai->driver->probe(codec_dai);
fe3e78e07   Mark Brown   ASoC: Factor out ...
1124
  			if (ret < 0) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1125
1126
1127
1128
  				printk(KERN_ERR "asoc: failed to probe CODEC DAI %s
  ",
  						codec_dai->name);
  				return ret;
fe3e78e07   Mark Brown   ASoC: Factor out ...
1129
1130
  			}
  		}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1131

1c8371d61   Wolfram Sang   ASoC: core: make ...
1132
  		/* mark codec_dai as probed and add to card dai list */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1133
1134
  		codec_dai->probed = 1;
  		list_add(&codec_dai->card_list, &card->dai_dev_list);
fe3e78e07   Mark Brown   ASoC: Factor out ...
1135
  	}
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
1136
1137
1138
  	/* complete DAI probe during last probe */
  	if (order != SND_SOC_COMP_ORDER_LAST)
  		return 0;
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1139
1140
  	ret = soc_post_component_init(card, codec, num, 0);
  	if (ret)
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1141
  		return ret;
fe3e78e07   Mark Brown   ASoC: Factor out ...
1142

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1143
1144
1145
1146
  	ret = device_create_file(&rtd->dev, &dev_attr_pmdown_time);
  	if (ret < 0)
  		printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs
  ");
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
  	/* 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 ...
1161
  #ifdef CONFIG_SND_SOC_AC97_BUS
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1162
1163
1164
  static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
  {
  	int ret;
fe3e78e07   Mark Brown   ASoC: Factor out ...
1165
1166
1167
  	/* Only instantiate AC97 if not already done by the adaptor
  	 * for the generic AC97 subsystem.
  	 */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1168
  	if (rtd->codec_dai->driver->ac97_control && !rtd->codec->ac97_registered) {
0562f7882   Mika Westerberg   ASoC: don't regis...
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
  		/*
  		 * 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...
1179
1180
  
  		ret = soc_ac97_dev_register(rtd->codec);
fe3e78e07   Mark Brown   ASoC: Factor out ...
1181
1182
1183
  		if (ret < 0) {
  			printk(KERN_ERR "asoc: AC97 device register failed
  ");
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1184
  			return ret;
fe3e78e07   Mark Brown   ASoC: Factor out ...
1185
  		}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1186
1187
  
  		rtd->codec->ac97_registered = 1;
fe3e78e07   Mark Brown   ASoC: Factor out ...
1188
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
  	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 ...
1199
  #endif
2eea392d0   Jarkko Nikula   ASoC: Add support...
1200
1201
1202
  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...
1203
  	struct snd_soc_codec *codec;
676ad98a0   Jarkko Nikula   ASoC: Don't oops ...
1204
  	int ret = -ENODEV;
2eea392d0   Jarkko Nikula   ASoC: Add support...
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
  
  	/* 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 ...
1215
  			goto found;
2eea392d0   Jarkko Nikula   ASoC: Add support...
1216
1217
  		}
  	}
676ad98a0   Jarkko Nikula   ASoC: Don't oops ...
1218
1219
1220
  	/* codec not found */
  	dev_err(card->dev, "asoc: codec %s not found", aux_dev->codec_name);
  	goto out;
2eea392d0   Jarkko Nikula   ASoC: Add support...
1221

676ad98a0   Jarkko Nikula   ASoC: Don't oops ...
1222
  found:
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1223
  	ret = soc_probe_codec(card, codec);
2eea392d0   Jarkko Nikula   ASoC: Add support...
1224
  	if (ret < 0)
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1225
  		return ret;
2eea392d0   Jarkko Nikula   ASoC: Add support...
1226

589c3563f   Jarkko Nikula   ASoC: Merge commo...
1227
  	ret = soc_post_component_init(card, codec, num, 1);
2eea392d0   Jarkko Nikula   ASoC: Add support...
1228
1229
1230
1231
1232
1233
1234
1235
1236
  
  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...
1237
1238
1239
  
  	/* unregister the rtd device */
  	if (rtd->dev_registered) {
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1240
  		device_remove_file(&rtd->dev, &dev_attr_codec_reg);
2eea392d0   Jarkko Nikula   ASoC: Add support...
1241
1242
1243
  		device_unregister(&rtd->dev);
  		rtd->dev_registered = 0;
  	}
589c3563f   Jarkko Nikula   ASoC: Merge commo...
1244
1245
  	if (codec && codec->probed)
  		soc_remove_codec(codec);
2eea392d0   Jarkko Nikula   ASoC: Add support...
1246
  }
fdf0f54da   Dimitris Papastamos   ASoC: soc-core: A...
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
  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...
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
  	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...
1268
1269
  static void snd_soc_instantiate_card(struct snd_soc_card *card)
  {
fdf0f54da   Dimitris Papastamos   ASoC: soc-core: A...
1270
1271
1272
  	struct snd_soc_codec *codec;
  	struct snd_soc_codec_conf *codec_conf;
  	enum snd_soc_compress_type compress_type;
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
1273
  	int ret, i, order;
fe3e78e07   Mark Brown   ASoC: Factor out ...
1274

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

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1277
1278
1279
1280
  	if (card->instantiated) {
  		mutex_unlock(&card->mutex);
  		return;
  	}
fe3e78e07   Mark Brown   ASoC: Factor out ...
1281

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

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1286
1287
1288
1289
1290
  	/* bind completed ? */
  	if (card->num_rtd != card->num_links) {
  		mutex_unlock(&card->mutex);
  		return;
  	}
435c5e258   Mark Brown   ASoC: Initial fra...
1291

fdf0f54da   Dimitris Papastamos   ASoC: soc-core: A...
1292
1293
1294
1295
  	/* 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...
1296
1297
  		/* by default we don't override the compress_type */
  		compress_type = 0;
fdf0f54da   Dimitris Papastamos   ASoC: soc-core: A...
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
  		/* 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...
1308
1309
1310
1311
1312
1313
  		ret = snd_soc_init_codec_cache(codec, compress_type);
  		if (ret < 0) {
  			mutex_unlock(&card->mutex);
  			return;
  		}
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
  	/* 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...
1325
1326
1327
1328
  	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...
1329
1330
1331
  #ifdef CONFIG_DEBUG_FS
  	snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root);
  #endif
88ee1c611   Mark Brown   ASoC: Update PM i...
1332
  #ifdef CONFIG_PM_SLEEP
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1333
1334
1335
  	/* deferred resume work */
  	INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
  #endif
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1336

9a841ebb9   Mark Brown   ASoC: Create card...
1337
1338
1339
  	if (card->dapm_widgets)
  		snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
  					  card->num_dapm_widgets);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1340
1341
  	/* initialise the sound card only once */
  	if (card->probe) {
e7361ec49   Mark Brown   ASoC: Replace pde...
1342
  		ret = card->probe(card);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1343
1344
1345
  		if (ret < 0)
  			goto card_probe_error;
  	}
fe3e78e07   Mark Brown   ASoC: Factor out ...
1346

0168bf0d1   Liam Girdwood   ASoC: core - Allo...
1347
1348
1349
1350
1351
1352
1353
1354
  	/* 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...
1355
  			       card->name, ret);
0168bf0d1   Liam Girdwood   ASoC: core - Allo...
1356
1357
  				goto probe_dai_err;
  			}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1358
1359
  		}
  	}
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1360

2eea392d0   Jarkko Nikula   ASoC: Add support...
1361
1362
1363
1364
1365
1366
1367
1368
1369
  	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...
1370
1371
1372
1373
1374
1375
1376
  	/* 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 ...
1377
1378
1379
  	if (card->dapm_routes)
  		snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
  					card->num_dapm_routes);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1380
  	snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1381
  		 "%s", card->name);
22de71ba0   Liam Girdwood   ASoC: core - allo...
1382
1383
  	snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
  		 "%s", card->long_name ? card->long_name : card->name);
873bd4cb4   Takashi Iwai   ASoC: Don't set i...
1384
1385
1386
  	if (card->driver_name)
  		strlcpy(card->snd_card->driver, card->driver_name,
  			sizeof(card->snd_card->driver));
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1387

28e9ad921   Mark Brown   ASoC: Add a late_...
1388
1389
1390
1391
1392
1393
1394
1395
1396
  	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;
  		}
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1397
1398
1399
1400
  	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...
1401
  		goto probe_aux_dev_err;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1402
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1403
1404
1405
  #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...
1406
1407
1408
1409
1410
  		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...
1411
  				soc_unregister_ac97_dai_link(card->rtd[i].codec);
6b3ed7853   Axel Lin   ASoC: Fix snd_soc...
1412
  			goto probe_aux_dev_err;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1413
  		}
6b3ed7853   Axel Lin   ASoC: Fix snd_soc...
1414
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1415
1416
1417
1418
1419
  #endif
  
  	card->instantiated = 1;
  	mutex_unlock(&card->mutex);
  	return;
2eea392d0   Jarkko Nikula   ASoC: Add support...
1420
1421
1422
  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...
1423
  probe_dai_err:
0671fd8ef   Kuninori Morimoto   ASoC: Add soc_rem...
1424
  	soc_remove_dai_links(card);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1425
1426
  
  card_probe_error:
875065491   Mark Brown   ASoC: Rename snd_...
1427
  	if (card->remove)
e7361ec49   Mark Brown   ASoC: Replace pde...
1428
  		card->remove(card);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1429
1430
1431
1432
  
  	snd_card_free(card->snd_card);
  
  	mutex_unlock(&card->mutex);
435c5e258   Mark Brown   ASoC: Initial fra...
1433
  }
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1434

435c5e258   Mark Brown   ASoC: Initial fra...
1435
  /*
421f91d21   Uwe Kleine-König   fix typos concern...
1436
   * Attempt to initialise any uninitialised cards.  Must be called with
435c5e258   Mark Brown   ASoC: Initial fra...
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
   * 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...
1449
  	struct snd_soc_card *card = platform_get_drvdata(pdev);
435c5e258   Mark Brown   ASoC: Initial fra...
1450
  	int ret = 0;
435c5e258   Mark Brown   ASoC: Initial fra...
1451

70a7ca34d   Vinod Koul   ASoC: soc core al...
1452
1453
1454
1455
1456
1457
  	/*
  	 * 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...
1458
1459
  	/* Bodge while we unpick instantiation */
  	card->dev = &pdev->dev;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1460

435c5e258   Mark Brown   ASoC: Initial fra...
1461
1462
1463
1464
1465
1466
1467
1468
  	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...
1469
  }
b0e264855   Vinod Koul   ASoC: soc core mo...
1470
  static int soc_cleanup_card_resources(struct snd_soc_card *card)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1471
1472
  {
  	int i;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1473

b0e264855   Vinod Koul   ASoC: soc core mo...
1474
1475
1476
1477
1478
  	/* 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...
1479

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

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

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

b0e264855   Vinod Koul   ASoC: soc core mo...
1489
1490
  	/* remove the card */
  	if (card->remove)
e7361ec49   Mark Brown   ASoC: Replace pde...
1491
  		card->remove(card);
a60521549   Jarkko Nikula   ASoC: Add sound c...
1492

0aaae527c   Lars-Peter Clausen   ASoC: Free the ca...
1493
  	snd_soc_dapm_free(&card->dapm);
b0e264855   Vinod Koul   ASoC: soc core mo...
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
  	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...
1504

c5af3a2e1   Mark Brown   ASoC: Add card re...
1505
  	snd_soc_unregister_card(card);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1506
1507
  	return 0;
  }
6f8ab4ac2   Mark Brown   ASoC: Export card...
1508
  int snd_soc_poweroff(struct device *dev)
517374704   Mark Brown   ASoC: Add a shutd...
1509
  {
6f8ab4ac2   Mark Brown   ASoC: Export card...
1510
  	struct snd_soc_card *card = dev_get_drvdata(dev);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1511
  	int i;
517374704   Mark Brown   ASoC: Add a shutd...
1512
1513
  
  	if (!card->instantiated)
416356fcf   Mark Brown   ASoC: Convert to ...
1514
  		return 0;
517374704   Mark Brown   ASoC: Add a shutd...
1515
1516
1517
  
  	/* 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...
1518
1519
  	for (i = 0; i < card->num_rtd; i++) {
  		struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
5b84ba26a   Tejun Heo   sound: don't use ...
1520
  		flush_delayed_work_sync(&rtd->delayed_work);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1521
  	}
517374704   Mark Brown   ASoC: Add a shutd...
1522

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
1523
  	snd_soc_dapm_shutdown(card);
416356fcf   Mark Brown   ASoC: Convert to ...
1524
1525
  
  	return 0;
517374704   Mark Brown   ASoC: Add a shutd...
1526
  }
6f8ab4ac2   Mark Brown   ASoC: Export card...
1527
  EXPORT_SYMBOL_GPL(snd_soc_poweroff);
517374704   Mark Brown   ASoC: Add a shutd...
1528

6f8ab4ac2   Mark Brown   ASoC: Export card...
1529
1530
1531
1532
  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 ...
1533
  };
deb2607e6   Stephen Warren   ASoC: Tegra: Susp...
1534
  EXPORT_SYMBOL_GPL(snd_soc_pm_ops);
416356fcf   Mark Brown   ASoC: Convert to ...
1535

db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1536
1537
1538
1539
  /* ASoC platform driver */
  static struct platform_driver soc_driver = {
  	.driver		= {
  		.name		= "soc-audio",
8b45a2099   Kay Sievers   [ALSA] sound: fix...
1540
  		.owner		= THIS_MODULE,
6f8ab4ac2   Mark Brown   ASoC: Export card...
1541
  		.pm		= &snd_soc_pm_ops,
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1542
1543
1544
  	},
  	.probe		= soc_probe,
  	.remove		= soc_remove,
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1545
  };
096e49d5e   Mark Brown   ASoC: Add CODEC v...
1546
1547
1548
1549
1550
1551
1552
1553
  /**
   * 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...
1554
1555
  int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
  				    unsigned int reg)
096e49d5e   Mark Brown   ASoC: Add CODEC v...
1556
  {
1500b7b5f   Dimitris Papastamos   ASoC: Automatical...
1557
1558
  	if (codec->volatile_register)
  		return codec->volatile_register(codec, reg);
096e49d5e   Mark Brown   ASoC: Add CODEC v...
1559
1560
1561
1562
  	else
  		return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_codec_volatile_register);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1563
  /**
239c97062   Dimitris Papastamos   ASoC: Add snd_soc...
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
   * 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...
1577
  		return 1;
239c97062   Dimitris Papastamos   ASoC: Add snd_soc...
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
  }
  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...
1595
  		return 1;
239c97062   Dimitris Papastamos   ASoC: Add snd_soc...
1596
1597
  }
  EXPORT_SYMBOL_GPL(snd_soc_codec_writable_register);
f1442bc1e   Liam Girdwood   ASoC: core - Add ...
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
  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 ...
1612
  	trace_snd_soc_preg_read(platform, reg, ret);
f1442bc1e   Liam Girdwood   ASoC: core - Add ...
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
  
  	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 ...
1629
  	trace_snd_soc_preg_write(platform, reg, val);
f1442bc1e   Liam Girdwood   ASoC: core - Add ...
1630
1631
1632
  	return platform->driver->write(platform, reg, val);
  }
  EXPORT_SYMBOL_GPL(snd_soc_platform_write);
239c97062   Dimitris Papastamos   ASoC: Add snd_soc...
1633
  /**
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
   * 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...
1662
1663
1664
1665
1666
1667
  
  	/*
  	 * 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...
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
  	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...
1682
1683
1684
  #ifdef CONFIG_SND_SOC_AC97_BUS
  	soc_unregister_ac97_dai_link(codec);
  #endif
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1685
1686
1687
  	kfree(codec->ac97->bus);
  	kfree(codec->ac97);
  	codec->ac97 = NULL;
0562f7882   Mika Westerberg   ASoC: don't regis...
1688
  	codec->ac97_created = 0;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1689
1690
1691
  	mutex_unlock(&codec->mutex);
  }
  EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
c37537079   Mark Brown   ASoC: Push snd_so...
1692
1693
1694
  unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg)
  {
  	unsigned int ret;
c3acec267   Mark Brown   ASoC: Move active...
1695
  	ret = codec->read(codec, reg);
c37537079   Mark Brown   ASoC: Push snd_so...
1696
1697
  	dev_dbg(codec->dev, "read %x => %x
  ", reg, ret);
a8b1d34f3   Mark Brown   ASoC: Add trace e...
1698
  	trace_snd_soc_reg_read(codec, reg, ret);
c37537079   Mark Brown   ASoC: Push snd_so...
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
  
  	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...
1709
  	trace_snd_soc_reg_write(codec, reg, val);
c3acec267   Mark Brown   ASoC: Move active...
1710
  	return codec->write(codec, reg, val);
c37537079   Mark Brown   ASoC: Push snd_so...
1711
1712
  }
  EXPORT_SYMBOL_GPL(snd_soc_write);
5fb609d43   Dimitris Papastamos   ASoC: soc-cache: ...
1713
1714
1715
1716
1717
1718
  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...
1719
1720
1721
1722
1723
1724
1725
1726
1727
  /**
   * 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...
1728
   * Returns 1 for change, 0 for no change, or negative error code.
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1729
1730
   */
  int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
46f5822f7   Daniel Ribeiro   ASoC: Allow 32 bi...
1731
  				unsigned int mask, unsigned int value)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1732
1733
  {
  	int change;
46f5822f7   Daniel Ribeiro   ASoC: Allow 32 bi...
1734
  	unsigned int old, new;
180c329d6   Timur Tabi   ASoC: let snd_soc...
1735
1736
1737
1738
1739
  	int ret;
  
  	ret = snd_soc_read(codec, reg);
  	if (ret < 0)
  		return ret;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1740

180c329d6   Timur Tabi   ASoC: let snd_soc...
1741
  	old = ret;
78bf3c9ab   Mark Brown   ASoC: Enforce the...
1742
  	new = (old & ~mask) | (value & mask);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1743
  	change = old != new;
180c329d6   Timur Tabi   ASoC: let snd_soc...
1744
1745
1746
1747
1748
  	if (change) {
  		ret = snd_soc_write(codec, reg, new);
  		if (ret < 0)
  			return ret;
  	}
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1749

db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1750
1751
1752
1753
1754
  	return change;
  }
  EXPORT_SYMBOL_GPL(snd_soc_update_bits);
  
  /**
6c508c62f   Eero Nurkkala   ASoC: refactor sn...
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
   * 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_...
1765
1766
1767
  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...
1768
1769
1770
1771
1772
1773
1774
1775
1776
  {
  	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_...
1777
  EXPORT_SYMBOL_GPL(snd_soc_update_bits_locked);
6c508c62f   Eero Nurkkala   ASoC: refactor sn...
1778
1779
  
  /**
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
   * 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...
1792
  				unsigned int mask, unsigned int value)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1793
1794
  {
  	int change;
46f5822f7   Daniel Ribeiro   ASoC: Allow 32 bi...
1795
  	unsigned int old, new;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1796

db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1797
1798
1799
  	old = snd_soc_read(codec, reg);
  	new = (old & ~mask) | value;
  	change = old != new;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1800
1801
1802
1803
1804
1805
  
  	return change;
  }
  EXPORT_SYMBOL_GPL(snd_soc_test_bits);
  
  /**
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
   * 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...
1832
   * @long_name: control long name
efb7ac3f9   Mark Brown   ASoC: Fix prefixi...
1833
   * @prefix: control name prefix
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1834
1835
1836
1837
1838
1839
   *
   * 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...
1840
1841
  				  void *data, char *long_name,
  				  const char *prefix)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1842
1843
  {
  	struct snd_kcontrol_new template;
efb7ac3f9   Mark Brown   ASoC: Fix prefixi...
1844
1845
1846
  	struct snd_kcontrol *kcontrol;
  	char *name = NULL;
  	int name_len;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1847
1848
  
  	memcpy(&template, _template, sizeof(template));
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1849
  	template.index = 0;
efb7ac3f9   Mark Brown   ASoC: Fix prefixi...
1850
1851
1852
1853
1854
  	if (!long_name)
  		long_name = template.name;
  
  	if (prefix) {
  		name_len = strlen(long_name) + strlen(prefix) + 2;
57cf9d451   Axel Lin   ASoC: soc-core: u...
1855
  		name = kmalloc(name_len, GFP_KERNEL);
efb7ac3f9   Mark Brown   ASoC: Fix prefixi...
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
  		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...
1871
1872
1873
1874
  }
  EXPORT_SYMBOL_GPL(snd_soc_cnew);
  
  /**
3e8e1952e   Ian Molton   ASoC: cleanup dup...
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
   * 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...
1888
  	struct snd_card *card = codec->card->snd_card;
3e8e1952e   Ian Molton   ASoC: cleanup dup...
1889
1890
1891
1892
  	int err, i;
  
  	for (i = 0; i < num_controls; i++) {
  		const struct snd_kcontrol_new *control = &controls[i];
efb7ac3f9   Mark Brown   ASoC: Fix prefixi...
1893
1894
1895
  		err = snd_ctl_add(card, snd_soc_cnew(control, codec,
  						     control->name,
  						     codec->name_prefix));
3e8e1952e   Ian Molton   ASoC: cleanup dup...
1896
  		if (err < 0) {
082100dc9   Mark Brown   ASoC: Report erro...
1897
1898
  			dev_err(codec->dev, "%s: Failed to add %s: %d
  ",
efb7ac3f9   Mark Brown   ASoC: Fix prefixi...
1899
  				codec->name, control->name, err);
3e8e1952e   Ian Molton   ASoC: cleanup dup...
1900
1901
1902
1903
1904
1905
1906
1907
1908
  			return err;
  		}
  	}
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_add_controls);
  
  /**
a491a5c84   Liam Girdwood   ASoC: core - Add ...
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
   * 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...
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
   * 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...
1956
  	uinfo->value.enumerated.items = e->max;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1957

f8ba0b7bf   Jon Smirl   ALSA: ASoC: Renam...
1958
1959
  	if (uinfo->value.enumerated.item > e->max - 1)
  		uinfo->value.enumerated.item = e->max - 1;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1960
1961
1962
1963
1964
1965
1966
1967
1968
  	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...
1969
   * @ucontrol: control element information
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
   *
   * 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...
1980
  	unsigned int val, bitmask;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1981

f8ba0b7bf   Jon Smirl   ALSA: ASoC: Renam...
1982
  	for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1983
1984
  		;
  	val = snd_soc_read(codec, e->reg);
3ff3f64ba   Mark Brown   [ALSA] ASoC: core...
1985
1986
  	ucontrol->value.enumerated.item[0]
  		= (val >> e->shift_l) & (bitmask - 1);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
  	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...
1998
   * @ucontrol: control element information
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
   *
   * 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...
2009
2010
  	unsigned int val;
  	unsigned int mask, bitmask;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2011

f8ba0b7bf   Jon Smirl   ALSA: ASoC: Renam...
2012
  	for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2013
  		;
f8ba0b7bf   Jon Smirl   ALSA: ASoC: Renam...
2014
  	if (ucontrol->value.enumerated.item[0] > e->max - 1)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2015
2016
2017
2018
  		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...
2019
  		if (ucontrol->value.enumerated.item[1] > e->max - 1)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2020
2021
2022
2023
  			return -EINVAL;
  		val |= ucontrol->value.enumerated.item[1] << e->shift_r;
  		mask |= (bitmask - 1) << e->shift_r;
  	}
6c508c62f   Eero Nurkkala   ASoC: refactor sn...
2024
  	return snd_soc_update_bits_locked(codec, e->reg, mask, val);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2025
2026
2027
2028
  }
  EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
  
  /**
2e72f8e37   Peter Ujfalusi   ASoC: New enum ty...
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
   * 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...
2044
  	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
46f5822f7   Daniel Ribeiro   ASoC: Allow 32 bi...
2045
  	unsigned int reg_val, val, mux;
2e72f8e37   Peter Ujfalusi   ASoC: New enum ty...
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
  
  	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...
2083
  	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
46f5822f7   Daniel Ribeiro   ASoC: Allow 32 bi...
2084
2085
  	unsigned int val;
  	unsigned int mask;
2e72f8e37   Peter Ujfalusi   ASoC: New enum ty...
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
  
  	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...
2097
  	return snd_soc_update_bits_locked(codec, e->reg, mask, val);
2e72f8e37   Peter Ujfalusi   ASoC: New enum ty...
2098
2099
2100
2101
  }
  EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double);
  
  /**
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
   * 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...
2118
  	uinfo->value.enumerated.items = e->max;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2119

f8ba0b7bf   Jon Smirl   ALSA: ASoC: Renam...
2120
2121
  	if (uinfo->value.enumerated.item > e->max - 1)
  		uinfo->value.enumerated.item = e->max - 1;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
  	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...
2140
  	int max = kcontrol->private_value;
fd5dfad9c   Mark Brown   ASoC: Volume cont...
2141
  	if (max == 1 && !strstr(kcontrol->id.name, " Volume"))
a7a4ac86b   Philipp Zabel   [ALSA] ASoC TLV s...
2142
2143
2144
  		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
  	else
  		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2145

db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2146
2147
  	uinfo->count = 1;
  	uinfo->value.integer.min = 0;
a7a4ac86b   Philipp Zabel   [ALSA] ASoC TLV s...
2148
  	uinfo->value.integer.max = max;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2149
2150
2151
2152
2153
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext);
  
  /**
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
   * snd_soc_info_volsw - single mixer info callback
   * @kcontrol: mixer control
   * @uinfo: control element information
   *
   * Callback to provide information about a single mixer control.
   *
   * 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...
2165
2166
  	struct soc_mixer_control *mc =
  		(struct soc_mixer_control *)kcontrol->private_value;
d11bb4a92   Peter Ujfalusi   ASoC: core: Fix f...
2167
  	int platform_max;
762b8df74   Mark Brown   ALSA: ASoC: Fix m...
2168
  	unsigned int shift = mc->shift;
815ecf8de   Jon Smirl   ALSA: ASoC: conve...
2169
  	unsigned int rshift = mc->rshift;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2170

d11bb4a92   Peter Ujfalusi   ASoC: core: Fix f...
2171
2172
2173
2174
2175
  	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...
2176
2177
2178
  		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
  	else
  		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2179
2180
  	uinfo->count = shift == rshift ? 1 : 2;
  	uinfo->value.integer.min = 0;
d11bb4a92   Peter Ujfalusi   ASoC: core: Fix f...
2181
  	uinfo->value.integer.max = platform_max;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2182
2183
2184
2185
2186
2187
2188
  	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...
2189
   * @ucontrol: control element information
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2190
2191
2192
2193
2194
2195
2196
2197
   *
   * Callback to get the value of a single mixer control.
   *
   * 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...
2198
2199
  	struct soc_mixer_control *mc =
  		(struct soc_mixer_control *)kcontrol->private_value;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2200
  	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
815ecf8de   Jon Smirl   ALSA: ASoC: conve...
2201
2202
2203
  	unsigned int reg = mc->reg;
  	unsigned int shift = mc->shift;
  	unsigned int rshift = mc->rshift;
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2204
  	int max = mc->max;
815ecf8de   Jon Smirl   ALSA: ASoC: conve...
2205
2206
  	unsigned int mask = (1 << fls(max)) - 1;
  	unsigned int invert = mc->invert;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2207
2208
2209
2210
2211
2212
2213
2214
  
  	ucontrol->value.integer.value[0] =
  		(snd_soc_read(codec, reg) >> shift) & mask;
  	if (shift != rshift)
  		ucontrol->value.integer.value[1] =
  			(snd_soc_read(codec, reg) >> rshift) & mask;
  	if (invert) {
  		ucontrol->value.integer.value[0] =
a7a4ac86b   Philipp Zabel   [ALSA] ASoC TLV s...
2215
  			max - ucontrol->value.integer.value[0];
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2216
2217
  		if (shift != rshift)
  			ucontrol->value.integer.value[1] =
a7a4ac86b   Philipp Zabel   [ALSA] ASoC TLV s...
2218
  				max - ucontrol->value.integer.value[1];
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2219
2220
2221
2222
2223
2224
2225
2226
2227
  	}
  
  	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...
2228
   * @ucontrol: control element information
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2229
2230
2231
2232
2233
2234
2235
2236
   *
   * Callback to set the value of a single mixer control.
   *
   * 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...
2237
2238
  	struct soc_mixer_control *mc =
  		(struct soc_mixer_control *)kcontrol->private_value;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2239
  	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
815ecf8de   Jon Smirl   ALSA: ASoC: conve...
2240
2241
2242
  	unsigned int reg = mc->reg;
  	unsigned int shift = mc->shift;
  	unsigned int rshift = mc->rshift;
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2243
  	int max = mc->max;
815ecf8de   Jon Smirl   ALSA: ASoC: conve...
2244
2245
  	unsigned int mask = (1 << fls(max)) - 1;
  	unsigned int invert = mc->invert;
46f5822f7   Daniel Ribeiro   ASoC: Allow 32 bi...
2246
  	unsigned int val, val2, val_mask;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2247
2248
2249
  
  	val = (ucontrol->value.integer.value[0] & mask);
  	if (invert)
a7a4ac86b   Philipp Zabel   [ALSA] ASoC TLV s...
2250
  		val = max - val;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2251
2252
2253
2254
2255
  	val_mask = mask << shift;
  	val = val << shift;
  	if (shift != rshift) {
  		val2 = (ucontrol->value.integer.value[1] & mask);
  		if (invert)
a7a4ac86b   Philipp Zabel   [ALSA] ASoC TLV s...
2256
  			val2 = max - val2;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2257
2258
2259
  		val_mask |= mask << rshift;
  		val |= val2 << rshift;
  	}
6c508c62f   Eero Nurkkala   ASoC: refactor sn...
2260
  	return snd_soc_update_bits_locked(codec, reg, val_mask, val);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
  }
  EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
  
  /**
   * snd_soc_info_volsw_2r - double mixer info callback
   * @kcontrol: mixer control
   * @uinfo: control element information
   *
   * Callback to provide information about a double mixer control that
   * spans 2 codec registers.
   *
   * Returns 0 for success.
   */
  int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol,
  	struct snd_ctl_elem_info *uinfo)
  {
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2277
2278
  	struct soc_mixer_control *mc =
  		(struct soc_mixer_control *)kcontrol->private_value;
d11bb4a92   Peter Ujfalusi   ASoC: core: Fix f...
2279
  	int platform_max;
a7a4ac86b   Philipp Zabel   [ALSA] ASoC TLV s...
2280

d11bb4a92   Peter Ujfalusi   ASoC: core: Fix f...
2281
2282
2283
2284
2285
  	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...
2286
2287
2288
  		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
  	else
  		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2289

db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2290
2291
  	uinfo->count = 2;
  	uinfo->value.integer.min = 0;
d11bb4a92   Peter Ujfalusi   ASoC: core: Fix f...
2292
  	uinfo->value.integer.max = platform_max;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2293
2294
2295
2296
2297
2298
2299
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r);
  
  /**
   * snd_soc_get_volsw_2r - double mixer get callback
   * @kcontrol: mixer control
ac11a2b35   Mark Brown   ASoC: Clean up ke...
2300
   * @ucontrol: control element information
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2301
2302
2303
2304
2305
2306
2307
2308
   *
   * Callback to get the value of a double mixer control that spans 2 registers.
   *
   * Returns 0 for success.
   */
  int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
  	struct snd_ctl_elem_value *ucontrol)
  {
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2309
2310
  	struct soc_mixer_control *mc =
  		(struct soc_mixer_control *)kcontrol->private_value;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2311
  	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
815ecf8de   Jon Smirl   ALSA: ASoC: conve...
2312
2313
2314
  	unsigned int reg = mc->reg;
  	unsigned int reg2 = mc->rreg;
  	unsigned int shift = mc->shift;
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2315
  	int max = mc->max;
46f5822f7   Daniel Ribeiro   ASoC: Allow 32 bi...
2316
  	unsigned int mask = (1 << fls(max)) - 1;
815ecf8de   Jon Smirl   ALSA: ASoC: conve...
2317
  	unsigned int invert = mc->invert;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2318
2319
2320
2321
2322
2323
2324
  
  	ucontrol->value.integer.value[0] =
  		(snd_soc_read(codec, reg) >> shift) & mask;
  	ucontrol->value.integer.value[1] =
  		(snd_soc_read(codec, reg2) >> shift) & mask;
  	if (invert) {
  		ucontrol->value.integer.value[0] =
a7a4ac86b   Philipp Zabel   [ALSA] ASoC TLV s...
2325
  			max - ucontrol->value.integer.value[0];
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2326
  		ucontrol->value.integer.value[1] =
a7a4ac86b   Philipp Zabel   [ALSA] ASoC TLV s...
2327
  			max - ucontrol->value.integer.value[1];
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2328
2329
2330
2331
2332
2333
2334
2335
2336
  	}
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r);
  
  /**
   * snd_soc_put_volsw_2r - double mixer set callback
   * @kcontrol: mixer control
ac11a2b35   Mark Brown   ASoC: Clean up ke...
2337
   * @ucontrol: control element information
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2338
2339
2340
2341
2342
2343
2344
2345
   *
   * Callback to set the value of a double mixer control that spans 2 registers.
   *
   * Returns 0 for success.
   */
  int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
  	struct snd_ctl_elem_value *ucontrol)
  {
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2346
2347
  	struct soc_mixer_control *mc =
  		(struct soc_mixer_control *)kcontrol->private_value;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2348
  	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
815ecf8de   Jon Smirl   ALSA: ASoC: conve...
2349
2350
2351
  	unsigned int reg = mc->reg;
  	unsigned int reg2 = mc->rreg;
  	unsigned int shift = mc->shift;
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2352
  	int max = mc->max;
815ecf8de   Jon Smirl   ALSA: ASoC: conve...
2353
2354
  	unsigned int mask = (1 << fls(max)) - 1;
  	unsigned int invert = mc->invert;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2355
  	int err;
46f5822f7   Daniel Ribeiro   ASoC: Allow 32 bi...
2356
  	unsigned int val, val2, val_mask;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2357
2358
2359
2360
2361
2362
  
  	val_mask = mask << shift;
  	val = (ucontrol->value.integer.value[0] & mask);
  	val2 = (ucontrol->value.integer.value[1] & mask);
  
  	if (invert) {
a7a4ac86b   Philipp Zabel   [ALSA] ASoC TLV s...
2363
2364
  		val = max - val;
  		val2 = max - val2;
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2365
2366
2367
2368
  	}
  
  	val = val << shift;
  	val2 = val2 << shift;
6c508c62f   Eero Nurkkala   ASoC: refactor sn...
2369
  	err = snd_soc_update_bits_locked(codec, reg, val_mask, val);
3ff3f64ba   Mark Brown   [ALSA] ASoC: core...
2370
  	if (err < 0)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2371
  		return err;
6c508c62f   Eero Nurkkala   ASoC: refactor sn...
2372
  	err = snd_soc_update_bits_locked(codec, reg2, val_mask, val2);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
2373
2374
2375
  	return err;
  }
  EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r);
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
  /**
   * 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...
2388
2389
  	struct soc_mixer_control *mc =
  		(struct soc_mixer_control *)kcontrol->private_value;
d11bb4a92   Peter Ujfalusi   ASoC: core: Fix f...
2390
  	int platform_max;
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2391
  	int min = mc->min;
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2392

d11bb4a92   Peter Ujfalusi   ASoC: core: Fix f...
2393
2394
2395
  	if (!mc->platform_max)
  		mc->platform_max = mc->max;
  	platform_max = mc->platform_max;
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2396
2397
2398
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  	uinfo->count = 2;
  	uinfo->value.integer.min = 0;
d11bb4a92   Peter Ujfalusi   ASoC: core: Fix f...
2399
  	uinfo->value.integer.max = platform_max - min;
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2400
2401
2402
2403
2404
2405
2406
  	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...
2407
   * @ucontrol: control element information
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2408
2409
2410
2411
2412
2413
2414
2415
   *
   * 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...
2416
2417
  	struct soc_mixer_control *mc =
  		(struct soc_mixer_control *)kcontrol->private_value;
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2418
  	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
815ecf8de   Jon Smirl   ALSA: ASoC: conve...
2419
  	unsigned int reg = mc->reg;
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2420
  	int min = mc->min;
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
  	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...
2434
   * @ucontrol: control element information
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2435
2436
2437
2438
2439
2440
2441
2442
   *
   * 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...
2443
2444
  	struct soc_mixer_control *mc =
  		(struct soc_mixer_control *)kcontrol->private_value;
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2445
  	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
815ecf8de   Jon Smirl   ALSA: ASoC: conve...
2446
  	unsigned int reg = mc->reg;
4eaa9819d   Jon Smirl   ALSA: ASoC: Conve...
2447
  	int min = mc->min;
46f5822f7   Daniel Ribeiro   ASoC: Allow 32 bi...
2448
  	unsigned int val;
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2449
2450
2451
  
  	val = (ucontrol->value.integer.value[0]+min) & 0xff;
  	val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8;
6c508c62f   Eero Nurkkala   ASoC: refactor sn...
2452
  	return snd_soc_update_bits_locked(codec, reg, 0xffff, val);
e13ac2e9b   Mark Brown   [ALSA] ASoC: Add ...
2453
2454
  }
  EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8);
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2455
  /**
637d3847b   Peter Ujfalusi   ASoC: core: Suppo...
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
   * 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...
2467
  	struct snd_card *card = codec->card->snd_card;
637d3847b   Peter Ujfalusi   ASoC: core: Suppo...
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
  	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...
2486
  			mc->platform_max = max;
637d3847b   Peter Ujfalusi   ASoC: core: Suppo...
2487
2488
2489
2490
2491
2492
2493
2494
  			ret = 0;
  		}
  	}
  	return ret;
  }
  EXPORT_SYMBOL_GPL(snd_soc_limit_volume);
  
  /**
b6f4bb383   apatard@mandriva.com   ASoC: Add SOC_DOU...
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
   * 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...
2537
2538
  	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...
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
  	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...
2574
  			return ret;
b6f4bb383   apatard@mandriva.com   ASoC: Add SOC_DOU...
2575
2576
2577
2578
  	}
  	if (ovalr != valr) {
  		ret = snd_soc_write(codec, mc->rreg, valr);
  		if (ret < 0)
f1df5aec6   Mark Brown   ASoC: Pay attenti...
2579
  			return ret;
b6f4bb383   apatard@mandriva.com   ASoC: Add SOC_DOU...
2580
2581
2582
2583
2584
2585
2586
  	}
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx);
  
  /**
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
   * 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...
2598
2599
  	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...
2600
2601
2602
  	else if (dai->codec && dai->codec->driver->set_sysclk)
  		return dai->codec->driver->set_sysclk(dai->codec, clk_id,
  						      freq, dir);
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2603
2604
2605
2606
2607
2608
  	else
  		return -EINVAL;
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
  
  /**
ec4ee52a8   Mark Brown   ASoC: Provide COD...
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
   * snd_soc_codec_set_sysclk - configure CODEC system or master clock.
   * @codec: CODEC
   * @clk_id: DAI specific clock ID
   * @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,
  	unsigned int freq, int dir)
  {
  	if (codec->driver->set_sysclk)
  		return codec->driver->set_sysclk(codec, clk_id, freq, dir);
  	else
  		return -EINVAL;
  }
  EXPORT_SYMBOL_GPL(snd_soc_codec_set_sysclk);
  
  /**
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2628
2629
   * snd_soc_dai_set_clkdiv - configure DAI clock dividers.
   * @dai: DAI
ac11a2b35   Mark Brown   ASoC: Clean up ke...
2630
   * @div_id: DAI specific clock divider ID
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2631
2632
2633
2634
2635
2636
2637
2638
2639
   * @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...
2640
2641
  	if (dai->driver && dai->driver->ops->set_clkdiv)
  		return dai->driver->ops->set_clkdiv(dai, div_id, div);
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2642
2643
2644
2645
2646
2647
2648
2649
2650
  	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 ...
2651
   * @source: DAI specific source for the PLL
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2652
2653
2654
2655
2656
   * @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 ...
2657
2658
  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 ...
2659
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2660
2661
  	if (dai->driver && dai->driver->ops->set_pll)
  		return dai->driver->ops->set_pll(dai, pll_id, source,
85488037b   Mark Brown   ASoC: Add source ...
2662
  					 freq_in, freq_out);
ec4ee52a8   Mark Brown   ASoC: Provide COD...
2663
2664
2665
  	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 ...
2666
2667
2668
2669
  	else
  		return -EINVAL;
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
ec4ee52a8   Mark Brown   ASoC: Provide COD...
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
  /*
   * 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 ...
2690
2691
2692
  /**
   * snd_soc_dai_set_fmt - configure DAI hardware audio format.
   * @dai: DAI
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2693
2694
2695
2696
2697
2698
   * @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...
2699
2700
  	if (dai->driver && dai->driver->ops->set_fmt)
  		return dai->driver->ops->set_fmt(dai, fmt);
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2701
2702
2703
2704
2705
2706
2707
2708
  	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_...
2709
2710
   * @tx_mask: bitmask representing active TX slots.
   * @rx_mask: bitmask representing active RX slots.
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2711
   * @slots: Number of slots in use.
a5479e389   Daniel Ribeiro   ASoC: change set_...
2712
   * @slot_width: Width in bits for each slot.
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2713
2714
2715
2716
2717
   *
   * 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_...
2718
  	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2719
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2720
2721
  	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_...
2722
  				slots, slot_width);
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2723
2724
2725
2726
2727
2728
  	else
  		return -EINVAL;
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
  
  /**
472df3cba   Barry Song   ASoC: Provide API...
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
   * 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...
2744
2745
  	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...
2746
2747
2748
2749
2750
2751
2752
  			rx_num, rx_slot);
  	else
  		return -EINVAL;
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
  
  /**
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2753
2754
2755
2756
2757
2758
2759
2760
   * 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...
2761
2762
  	if (dai->driver && dai->driver->ops->set_tristate)
  		return dai->driver->ops->set_tristate(dai, tristate);
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
  	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...
2777
2778
  	if (dai->driver && dai->driver->ops->digital_mute)
  		return dai->driver->ops->digital_mute(dai, mute);
8c6529dbf   Liam Girdwood   ALSA: asoc: core ...
2779
2780
2781
2782
  	else
  		return -EINVAL;
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
c5af3a2e1   Mark Brown   ASoC: Add card re...
2783
2784
2785
  /**
   * snd_soc_register_card - Register a card with the ASoC core
   *
ac11a2b35   Mark Brown   ASoC: Clean up ke...
2786
   * @card: Card to register
c5af3a2e1   Mark Brown   ASoC: Add card re...
2787
   *
c5af3a2e1   Mark Brown   ASoC: Add card re...
2788
   */
70a7ca34d   Vinod Koul   ASoC: soc core al...
2789
  int snd_soc_register_card(struct snd_soc_card *card)
c5af3a2e1   Mark Brown   ASoC: Add card re...
2790
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2791
  	int i;
c5af3a2e1   Mark Brown   ASoC: Add card re...
2792
2793
  	if (!card->name || !card->dev)
  		return -EINVAL;
ed77cc122   Mark Brown   ASoC: Don't crash...
2794
  	dev_set_drvdata(card->dev, card);
111c6419f   Stephen Warren   ASoC: Move card l...
2795
  	snd_soc_initialize_card_lists(card);
150dd2f8c   Vinod Koul   ASoC: soc core mo...
2796
  	soc_init_card_debugfs(card);
2eea392d0   Jarkko Nikula   ASoC: Add support...
2797
2798
2799
  	card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) *
  			    (card->num_links + card->num_aux_devs),
  			    GFP_KERNEL);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2800
2801
  	if (card->rtd == NULL)
  		return -ENOMEM;
2eea392d0   Jarkko Nikula   ASoC: Add support...
2802
  	card->rtd_aux = &card->rtd[card->num_links];
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2803
2804
2805
  
  	for (i = 0; i < card->num_links; i++)
  		card->rtd[i].dai_link = &card->dai_link[i];
c5af3a2e1   Mark Brown   ASoC: Add card re...
2806
2807
  	INIT_LIST_HEAD(&card->list);
  	card->instantiated = 0;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2808
  	mutex_init(&card->mutex);
c5af3a2e1   Mark Brown   ASoC: Add card re...
2809
2810
2811
  
  	mutex_lock(&client_mutex);
  	list_add(&card->list, &card_list);
435c5e258   Mark Brown   ASoC: Initial fra...
2812
  	snd_soc_instantiate_cards();
c5af3a2e1   Mark Brown   ASoC: Add card re...
2813
2814
2815
2816
2817
2818
2819
  	mutex_unlock(&client_mutex);
  
  	dev_dbg(card->dev, "Registered card '%s'
  ", card->name);
  
  	return 0;
  }
70a7ca34d   Vinod Koul   ASoC: soc core al...
2820
  EXPORT_SYMBOL_GPL(snd_soc_register_card);
c5af3a2e1   Mark Brown   ASoC: Add card re...
2821
2822
2823
2824
  
  /**
   * snd_soc_unregister_card - Unregister a card with the ASoC core
   *
ac11a2b35   Mark Brown   ASoC: Clean up ke...
2825
   * @card: Card to unregister
c5af3a2e1   Mark Brown   ASoC: Add card re...
2826
   *
c5af3a2e1   Mark Brown   ASoC: Add card re...
2827
   */
70a7ca34d   Vinod Koul   ASoC: soc core al...
2828
  int snd_soc_unregister_card(struct snd_soc_card *card)
c5af3a2e1   Mark Brown   ASoC: Add card re...
2829
  {
b0e264855   Vinod Koul   ASoC: soc core mo...
2830
2831
  	if (card->instantiated)
  		soc_cleanup_card_resources(card);
c5af3a2e1   Mark Brown   ASoC: Add card re...
2832
2833
2834
  	mutex_lock(&client_mutex);
  	list_del(&card->list);
  	mutex_unlock(&client_mutex);
c5af3a2e1   Mark Brown   ASoC: Add card re...
2835
2836
2837
2838
2839
  	dev_dbg(card->dev, "Unregistered card '%s'
  ", card->name);
  
  	return 0;
  }
70a7ca34d   Vinod Koul   ASoC: soc core al...
2840
  EXPORT_SYMBOL_GPL(snd_soc_unregister_card);
c5af3a2e1   Mark Brown   ASoC: Add card re...
2841

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2842
2843
2844
2845
  /*
   * Simplify DAI link configuration by removing ".-1" from device names
   * and sanitizing names.
   */
0b9a214a6   Dimitris Papastamos   ASoC: soc-core: R...
2846
  static char *fmt_single_name(struct device *dev, int *id)
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2847
2848
2849
2850
2851
2852
  {
  	char *found, name[NAME_SIZE];
  	int id1, id2;
  
  	if (dev_name(dev) == NULL)
  		return NULL;
58818a77c   Dimitris Papastamos   ASoC: soc-core: R...
2853
  	strlcpy(name, dev_name(dev), NAME_SIZE);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
  
  	/* 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...
2872
  			*id = ((id1 & 0xffff) << 16) + id2;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2873
2874
2875
  
  			/* sanitize component name for DAI link creation */
  			snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, name);
58818a77c   Dimitris Papastamos   ASoC: soc-core: R...
2876
  			strlcpy(name, tmp, NAME_SIZE);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
  		} 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...
2900
2901
2902
  /**
   * snd_soc_register_dai - Register a DAI with the ASoC core
   *
ac11a2b35   Mark Brown   ASoC: Clean up ke...
2903
   * @dai: DAI to register
9115171a6   Mark Brown   ASoC: Add DAI reg...
2904
   */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2905
2906
  int snd_soc_register_dai(struct device *dev,
  		struct snd_soc_dai_driver *dai_drv)
9115171a6   Mark Brown   ASoC: Add DAI reg...
2907
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2908
2909
2910
2911
  	struct snd_soc_dai *dai;
  
  	dev_dbg(dev, "dai register %s
  ", dev_name(dev));
9115171a6   Mark Brown   ASoC: Add DAI reg...
2912

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

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2917
2918
2919
2920
2921
2922
  	/* 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 ...
2923

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2924
2925
2926
2927
  	dai->dev = dev;
  	dai->driver = dai_drv;
  	if (!dai->driver->ops)
  		dai->driver->ops = &null_dai_ops;
9115171a6   Mark Brown   ASoC: Add DAI reg...
2928
2929
2930
  
  	mutex_lock(&client_mutex);
  	list_add(&dai->list, &dai_list);
435c5e258   Mark Brown   ASoC: Initial fra...
2931
  	snd_soc_instantiate_cards();
9115171a6   Mark Brown   ASoC: Add DAI reg...
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
  	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...
2944
   * @dai: DAI to unregister
9115171a6   Mark Brown   ASoC: Add DAI reg...
2945
   */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2946
  void snd_soc_unregister_dai(struct device *dev)
9115171a6   Mark Brown   ASoC: Add DAI reg...
2947
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2948
2949
2950
2951
2952
2953
2954
2955
2956
  	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...
2957
2958
2959
2960
2961
2962
  	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...
2963
2964
  	kfree(dai->name);
  	kfree(dai);
9115171a6   Mark Brown   ASoC: Add DAI reg...
2965
2966
2967
2968
2969
2970
  }
  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...
2971
2972
   * @dai: Array of DAIs to register
   * @count: Number of DAIs
9115171a6   Mark Brown   ASoC: Add DAI reg...
2973
   */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2974
2975
  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...
2976
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2977
2978
  	struct snd_soc_dai *dai;
  	int i, ret = 0;
720ffa4cf   Liam Girdwood   ASoC: core - fix ...
2979
2980
  	dev_dbg(dev, "dai register %s #%Zu
  ", dev_name(dev), count);
9115171a6   Mark Brown   ASoC: Add DAI reg...
2981
2982
  
  	for (i = 0; i < count; i++) {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2983
2984
  
  		dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
c46e0079c   Axel Lin   ASoC: Fix snd_soc...
2985
2986
2987
2988
  		if (dai == NULL) {
  			ret = -ENOMEM;
  			goto err;
  		}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2989
2990
2991
2992
2993
2994
  
  		/* 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...
2995
  			goto err;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2996
2997
2998
  		}
  
  		dai->dev = dev;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
2999
  		dai->driver = &dai_drv[i];
0f9141c97   Mark Brown   ASoC: Pay attenti...
3000
3001
3002
3003
  		if (dai->driver->id)
  			dai->id = dai->driver->id;
  		else
  			dai->id = i;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3004
3005
3006
3007
3008
3009
3010
3011
3012
  		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...
3013
  	}
1dcb4f38e   Axel Lin   ASoC: Hold client...
3014
  	mutex_lock(&client_mutex);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3015
  	snd_soc_instantiate_cards();
1dcb4f38e   Axel Lin   ASoC: Hold client...
3016
  	mutex_unlock(&client_mutex);
9115171a6   Mark Brown   ASoC: Add DAI reg...
3017
3018
3019
3020
  	return 0;
  
  err:
  	for (i--; i >= 0; i--)
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3021
  		snd_soc_unregister_dai(dev);
9115171a6   Mark Brown   ASoC: Add DAI reg...
3022
3023
3024
3025
3026
3027
3028
3029
  
  	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...
3030
3031
   * @dai: Array of DAIs to unregister
   * @count: Number of DAIs
9115171a6   Mark Brown   ASoC: Add DAI reg...
3032
   */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3033
  void snd_soc_unregister_dais(struct device *dev, size_t count)
9115171a6   Mark Brown   ASoC: Add DAI reg...
3034
3035
3036
3037
  {
  	int i;
  
  	for (i = 0; i < count; i++)
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3038
  		snd_soc_unregister_dai(dev);
9115171a6   Mark Brown   ASoC: Add DAI reg...
3039
3040
  }
  EXPORT_SYMBOL_GPL(snd_soc_unregister_dais);
12a48a8c0   Mark Brown   ASoC: Add platfor...
3041
3042
3043
  /**
   * snd_soc_register_platform - Register a platform with the ASoC core
   *
ac11a2b35   Mark Brown   ASoC: Clean up ke...
3044
   * @platform: platform to register
12a48a8c0   Mark Brown   ASoC: Add platfor...
3045
   */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3046
3047
  int snd_soc_register_platform(struct device *dev,
  		struct snd_soc_platform_driver *platform_drv)
12a48a8c0   Mark Brown   ASoC: Add platfor...
3048
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3049
3050
3051
3052
3053
3054
3055
  	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...
3056
  		return -ENOMEM;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3057
3058
3059
3060
3061
3062
3063
  
  	/* 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...
3064

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3065
3066
  	platform->dev = dev;
  	platform->driver = platform_drv;
b79506413   Liam Girdwood   ASoC: core - Add ...
3067
3068
  	platform->dapm.dev = dev;
  	platform->dapm.platform = platform;
12a48a8c0   Mark Brown   ASoC: Add platfor...
3069
3070
3071
  
  	mutex_lock(&client_mutex);
  	list_add(&platform->list, &platform_list);
435c5e258   Mark Brown   ASoC: Initial fra...
3072
  	snd_soc_instantiate_cards();
12a48a8c0   Mark Brown   ASoC: Add platfor...
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
  	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...
3085
   * @platform: platform to unregister
12a48a8c0   Mark Brown   ASoC: Add platfor...
3086
   */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3087
  void snd_soc_unregister_platform(struct device *dev)
12a48a8c0   Mark Brown   ASoC: Add platfor...
3088
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3089
3090
3091
3092
3093
3094
3095
3096
3097
  	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...
3098
3099
3100
3101
3102
3103
  	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...
3104
3105
  	kfree(platform->name);
  	kfree(platform);
12a48a8c0   Mark Brown   ASoC: Add platfor...
3106
3107
  }
  EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
151ab22cf   Mark Brown   ASoC: Fix up CODE...
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
  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...
3140
3141
3142
  /**
   * snd_soc_register_codec - Register a codec with the ASoC core
   *
ac11a2b35   Mark Brown   ASoC: Clean up ke...
3143
   * @codec: codec to register
0d0cf00a7   Mark Brown   ASoC: Add codec r...
3144
   */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3145
  int snd_soc_register_codec(struct device *dev,
001ae4c03   Mark Brown   ASoC: Constify st...
3146
3147
3148
  			   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...
3149
  {
3335ddca9   Dimitris Papastamos   ASoC: soc-cache: ...
3150
  	size_t reg_size;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3151
3152
  	struct snd_soc_codec *codec;
  	int ret, i;
151ab22cf   Mark Brown   ASoC: Fix up CODE...
3153

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3154
3155
3156
3157
3158
3159
  	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...
3160

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3161
3162
3163
3164
3165
3166
  	/* 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...
3167
3168
3169
3170
  	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...
3171
3172
  	codec->write = codec_drv->write;
  	codec->read = codec_drv->read;
1500b7b5f   Dimitris Papastamos   ASoC: Automatical...
3173
3174
  	codec->volatile_register = codec_drv->volatile_register;
  	codec->readable_register = codec_drv->readable_register;
8020454c9   Dimitris Papastamos   ASoC: Add default...
3175
  	codec->writable_register = codec_drv->writable_register;
ce6120cca   Liam Girdwood   ASoC: Decouple DA...
3176
3177
3178
  	codec->dapm.bias_level = SND_SOC_BIAS_OFF;
  	codec->dapm.dev = dev;
  	codec->dapm.codec = codec;
474b62d6e   Mark Brown   ASoC: Provide per...
3179
  	codec->dapm.seq_notifier = codec_drv->seq_notifier;
7a30a3db3   Dimitris Papastamos   ASoC: soc-cache: ...
3180
3181
3182
3183
  	codec->dev = dev;
  	codec->driver = codec_drv;
  	codec->num_dai = num_dai;
  	mutex_init(&codec->mutex);
ce6120cca   Liam Girdwood   ASoC: Decouple DA...
3184

f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3185
3186
  	/* allocate CODEC register cache */
  	if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
3335ddca9   Dimitris Papastamos   ASoC: soc-cache: ...
3187
  		reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
aea170a09   Dimitris Papastamos   ASoC: soc-cache: ...
3188
  		codec->reg_size = reg_size;
3335ddca9   Dimitris Papastamos   ASoC: soc-cache: ...
3189
3190
3191
3192
3193
3194
  		/* 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...
3195
3196
3197
3198
3199
3200
3201
  		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...
3202
  		}
151ab22cf   Mark Brown   ASoC: Fix up CODE...
3203
  	}
1500b7b5f   Dimitris Papastamos   ASoC: Automatical...
3204
3205
3206
3207
3208
  	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...
3209
3210
  		if (!codec->writable_register)
  			codec->writable_register = snd_soc_default_writable_register;
1500b7b5f   Dimitris Papastamos   ASoC: Automatical...
3211
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3212
3213
3214
3215
  	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 ...
3216
3217
3218
3219
  	/* 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...
3220
  			goto fail;
26b01ccdc   Mark Brown   ASoC: Don't call ...
3221
  	}
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3222

0d0cf00a7   Mark Brown   ASoC: Add codec r...
3223
3224
3225
3226
3227
3228
3229
  	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...
3230
  	return 0;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3231

fdf0f54da   Dimitris Papastamos   ASoC: soc-core: A...
3232
  fail:
3335ddca9   Dimitris Papastamos   ASoC: soc-cache: ...
3233
3234
  	kfree(codec->reg_def_copy);
  	codec->reg_def_copy = NULL;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3235
3236
3237
  	kfree(codec->name);
  	kfree(codec);
  	return ret;
0d0cf00a7   Mark Brown   ASoC: Add codec r...
3238
3239
3240
3241
3242
3243
  }
  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...
3244
   * @codec: codec to unregister
0d0cf00a7   Mark Brown   ASoC: Add codec r...
3245
   */
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3246
  void snd_soc_unregister_codec(struct device *dev)
0d0cf00a7   Mark Brown   ASoC: Add codec r...
3247
  {
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
  	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 ...
3258
3259
3260
  	if (codec->num_dai)
  		for (i = 0; i < codec->num_dai; i++)
  			snd_soc_unregister_dai(dev);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3261

0d0cf00a7   Mark Brown   ASoC: Add codec r...
3262
3263
3264
3265
3266
3267
  	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...
3268

7a30a3db3   Dimitris Papastamos   ASoC: soc-cache: ...
3269
  	snd_soc_cache_exit(codec);
3335ddca9   Dimitris Papastamos   ASoC: soc-cache: ...
3270
  	kfree(codec->reg_def_copy);
1aafcd4d6   Dimitris Papastamos   ASoC: soc-core: F...
3271
  	kfree(codec->name);
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
3272
  	kfree(codec);
0d0cf00a7   Mark Brown   ASoC: Add codec r...
3273
3274
  }
  EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
c9b3a40ff   Takashi Iwai   ALSA: ASoC - Fix ...
3275
  static int __init snd_soc_init(void)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
3276
  {
384c89e2e   Mark Brown   ASoC: Push debugf...
3277
  #ifdef CONFIG_DEBUG_FS
8a9dab1a5   Mark Brown   ASoC: Update name...
3278
3279
  	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...
3280
3281
3282
  		printk(KERN_WARNING
  		       "ASoC: Failed to create debugfs directory
  ");
8a9dab1a5   Mark Brown   ASoC: Update name...
3283
  		snd_soc_debugfs_root = NULL;
384c89e2e   Mark Brown   ASoC: Push debugf...
3284
  	}
c3c5a19a5   Mark Brown   ASoC: Add debugfs...
3285

8a9dab1a5   Mark Brown   ASoC: Update name...
3286
  	if (!debugfs_create_file("codecs", 0444, snd_soc_debugfs_root, NULL,
c3c5a19a5   Mark Brown   ASoC: Add debugfs...
3287
3288
3289
  				 &codec_list_fops))
  		pr_warn("ASoC: Failed to create CODEC list debugfs file
  ");
8a9dab1a5   Mark Brown   ASoC: Update name...
3290
  	if (!debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL,
f32087803   Mark Brown   ASoC: Add DAI lis...
3291
3292
3293
  				 &dai_list_fops))
  		pr_warn("ASoC: Failed to create DAI list debugfs file
  ");
19c7ac27a   Mark Brown   ASoC: Add platfor...
3294

8a9dab1a5   Mark Brown   ASoC: Update name...
3295
  	if (!debugfs_create_file("platforms", 0444, snd_soc_debugfs_root, NULL,
19c7ac27a   Mark Brown   ASoC: Add platfor...
3296
3297
3298
  				 &platform_list_fops))
  		pr_warn("ASoC: Failed to create platform list debugfs file
  ");
384c89e2e   Mark Brown   ASoC: Push debugf...
3299
  #endif
fb257897b   Mark Brown   ASoC: Work around...
3300
  	snd_soc_util_init();
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
3301
3302
  	return platform_driver_register(&soc_driver);
  }
4abe8e16a   Mark Brown   ASoC: Move soc-co...
3303
  module_init(snd_soc_init);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
3304

7d8c16a6f   Mark Brown   ASoC: Annotate co...
3305
  static void __exit snd_soc_exit(void)
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
3306
  {
fb257897b   Mark Brown   ASoC: Work around...
3307
  	snd_soc_util_exit();
384c89e2e   Mark Brown   ASoC: Push debugf...
3308
  #ifdef CONFIG_DEBUG_FS
8a9dab1a5   Mark Brown   ASoC: Update name...
3309
  	debugfs_remove_recursive(snd_soc_debugfs_root);
384c89e2e   Mark Brown   ASoC: Push debugf...
3310
  #endif
3ff3f64ba   Mark Brown   [ALSA] ASoC: core...
3311
  	platform_driver_unregister(&soc_driver);
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
3312
  }
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
3313
3314
3315
  module_exit(snd_soc_exit);
  
  /* Module information */
d331124dc   Liam Girdwood   ALSA: ASoC: updat...
3316
  MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
db2a41655   Frank Mandarino   [ALSA] ASoC: core...
3317
3318
  MODULE_DESCRIPTION("ALSA SoC Core");
  MODULE_LICENSE("GPL");
8b45a2099   Kay Sievers   [ALSA] sound: fix...
3319
  MODULE_ALIAS("platform:soc-audio");