diff options
Diffstat (limited to 'sound/soc/soc-core.c')
-rw-r--r-- | sound/soc/soc-core.c | 1920 |
1 files changed, 1920 insertions, 0 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c new file mode 100644 index 000000000000..e841ad46c759 --- /dev/null +++ b/sound/soc/soc-core.c | |||
@@ -0,0 +1,1920 @@ | |||
1 | /* | ||
2 | * soc-core.c -- ALSA SoC Audio Layer | ||
3 | * | ||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
5 | * Author: Liam Girdwood | ||
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * Revision history | ||
14 | * 12th Aug 2005 Initial version. | ||
15 | * 25th Oct 2005 Working Codec, Interface and Platform registration. | ||
16 | * | ||
17 | * TODO: | ||
18 | * o Add hw rules to enforce rates, etc. | ||
19 | * o More testing with other codecs/machines. | ||
20 | * o Add more codecs and platforms to ensure good API coverage. | ||
21 | * o Support TDM on PCM and I2S | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/moduleparam.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/pm.h> | ||
29 | #include <linux/bitops.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <sound/driver.h> | ||
32 | #include <sound/core.h> | ||
33 | #include <sound/pcm.h> | ||
34 | #include <sound/pcm_params.h> | ||
35 | #include <sound/soc.h> | ||
36 | #include <sound/soc-dapm.h> | ||
37 | #include <sound/initval.h> | ||
38 | |||
39 | /* debug */ | ||
40 | #define SOC_DEBUG 0 | ||
41 | #if SOC_DEBUG | ||
42 | #define dbg(format, arg...) printk(format, ## arg) | ||
43 | #else | ||
44 | #define dbg(format, arg...) | ||
45 | #endif | ||
46 | /* debug DAI capabilities matching */ | ||
47 | #define SOC_DEBUG_DAI 0 | ||
48 | #if SOC_DEBUG_DAI | ||
49 | #define dbgc(format, arg...) printk(format, ## arg) | ||
50 | #else | ||
51 | #define dbgc(format, arg...) | ||
52 | #endif | ||
53 | |||
54 | static DEFINE_MUTEX(pcm_mutex); | ||
55 | static DEFINE_MUTEX(io_mutex); | ||
56 | static struct workqueue_struct *soc_workq; | ||
57 | static struct work_struct soc_stream_work; | ||
58 | static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); | ||
59 | |||
60 | /* supported sample rates */ | ||
61 | /* ATTENTION: these values depend on the definition in pcm.h! */ | ||
62 | static const unsigned int rates[] = { | ||
63 | 5512, 8000, 11025, 16000, 22050, 32000, 44100, | ||
64 | 48000, 64000, 88200, 96000, 176400, 192000 | ||
65 | }; | ||
66 | |||
67 | /* | ||
68 | * This is a timeout to do a DAPM powerdown after a stream is closed(). | ||
69 | * It can be used to eliminate pops between different playback streams, e.g. | ||
70 | * between two audio tracks. | ||
71 | */ | ||
72 | static int pmdown_time = 5000; | ||
73 | module_param(pmdown_time, int, 0); | ||
74 | MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); | ||
75 | |||
76 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
77 | /* unregister ac97 codec */ | ||
78 | static int soc_ac97_dev_unregister(struct snd_soc_codec *codec) | ||
79 | { | ||
80 | if (codec->ac97->dev.bus) | ||
81 | device_unregister(&codec->ac97->dev); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | /* stop no dev release warning */ | ||
86 | static void soc_ac97_device_release(struct device *dev){} | ||
87 | |||
88 | /* register ac97 codec to bus */ | ||
89 | static int soc_ac97_dev_register(struct snd_soc_codec *codec) | ||
90 | { | ||
91 | int err; | ||
92 | |||
93 | codec->ac97->dev.bus = &ac97_bus_type; | ||
94 | codec->ac97->dev.parent = NULL; | ||
95 | codec->ac97->dev.release = soc_ac97_device_release; | ||
96 | |||
97 | snprintf(codec->ac97->dev.bus_id, BUS_ID_SIZE, "%d-%d:%s", | ||
98 | codec->card->number, 0, codec->name); | ||
99 | err = device_register(&codec->ac97->dev); | ||
100 | if (err < 0) { | ||
101 | snd_printk(KERN_ERR "Can't register ac97 bus\n"); | ||
102 | codec->ac97->dev.bus = NULL; | ||
103 | return err; | ||
104 | } | ||
105 | return 0; | ||
106 | } | ||
107 | #endif | ||
108 | |||
109 | static inline const char* get_dai_name(int type) | ||
110 | { | ||
111 | switch(type) { | ||
112 | case SND_SOC_DAI_AC97: | ||
113 | return "AC97"; | ||
114 | case SND_SOC_DAI_I2S: | ||
115 | return "I2S"; | ||
116 | case SND_SOC_DAI_PCM: | ||
117 | return "PCM"; | ||
118 | } | ||
119 | return NULL; | ||
120 | } | ||
121 | |||
122 | /* get rate format from rate */ | ||
123 | static inline int soc_get_rate_format(int rate) | ||
124 | { | ||
125 | int i; | ||
126 | |||
127 | for (i = 0; i < ARRAY_SIZE(rates); i++) { | ||
128 | if (rates[i] == rate) | ||
129 | return 1 << i; | ||
130 | } | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | /* gets the audio system mclk/sysclk for the given parameters */ | ||
135 | static unsigned inline int soc_get_mclk(struct snd_soc_pcm_runtime *rtd, | ||
136 | struct snd_soc_clock_info *info) | ||
137 | { | ||
138 | struct snd_soc_device *socdev = rtd->socdev; | ||
139 | struct snd_soc_machine *machine = socdev->machine; | ||
140 | int i; | ||
141 | |||
142 | /* find the matching machine config and get it's mclk for the given | ||
143 | * sample rate and hardware format */ | ||
144 | for(i = 0; i < machine->num_links; i++) { | ||
145 | if (machine->dai_link[i].cpu_dai == rtd->cpu_dai && | ||
146 | machine->dai_link[i].config_sysclk) | ||
147 | return machine->dai_link[i].config_sysclk(rtd, info); | ||
148 | } | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | /* changes a bitclk multiplier mask to a divider mask */ | ||
153 | static u16 soc_bfs_mult_to_div(u16 bfs, int rate, unsigned int mclk, | ||
154 | unsigned int pcmfmt, unsigned int chn) | ||
155 | { | ||
156 | int i, j; | ||
157 | u16 bfs_ = 0; | ||
158 | int size = snd_pcm_format_physical_width(pcmfmt), min = 0; | ||
159 | |||
160 | if (size <= 0) | ||
161 | return 0; | ||
162 | |||
163 | /* the minimum bit clock that has enough bandwidth */ | ||
164 | min = size * rate * chn; | ||
165 | dbgc("mult --> div min bclk %d with mclk %d\n", min, mclk); | ||
166 | |||
167 | for (i = 0; i < 16; i++) { | ||
168 | if ((bfs >> i) & 0x1) { | ||
169 | j = rate * SND_SOC_FSB_REAL(1<<i); | ||
170 | |||
171 | if (j >= min) { | ||
172 | bfs_ |= SND_SOC_FSBD(mclk/j); | ||
173 | dbgc("mult --> div support mult %d\n", | ||
174 | SND_SOC_FSB_REAL(1<<i)); | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | |||
179 | return bfs_; | ||
180 | } | ||
181 | |||
182 | /* changes a bitclk divider mask to a multiplier mask */ | ||
183 | static u16 soc_bfs_div_to_mult(u16 bfs, int rate, unsigned int mclk, | ||
184 | unsigned int pcmfmt, unsigned int chn) | ||
185 | { | ||
186 | int i, j; | ||
187 | u16 bfs_ = 0; | ||
188 | |||
189 | int size = snd_pcm_format_physical_width(pcmfmt), min = 0; | ||
190 | |||
191 | if (size <= 0) | ||
192 | return 0; | ||
193 | |||
194 | /* the minimum bit clock that has enough bandwidth */ | ||
195 | min = size * rate * chn; | ||
196 | dbgc("div to mult min bclk %d with mclk %d\n", min, mclk); | ||
197 | |||
198 | for (i = 0; i < 16; i++) { | ||
199 | if ((bfs >> i) & 0x1) { | ||
200 | j = mclk / (SND_SOC_FSBD_REAL(1<<i)); | ||
201 | if (j >= min) { | ||
202 | bfs_ |= SND_SOC_FSB(j/rate); | ||
203 | dbgc("div --> mult support div %d\n", | ||
204 | SND_SOC_FSBD_REAL(1<<i)); | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | |||
209 | return bfs_; | ||
210 | } | ||
211 | |||
212 | /* Matches codec DAI and SoC CPU DAI hardware parameters */ | ||
213 | static int soc_hw_match_params(struct snd_pcm_substream *substream, | ||
214 | struct snd_pcm_hw_params *params) | ||
215 | { | ||
216 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
217 | struct snd_soc_dai_mode *codec_dai_mode = NULL; | ||
218 | struct snd_soc_dai_mode *cpu_dai_mode = NULL; | ||
219 | struct snd_soc_clock_info clk_info; | ||
220 | unsigned int fs, mclk, codec_bfs, cpu_bfs, rate = params_rate(params), | ||
221 | chn, j, k, cpu_bclk, codec_bclk, pcmrate; | ||
222 | u16 fmt = 0; | ||
223 | |||
224 | dbg("asoc: match version %s\n", SND_SOC_VERSION); | ||
225 | clk_info.rate = rate; | ||
226 | pcmrate = soc_get_rate_format(rate); | ||
227 | |||
228 | /* try and find a match from the codec and cpu DAI capabilities */ | ||
229 | for (j = 0; j < rtd->codec_dai->caps.num_modes; j++) { | ||
230 | for (k = 0; k < rtd->cpu_dai->caps.num_modes; k++) { | ||
231 | codec_dai_mode = &rtd->codec_dai->caps.mode[j]; | ||
232 | cpu_dai_mode = &rtd->cpu_dai->caps.mode[k]; | ||
233 | |||
234 | if (!(codec_dai_mode->pcmrate & cpu_dai_mode->pcmrate & | ||
235 | pcmrate)) { | ||
236 | dbgc("asoc: DAI[%d:%d] failed to match rate\n", j, k); | ||
237 | continue; | ||
238 | } | ||
239 | |||
240 | fmt = codec_dai_mode->fmt & cpu_dai_mode->fmt; | ||
241 | if (!(fmt & SND_SOC_DAIFMT_FORMAT_MASK)) { | ||
242 | dbgc("asoc: DAI[%d:%d] failed to match format\n", j, k); | ||
243 | continue; | ||
244 | } | ||
245 | |||
246 | if (!(fmt & SND_SOC_DAIFMT_CLOCK_MASK)) { | ||
247 | dbgc("asoc: DAI[%d:%d] failed to match clock masters\n", | ||
248 | j, k); | ||
249 | continue; | ||
250 | } | ||
251 | |||
252 | if (!(fmt & SND_SOC_DAIFMT_INV_MASK)) { | ||
253 | dbgc("asoc: DAI[%d:%d] failed to match invert\n", j, k); | ||
254 | continue; | ||
255 | } | ||
256 | |||
257 | if (!(codec_dai_mode->pcmfmt & cpu_dai_mode->pcmfmt)) { | ||
258 | dbgc("asoc: DAI[%d:%d] failed to match pcm format\n", j, k); | ||
259 | continue; | ||
260 | } | ||
261 | |||
262 | if (!(codec_dai_mode->pcmdir & cpu_dai_mode->pcmdir)) { | ||
263 | dbgc("asoc: DAI[%d:%d] failed to match direction\n", j, k); | ||
264 | continue; | ||
265 | } | ||
266 | |||
267 | /* todo - still need to add tdm selection */ | ||
268 | rtd->cpu_dai->dai_runtime.fmt = | ||
269 | rtd->codec_dai->dai_runtime.fmt = | ||
270 | 1 << (ffs(fmt & SND_SOC_DAIFMT_FORMAT_MASK) -1) | | ||
271 | 1 << (ffs(fmt & SND_SOC_DAIFMT_CLOCK_MASK) - 1) | | ||
272 | 1 << (ffs(fmt & SND_SOC_DAIFMT_INV_MASK) - 1); | ||
273 | clk_info.bclk_master = | ||
274 | rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK; | ||
275 | |||
276 | /* make sure the ratio between rate and master | ||
277 | * clock is acceptable*/ | ||
278 | fs = (cpu_dai_mode->fs & codec_dai_mode->fs); | ||
279 | if (fs == 0) { | ||
280 | dbgc("asoc: DAI[%d:%d] failed to match FS\n", j, k); | ||
281 | continue; | ||
282 | } | ||
283 | clk_info.fs = rtd->cpu_dai->dai_runtime.fs = | ||
284 | rtd->codec_dai->dai_runtime.fs = fs; | ||
285 | |||
286 | /* calculate audio system clocking using slowest clocks possible*/ | ||
287 | mclk = soc_get_mclk(rtd, &clk_info); | ||
288 | if (mclk == 0) { | ||
289 | dbgc("asoc: DAI[%d:%d] configuration not clockable\n", j, k); | ||
290 | dbgc("asoc: rate %d fs %d master %x\n", rate, fs, | ||
291 | clk_info.bclk_master); | ||
292 | continue; | ||
293 | } | ||
294 | |||
295 | /* calculate word size (per channel) and frame size */ | ||
296 | rtd->codec_dai->dai_runtime.pcmfmt = | ||
297 | rtd->cpu_dai->dai_runtime.pcmfmt = | ||
298 | 1 << params_format(params); | ||
299 | |||
300 | chn = params_channels(params); | ||
301 | /* i2s always has left and right */ | ||
302 | if (params_channels(params) == 1 && | ||
303 | rtd->cpu_dai->dai_runtime.fmt & (SND_SOC_DAIFMT_I2S | | ||
304 | SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_LEFT_J)) | ||
305 | chn <<= 1; | ||
306 | |||
307 | /* Calculate bfs - the ratio between bitclock and the sample rate | ||
308 | * We must take into consideration the dividers and multipliers | ||
309 | * used in the codec and cpu DAI modes. We always choose the | ||
310 | * lowest possible clocks to reduce power. | ||
311 | */ | ||
312 | if (codec_dai_mode->flags & cpu_dai_mode->flags & | ||
313 | SND_SOC_DAI_BFS_DIV) { | ||
314 | /* cpu & codec bfs dividers */ | ||
315 | rtd->cpu_dai->dai_runtime.bfs = | ||
316 | rtd->codec_dai->dai_runtime.bfs = | ||
317 | 1 << (fls(codec_dai_mode->bfs & cpu_dai_mode->bfs) - 1); | ||
318 | } else if (codec_dai_mode->flags & SND_SOC_DAI_BFS_DIV) { | ||
319 | /* normalise bfs codec divider & cpu mult */ | ||
320 | codec_bfs = soc_bfs_div_to_mult(codec_dai_mode->bfs, rate, | ||
321 | mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); | ||
322 | rtd->cpu_dai->dai_runtime.bfs = | ||
323 | 1 << (ffs(codec_bfs & cpu_dai_mode->bfs) - 1); | ||
324 | cpu_bfs = soc_bfs_mult_to_div(cpu_dai_mode->bfs, rate, mclk, | ||
325 | rtd->codec_dai->dai_runtime.pcmfmt, chn); | ||
326 | rtd->codec_dai->dai_runtime.bfs = | ||
327 | 1 << (fls(codec_dai_mode->bfs & cpu_bfs) - 1); | ||
328 | } else if (cpu_dai_mode->flags & SND_SOC_DAI_BFS_DIV) { | ||
329 | /* normalise bfs codec mult & cpu divider */ | ||
330 | codec_bfs = soc_bfs_mult_to_div(codec_dai_mode->bfs, rate, | ||
331 | mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); | ||
332 | rtd->cpu_dai->dai_runtime.bfs = | ||
333 | 1 << (fls(codec_bfs & cpu_dai_mode->bfs) -1); | ||
334 | cpu_bfs = soc_bfs_div_to_mult(cpu_dai_mode->bfs, rate, mclk, | ||
335 | rtd->codec_dai->dai_runtime.pcmfmt, chn); | ||
336 | rtd->codec_dai->dai_runtime.bfs = | ||
337 | 1 << (ffs(codec_dai_mode->bfs & cpu_bfs) -1); | ||
338 | } else { | ||
339 | /* codec & cpu bfs rate multipliers */ | ||
340 | rtd->cpu_dai->dai_runtime.bfs = | ||
341 | rtd->codec_dai->dai_runtime.bfs = | ||
342 | 1 << (ffs(codec_dai_mode->bfs & cpu_dai_mode->bfs) -1); | ||
343 | } | ||
344 | |||
345 | /* make sure the bit clock speed is acceptable */ | ||
346 | if (!rtd->cpu_dai->dai_runtime.bfs || | ||
347 | !rtd->codec_dai->dai_runtime.bfs) { | ||
348 | dbgc("asoc: DAI[%d:%d] failed to match BFS\n", j, k); | ||
349 | dbgc("asoc: cpu_dai %x codec %x\n", | ||
350 | rtd->cpu_dai->dai_runtime.bfs, | ||
351 | rtd->codec_dai->dai_runtime.bfs); | ||
352 | dbgc("asoc: mclk %d hwfmt %x\n", mclk, fmt); | ||
353 | continue; | ||
354 | } | ||
355 | |||
356 | goto found; | ||
357 | } | ||
358 | } | ||
359 | printk(KERN_ERR "asoc: no matching DAI found between codec and CPU\n"); | ||
360 | return -EINVAL; | ||
361 | |||
362 | found: | ||
363 | /* we have matching DAI's, so complete the runtime info */ | ||
364 | rtd->codec_dai->dai_runtime.pcmrate = | ||
365 | rtd->cpu_dai->dai_runtime.pcmrate = | ||
366 | soc_get_rate_format(rate); | ||
367 | |||
368 | rtd->codec_dai->dai_runtime.priv = codec_dai_mode->priv; | ||
369 | rtd->cpu_dai->dai_runtime.priv = cpu_dai_mode->priv; | ||
370 | rtd->codec_dai->dai_runtime.flags = codec_dai_mode->flags; | ||
371 | rtd->cpu_dai->dai_runtime.flags = cpu_dai_mode->flags; | ||
372 | |||
373 | /* for debug atm */ | ||
374 | dbg("asoc: DAI[%d:%d] Match OK\n", j, k); | ||
375 | if (rtd->codec_dai->dai_runtime.flags == SND_SOC_DAI_BFS_DIV) { | ||
376 | codec_bclk = (rtd->codec_dai->dai_runtime.fs * params_rate(params)) / | ||
377 | SND_SOC_FSBD_REAL(rtd->codec_dai->dai_runtime.bfs); | ||
378 | dbg("asoc: codec fs %d mclk %d bfs div %d bclk %d\n", | ||
379 | rtd->codec_dai->dai_runtime.fs, mclk, | ||
380 | SND_SOC_FSBD_REAL(rtd->codec_dai->dai_runtime.bfs), codec_bclk); | ||
381 | } else { | ||
382 | codec_bclk = params_rate(params) * | ||
383 | SND_SOC_FSB_REAL(rtd->codec_dai->dai_runtime.bfs); | ||
384 | dbg("asoc: codec fs %d mclk %d bfs mult %d bclk %d\n", | ||
385 | rtd->codec_dai->dai_runtime.fs, mclk, | ||
386 | SND_SOC_FSB_REAL(rtd->codec_dai->dai_runtime.bfs), codec_bclk); | ||
387 | } | ||
388 | if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_DIV) { | ||
389 | cpu_bclk = (rtd->cpu_dai->dai_runtime.fs * params_rate(params)) / | ||
390 | SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs); | ||
391 | dbg("asoc: cpu fs %d mclk %d bfs div %d bclk %d\n", | ||
392 | rtd->cpu_dai->dai_runtime.fs, mclk, | ||
393 | SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk); | ||
394 | } else { | ||
395 | cpu_bclk = params_rate(params) * | ||
396 | SND_SOC_FSB_REAL(rtd->cpu_dai->dai_runtime.bfs); | ||
397 | dbg("asoc: cpu fs %d mclk %d bfs mult %d bclk %d\n", | ||
398 | rtd->cpu_dai->dai_runtime.fs, mclk, | ||
399 | SND_SOC_FSB_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk); | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * Check we have matching bitclocks. If we don't then it means the | ||
404 | * sysclock returned by either the codec or cpu DAI (selected by the | ||
405 | * machine sysclock function) is wrong compared with the supported DAI | ||
406 | * modes for the codec or cpu DAI. | ||
407 | */ | ||
408 | if (cpu_bclk != codec_bclk){ | ||
409 | printk(KERN_ERR | ||
410 | "asoc: codec and cpu bitclocks differ, audio may be wrong speed\n" | ||
411 | ); | ||
412 | printk(KERN_ERR "asoc: codec %d != cpu %d\n", codec_bclk, cpu_bclk); | ||
413 | } | ||
414 | |||
415 | switch(rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK) { | ||
416 | case SND_SOC_DAIFMT_CBM_CFM: | ||
417 | dbg("asoc: DAI codec BCLK master, LRC master\n"); | ||
418 | break; | ||
419 | case SND_SOC_DAIFMT_CBS_CFM: | ||
420 | dbg("asoc: DAI codec BCLK slave, LRC master\n"); | ||
421 | break; | ||
422 | case SND_SOC_DAIFMT_CBM_CFS: | ||
423 | dbg("asoc: DAI codec BCLK master, LRC slave\n"); | ||
424 | break; | ||
425 | case SND_SOC_DAIFMT_CBS_CFS: | ||
426 | dbg("asoc: DAI codec BCLK slave, LRC slave\n"); | ||
427 | break; | ||
428 | } | ||
429 | dbg("asoc: mode %x, invert %x\n", | ||
430 | rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_FORMAT_MASK, | ||
431 | rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_INV_MASK); | ||
432 | dbg("asoc: audio rate %d chn %d fmt %x\n", params_rate(params), | ||
433 | params_channels(params), params_format(params)); | ||
434 | |||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | static inline u32 get_rates(struct snd_soc_dai_mode *modes, int nmodes) | ||
439 | { | ||
440 | int i; | ||
441 | u32 rates = 0; | ||
442 | |||
443 | for(i = 0; i < nmodes; i++) | ||
444 | rates |= modes[i].pcmrate; | ||
445 | |||
446 | return rates; | ||
447 | } | ||
448 | |||
449 | static inline u64 get_formats(struct snd_soc_dai_mode *modes, int nmodes) | ||
450 | { | ||
451 | int i; | ||
452 | u64 formats = 0; | ||
453 | |||
454 | for(i = 0; i < nmodes; i++) | ||
455 | formats |= modes[i].pcmfmt; | ||
456 | |||
457 | return formats; | ||
458 | } | ||
459 | |||
460 | /* | ||
461 | * Called by ALSA when a PCM substream is opened, the runtime->hw record is | ||
462 | * then initialized and any private data can be allocated. This also calls | ||
463 | * startup for the cpu DAI, platform, machine and codec DAI. | ||
464 | */ | ||
465 | static int soc_pcm_open(struct snd_pcm_substream *substream) | ||
466 | { | ||
467 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
468 | struct snd_soc_device *socdev = rtd->socdev; | ||
469 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
470 | struct snd_soc_machine *machine = socdev->machine; | ||
471 | struct snd_soc_platform *platform = socdev->platform; | ||
472 | struct snd_soc_codec_dai *codec_dai = rtd->codec_dai; | ||
473 | struct snd_soc_cpu_dai *cpu_dai = rtd->cpu_dai; | ||
474 | int ret = 0; | ||
475 | |||
476 | mutex_lock(&pcm_mutex); | ||
477 | |||
478 | /* startup the audio subsystem */ | ||
479 | if (rtd->cpu_dai->ops.startup) { | ||
480 | ret = rtd->cpu_dai->ops.startup(substream); | ||
481 | if (ret < 0) { | ||
482 | printk(KERN_ERR "asoc: can't open interface %s\n", | ||
483 | rtd->cpu_dai->name); | ||
484 | goto out; | ||
485 | } | ||
486 | } | ||
487 | |||
488 | if (platform->pcm_ops->open) { | ||
489 | ret = platform->pcm_ops->open(substream); | ||
490 | if (ret < 0) { | ||
491 | printk(KERN_ERR "asoc: can't open platform %s\n", platform->name); | ||
492 | goto platform_err; | ||
493 | } | ||
494 | } | ||
495 | |||
496 | if (machine->ops && machine->ops->startup) { | ||
497 | ret = machine->ops->startup(substream); | ||
498 | if (ret < 0) { | ||
499 | printk(KERN_ERR "asoc: %s startup failed\n", machine->name); | ||
500 | goto machine_err; | ||
501 | } | ||
502 | } | ||
503 | |||
504 | if (rtd->codec_dai->ops.startup) { | ||
505 | ret = rtd->codec_dai->ops.startup(substream); | ||
506 | if (ret < 0) { | ||
507 | printk(KERN_ERR "asoc: can't open codec %s\n", | ||
508 | rtd->codec_dai->name); | ||
509 | goto codec_dai_err; | ||
510 | } | ||
511 | } | ||
512 | |||
513 | /* create runtime params from DMA, codec and cpu DAI */ | ||
514 | if (runtime->hw.rates) | ||
515 | runtime->hw.rates &= | ||
516 | get_rates(codec_dai->caps.mode, codec_dai->caps.num_modes) & | ||
517 | get_rates(cpu_dai->caps.mode, cpu_dai->caps.num_modes); | ||
518 | else | ||
519 | runtime->hw.rates = | ||
520 | get_rates(codec_dai->caps.mode, codec_dai->caps.num_modes) & | ||
521 | get_rates(cpu_dai->caps.mode, cpu_dai->caps.num_modes); | ||
522 | if (runtime->hw.formats) | ||
523 | runtime->hw.formats &= | ||
524 | get_formats(codec_dai->caps.mode, codec_dai->caps.num_modes) & | ||
525 | get_formats(cpu_dai->caps.mode, cpu_dai->caps.num_modes); | ||
526 | else | ||
527 | runtime->hw.formats = | ||
528 | get_formats(codec_dai->caps.mode, codec_dai->caps.num_modes) & | ||
529 | get_formats(cpu_dai->caps.mode, cpu_dai->caps.num_modes); | ||
530 | |||
531 | /* Check that the codec and cpu DAI's are compatible */ | ||
532 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
533 | runtime->hw.rate_min = | ||
534 | max(rtd->codec_dai->playback.rate_min, | ||
535 | rtd->cpu_dai->playback.rate_min); | ||
536 | runtime->hw.rate_max = | ||
537 | min(rtd->codec_dai->playback.rate_max, | ||
538 | rtd->cpu_dai->playback.rate_max); | ||
539 | runtime->hw.channels_min = | ||
540 | max(rtd->codec_dai->playback.channels_min, | ||
541 | rtd->cpu_dai->playback.channels_min); | ||
542 | runtime->hw.channels_max = | ||
543 | min(rtd->codec_dai->playback.channels_max, | ||
544 | rtd->cpu_dai->playback.channels_max); | ||
545 | } else { | ||
546 | runtime->hw.rate_min = | ||
547 | max(rtd->codec_dai->capture.rate_min, | ||
548 | rtd->cpu_dai->capture.rate_min); | ||
549 | runtime->hw.rate_max = | ||
550 | min(rtd->codec_dai->capture.rate_max, | ||
551 | rtd->cpu_dai->capture.rate_max); | ||
552 | runtime->hw.channels_min = | ||
553 | max(rtd->codec_dai->capture.channels_min, | ||
554 | rtd->cpu_dai->capture.channels_min); | ||
555 | runtime->hw.channels_max = | ||
556 | min(rtd->codec_dai->capture.channels_max, | ||
557 | rtd->cpu_dai->capture.channels_max); | ||
558 | } | ||
559 | |||
560 | snd_pcm_limit_hw_rates(runtime); | ||
561 | if (!runtime->hw.rates) { | ||
562 | printk(KERN_ERR "asoc: %s <-> %s No matching rates\n", | ||
563 | rtd->codec_dai->name, rtd->cpu_dai->name); | ||
564 | goto codec_dai_err; | ||
565 | } | ||
566 | if (!runtime->hw.formats) { | ||
567 | printk(KERN_ERR "asoc: %s <-> %s No matching formats\n", | ||
568 | rtd->codec_dai->name, rtd->cpu_dai->name); | ||
569 | goto codec_dai_err; | ||
570 | } | ||
571 | if (!runtime->hw.channels_min || !runtime->hw.channels_max) { | ||
572 | printk(KERN_ERR "asoc: %s <-> %s No matching channels\n", | ||
573 | rtd->codec_dai->name, rtd->cpu_dai->name); | ||
574 | goto codec_dai_err; | ||
575 | } | ||
576 | |||
577 | dbg("asoc: %s <-> %s info:\n", rtd->codec_dai->name, rtd->cpu_dai->name); | ||
578 | dbg("asoc: rate mask 0x%x \nasoc: min ch %d max ch %d\n | ||
579 | asoc: min rate %d max rate %d\n", | ||
580 | runtime->hw.rates, runtime->hw.channels_min, | ||
581 | runtime->hw.channels_max, runtime->hw.rate_min, runtime->hw.rate_max); | ||
582 | |||
583 | |||
584 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
585 | rtd->cpu_dai->playback.active = rtd->codec_dai->playback.active = 1; | ||
586 | else | ||
587 | rtd->cpu_dai->capture.active = rtd->codec_dai->capture.active = 1; | ||
588 | rtd->cpu_dai->active = rtd->codec_dai->active = 1; | ||
589 | rtd->cpu_dai->runtime = runtime; | ||
590 | socdev->codec->active++; | ||
591 | mutex_unlock(&pcm_mutex); | ||
592 | return 0; | ||
593 | |||
594 | codec_dai_err: | ||
595 | if (machine->ops && machine->ops->shutdown) | ||
596 | machine->ops->shutdown(substream); | ||
597 | |||
598 | machine_err: | ||
599 | if (platform->pcm_ops->close) | ||
600 | platform->pcm_ops->close(substream); | ||
601 | |||
602 | platform_err: | ||
603 | if (rtd->cpu_dai->ops.shutdown) | ||
604 | rtd->cpu_dai->ops.shutdown(substream); | ||
605 | out: | ||
606 | mutex_unlock(&pcm_mutex); | ||
607 | return ret; | ||
608 | } | ||
609 | |||
610 | /* | ||
611 | * Power down the audio subsytem pmdown_time msecs after close is called. | ||
612 | * This is to ensure there are no pops or clicks in between any music tracks | ||
613 | * due to DAPM power cycling. | ||
614 | */ | ||
615 | static void close_delayed_work(void *data) | ||
616 | { | ||
617 | struct snd_soc_device *socdev = data; | ||
618 | struct snd_soc_codec *codec = socdev->codec; | ||
619 | struct snd_soc_codec_dai *codec_dai; | ||
620 | int i; | ||
621 | |||
622 | mutex_lock(&pcm_mutex); | ||
623 | for(i = 0; i < codec->num_dai; i++) { | ||
624 | codec_dai = &codec->dai[i]; | ||
625 | |||
626 | dbg("pop wq checking: %s status: %s waiting: %s\n", | ||
627 | codec_dai->playback.stream_name, | ||
628 | codec_dai->playback.active ? "active" : "inactive", | ||
629 | codec_dai->pop_wait ? "yes" : "no"); | ||
630 | |||
631 | /* are we waiting on this codec DAI stream */ | ||
632 | if (codec_dai->pop_wait == 1) { | ||
633 | |||
634 | codec_dai->pop_wait = 0; | ||
635 | snd_soc_dapm_stream_event(codec, codec_dai->playback.stream_name, | ||
636 | SND_SOC_DAPM_STREAM_STOP); | ||
637 | |||
638 | /* power down the codec power domain if no longer active */ | ||
639 | if (codec->active == 0) { | ||
640 | dbg("pop wq D3 %s %s\n", codec->name, | ||
641 | codec_dai->playback.stream_name); | ||
642 | if (codec->dapm_event) | ||
643 | codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot); | ||
644 | } | ||
645 | } | ||
646 | } | ||
647 | mutex_unlock(&pcm_mutex); | ||
648 | } | ||
649 | |||
650 | /* | ||
651 | * Called by ALSA when a PCM substream is closed. Private data can be | ||
652 | * freed here. The cpu DAI, codec DAI, machine and platform are also | ||
653 | * shutdown. | ||
654 | */ | ||
655 | static int soc_codec_close(struct snd_pcm_substream *substream) | ||
656 | { | ||
657 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
658 | struct snd_soc_device *socdev = rtd->socdev; | ||
659 | struct snd_soc_machine *machine = socdev->machine; | ||
660 | struct snd_soc_platform *platform = socdev->platform; | ||
661 | struct snd_soc_codec *codec = socdev->codec; | ||
662 | |||
663 | mutex_lock(&pcm_mutex); | ||
664 | |||
665 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
666 | rtd->cpu_dai->playback.active = rtd->codec_dai->playback.active = 0; | ||
667 | else | ||
668 | rtd->cpu_dai->capture.active = rtd->codec_dai->capture.active = 0; | ||
669 | |||
670 | if (rtd->codec_dai->playback.active == 0 && | ||
671 | rtd->codec_dai->capture.active == 0) { | ||
672 | rtd->cpu_dai->active = rtd->codec_dai->active = 0; | ||
673 | } | ||
674 | codec->active--; | ||
675 | |||
676 | if (rtd->cpu_dai->ops.shutdown) | ||
677 | rtd->cpu_dai->ops.shutdown(substream); | ||
678 | |||
679 | if (rtd->codec_dai->ops.shutdown) | ||
680 | rtd->codec_dai->ops.shutdown(substream); | ||
681 | |||
682 | if (machine->ops && machine->ops->shutdown) | ||
683 | machine->ops->shutdown(substream); | ||
684 | |||
685 | if (platform->pcm_ops->close) | ||
686 | platform->pcm_ops->close(substream); | ||
687 | rtd->cpu_dai->runtime = NULL; | ||
688 | |||
689 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
690 | /* start delayed pop wq here for playback streams */ | ||
691 | rtd->codec_dai->pop_wait = 1; | ||
692 | queue_delayed_work(soc_workq, &soc_stream_work, | ||
693 | msecs_to_jiffies(pmdown_time)); | ||
694 | } else { | ||
695 | /* capture streams can be powered down now */ | ||
696 | snd_soc_dapm_stream_event(codec, rtd->codec_dai->capture.stream_name, | ||
697 | SND_SOC_DAPM_STREAM_STOP); | ||
698 | |||
699 | if (codec->active == 0 && rtd->codec_dai->pop_wait == 0){ | ||
700 | if (codec->dapm_event) | ||
701 | codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot); | ||
702 | } | ||
703 | } | ||
704 | |||
705 | mutex_unlock(&pcm_mutex); | ||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | /* | ||
710 | * Called by ALSA when the PCM substream is prepared, can set format, sample | ||
711 | * rate, etc. This function is non atomic and can be called multiple times, | ||
712 | * it can refer to the runtime info. | ||
713 | */ | ||
714 | static int soc_pcm_prepare(struct snd_pcm_substream *substream) | ||
715 | { | ||
716 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
717 | struct snd_soc_device *socdev = rtd->socdev; | ||
718 | struct snd_soc_platform *platform = socdev->platform; | ||
719 | struct snd_soc_codec *codec = socdev->codec; | ||
720 | int ret = 0; | ||
721 | |||
722 | mutex_lock(&pcm_mutex); | ||
723 | if (platform->pcm_ops->prepare) { | ||
724 | ret = platform->pcm_ops->prepare(substream); | ||
725 | if (ret < 0) | ||
726 | goto out; | ||
727 | } | ||
728 | |||
729 | if (rtd->codec_dai->ops.prepare) { | ||
730 | ret = rtd->codec_dai->ops.prepare(substream); | ||
731 | if (ret < 0) | ||
732 | goto out; | ||
733 | } | ||
734 | |||
735 | if (rtd->cpu_dai->ops.prepare) | ||
736 | ret = rtd->cpu_dai->ops.prepare(substream); | ||
737 | |||
738 | /* we only want to start a DAPM playback stream if we are not waiting | ||
739 | * on an existing one stopping */ | ||
740 | if (rtd->codec_dai->pop_wait) { | ||
741 | /* we are waiting for the delayed work to start */ | ||
742 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
743 | snd_soc_dapm_stream_event(codec, | ||
744 | rtd->codec_dai->capture.stream_name, | ||
745 | SND_SOC_DAPM_STREAM_START); | ||
746 | else { | ||
747 | rtd->codec_dai->pop_wait = 0; | ||
748 | cancel_delayed_work(&soc_stream_work); | ||
749 | if (rtd->codec_dai->digital_mute) | ||
750 | rtd->codec_dai->digital_mute(codec, rtd->codec_dai, 0); | ||
751 | } | ||
752 | } else { | ||
753 | /* no delayed work - do we need to power up codec */ | ||
754 | if (codec->dapm_state != SNDRV_CTL_POWER_D0) { | ||
755 | |||
756 | if (codec->dapm_event) | ||
757 | codec->dapm_event(codec, SNDRV_CTL_POWER_D1); | ||
758 | |||
759 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
760 | snd_soc_dapm_stream_event(codec, | ||
761 | rtd->codec_dai->playback.stream_name, | ||
762 | SND_SOC_DAPM_STREAM_START); | ||
763 | else | ||
764 | snd_soc_dapm_stream_event(codec, | ||
765 | rtd->codec_dai->capture.stream_name, | ||
766 | SND_SOC_DAPM_STREAM_START); | ||
767 | |||
768 | if (codec->dapm_event) | ||
769 | codec->dapm_event(codec, SNDRV_CTL_POWER_D0); | ||
770 | if (rtd->codec_dai->digital_mute) | ||
771 | rtd->codec_dai->digital_mute(codec, rtd->codec_dai, 0); | ||
772 | |||
773 | } else { | ||
774 | /* codec already powered - power on widgets */ | ||
775 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
776 | snd_soc_dapm_stream_event(codec, | ||
777 | rtd->codec_dai->playback.stream_name, | ||
778 | SND_SOC_DAPM_STREAM_START); | ||
779 | else | ||
780 | snd_soc_dapm_stream_event(codec, | ||
781 | rtd->codec_dai->capture.stream_name, | ||
782 | SND_SOC_DAPM_STREAM_START); | ||
783 | if (rtd->codec_dai->digital_mute) | ||
784 | rtd->codec_dai->digital_mute(codec, rtd->codec_dai, 0); | ||
785 | } | ||
786 | } | ||
787 | |||
788 | out: | ||
789 | mutex_unlock(&pcm_mutex); | ||
790 | return ret; | ||
791 | } | ||
792 | |||
793 | /* | ||
794 | * Called by ALSA when the hardware params are set by application. This | ||
795 | * function can also be called multiple times and can allocate buffers | ||
796 | * (using snd_pcm_lib_* ). It's non-atomic. | ||
797 | */ | ||
798 | static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | ||
799 | struct snd_pcm_hw_params *params) | ||
800 | { | ||
801 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
802 | struct snd_soc_device *socdev = rtd->socdev; | ||
803 | struct snd_soc_platform *platform = socdev->platform; | ||
804 | struct snd_soc_machine *machine = socdev->machine; | ||
805 | int ret = 0; | ||
806 | |||
807 | mutex_lock(&pcm_mutex); | ||
808 | |||
809 | /* we don't need to match any AC97 params */ | ||
810 | if (rtd->cpu_dai->type != SND_SOC_DAI_AC97) { | ||
811 | ret = soc_hw_match_params(substream, params); | ||
812 | if (ret < 0) | ||
813 | goto out; | ||
814 | } else { | ||
815 | struct snd_soc_clock_info clk_info; | ||
816 | clk_info.rate = params_rate(params); | ||
817 | ret = soc_get_mclk(rtd, &clk_info); | ||
818 | if (ret < 0) | ||
819 | goto out; | ||
820 | } | ||
821 | |||
822 | if (rtd->codec_dai->ops.hw_params) { | ||
823 | ret = rtd->codec_dai->ops.hw_params(substream, params); | ||
824 | if (ret < 0) { | ||
825 | printk(KERN_ERR "asoc: can't set codec %s hw params\n", | ||
826 | rtd->codec_dai->name); | ||
827 | goto out; | ||
828 | } | ||
829 | } | ||
830 | |||
831 | if (rtd->cpu_dai->ops.hw_params) { | ||
832 | ret = rtd->cpu_dai->ops.hw_params(substream, params); | ||
833 | if (ret < 0) { | ||
834 | printk(KERN_ERR "asoc: can't set interface %s hw params\n", | ||
835 | rtd->cpu_dai->name); | ||
836 | goto interface_err; | ||
837 | } | ||
838 | } | ||
839 | |||
840 | if (platform->pcm_ops->hw_params) { | ||
841 | ret = platform->pcm_ops->hw_params(substream, params); | ||
842 | if (ret < 0) { | ||
843 | printk(KERN_ERR "asoc: can't set platform %s hw params\n", | ||
844 | platform->name); | ||
845 | goto platform_err; | ||
846 | } | ||
847 | } | ||
848 | |||
849 | if (machine->ops && machine->ops->hw_params) { | ||
850 | ret = machine->ops->hw_params(substream, params); | ||
851 | if (ret < 0) { | ||
852 | printk(KERN_ERR "asoc: machine hw_params failed\n"); | ||
853 | goto machine_err; | ||
854 | } | ||
855 | } | ||
856 | |||
857 | out: | ||
858 | mutex_unlock(&pcm_mutex); | ||
859 | return ret; | ||
860 | |||
861 | machine_err: | ||
862 | if (platform->pcm_ops->hw_free) | ||
863 | platform->pcm_ops->hw_free(substream); | ||
864 | |||
865 | platform_err: | ||
866 | if (rtd->cpu_dai->ops.hw_free) | ||
867 | rtd->cpu_dai->ops.hw_free(substream); | ||
868 | |||
869 | interface_err: | ||
870 | if (rtd->codec_dai->ops.hw_free) | ||
871 | rtd->codec_dai->ops.hw_free(substream); | ||
872 | |||
873 | mutex_unlock(&pcm_mutex); | ||
874 | return ret; | ||
875 | } | ||
876 | |||
877 | /* | ||
878 | * Free's resources allocated by hw_params, can be called multiple times | ||
879 | */ | ||
880 | static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | ||
881 | { | ||
882 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
883 | struct snd_soc_device *socdev = rtd->socdev; | ||
884 | struct snd_soc_platform *platform = socdev->platform; | ||
885 | struct snd_soc_codec *codec = socdev->codec; | ||
886 | struct snd_soc_machine *machine = socdev->machine; | ||
887 | |||
888 | mutex_lock(&pcm_mutex); | ||
889 | |||
890 | /* apply codec digital mute */ | ||
891 | if (!codec->active && rtd->codec_dai->digital_mute) | ||
892 | rtd->codec_dai->digital_mute(codec, rtd->codec_dai, 1); | ||
893 | |||
894 | /* free any machine hw params */ | ||
895 | if (machine->ops && machine->ops->hw_free) | ||
896 | machine->ops->hw_free(substream); | ||
897 | |||
898 | /* free any DMA resources */ | ||
899 | if (platform->pcm_ops->hw_free) | ||
900 | platform->pcm_ops->hw_free(substream); | ||
901 | |||
902 | /* now free hw params for the DAI's */ | ||
903 | if (rtd->codec_dai->ops.hw_free) | ||
904 | rtd->codec_dai->ops.hw_free(substream); | ||
905 | |||
906 | if (rtd->cpu_dai->ops.hw_free) | ||
907 | rtd->cpu_dai->ops.hw_free(substream); | ||
908 | |||
909 | mutex_unlock(&pcm_mutex); | ||
910 | return 0; | ||
911 | } | ||
912 | |||
913 | static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
914 | { | ||
915 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
916 | struct snd_soc_device *socdev = rtd->socdev; | ||
917 | struct snd_soc_platform *platform = socdev->platform; | ||
918 | int ret; | ||
919 | |||
920 | if (rtd->codec_dai->ops.trigger) { | ||
921 | ret = rtd->codec_dai->ops.trigger(substream, cmd); | ||
922 | if (ret < 0) | ||
923 | return ret; | ||
924 | } | ||
925 | |||
926 | if (platform->pcm_ops->trigger) { | ||
927 | ret = platform->pcm_ops->trigger(substream, cmd); | ||
928 | if (ret < 0) | ||
929 | return ret; | ||
930 | } | ||
931 | |||
932 | if (rtd->cpu_dai->ops.trigger) { | ||
933 | ret = rtd->cpu_dai->ops.trigger(substream, cmd); | ||
934 | if (ret < 0) | ||
935 | return ret; | ||
936 | } | ||
937 | return 0; | ||
938 | } | ||
939 | |||
940 | /* ASoC PCM operations */ | ||
941 | static struct snd_pcm_ops soc_pcm_ops = { | ||
942 | .open = soc_pcm_open, | ||
943 | .close = soc_codec_close, | ||
944 | .hw_params = soc_pcm_hw_params, | ||
945 | .hw_free = soc_pcm_hw_free, | ||
946 | .prepare = soc_pcm_prepare, | ||
947 | .trigger = soc_pcm_trigger, | ||
948 | }; | ||
949 | |||
950 | #ifdef CONFIG_PM | ||
951 | /* powers down audio subsystem for suspend */ | ||
952 | static int soc_suspend(struct platform_device *pdev, pm_message_t state) | ||
953 | { | ||
954 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
955 | struct snd_soc_machine *machine = socdev->machine; | ||
956 | struct snd_soc_platform *platform = socdev->platform; | ||
957 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; | ||
958 | struct snd_soc_codec *codec = socdev->codec; | ||
959 | int i; | ||
960 | |||
961 | /* mute any active DAC's */ | ||
962 | for(i = 0; i < machine->num_links; i++) { | ||
963 | struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai; | ||
964 | if (dai->digital_mute && dai->playback.active) | ||
965 | dai->digital_mute(codec, dai, 1); | ||
966 | } | ||
967 | |||
968 | if (machine->suspend_pre) | ||
969 | machine->suspend_pre(pdev, state); | ||
970 | |||
971 | for(i = 0; i < machine->num_links; i++) { | ||
972 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | ||
973 | if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97) | ||
974 | cpu_dai->suspend(pdev, cpu_dai); | ||
975 | if (platform->suspend) | ||
976 | platform->suspend(pdev, cpu_dai); | ||
977 | } | ||
978 | |||
979 | /* close any waiting streams and save state */ | ||
980 | flush_workqueue(soc_workq); | ||
981 | codec->suspend_dapm_state = codec->dapm_state; | ||
982 | |||
983 | for(i = 0; i < codec->num_dai; i++) { | ||
984 | char *stream = codec->dai[i].playback.stream_name; | ||
985 | if (stream != NULL) | ||
986 | snd_soc_dapm_stream_event(codec, stream, | ||
987 | SND_SOC_DAPM_STREAM_SUSPEND); | ||
988 | stream = codec->dai[i].capture.stream_name; | ||
989 | if (stream != NULL) | ||
990 | snd_soc_dapm_stream_event(codec, stream, | ||
991 | SND_SOC_DAPM_STREAM_SUSPEND); | ||
992 | } | ||
993 | |||
994 | if (codec_dev->suspend) | ||
995 | codec_dev->suspend(pdev, state); | ||
996 | |||
997 | for(i = 0; i < machine->num_links; i++) { | ||
998 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | ||
999 | if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97) | ||
1000 | cpu_dai->suspend(pdev, cpu_dai); | ||
1001 | } | ||
1002 | |||
1003 | if (machine->suspend_post) | ||
1004 | machine->suspend_post(pdev, state); | ||
1005 | |||
1006 | return 0; | ||
1007 | } | ||
1008 | |||
1009 | /* powers up audio subsystem after a suspend */ | ||
1010 | static int soc_resume(struct platform_device *pdev) | ||
1011 | { | ||
1012 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1013 | struct snd_soc_machine *machine = socdev->machine; | ||
1014 | struct snd_soc_platform *platform = socdev->platform; | ||
1015 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; | ||
1016 | struct snd_soc_codec *codec = socdev->codec; | ||
1017 | int i; | ||
1018 | |||
1019 | if (machine->resume_pre) | ||
1020 | machine->resume_pre(pdev); | ||
1021 | |||
1022 | for(i = 0; i < machine->num_links; i++) { | ||
1023 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | ||
1024 | if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97) | ||
1025 | cpu_dai->resume(pdev, cpu_dai); | ||
1026 | } | ||
1027 | |||
1028 | if (codec_dev->resume) | ||
1029 | codec_dev->resume(pdev); | ||
1030 | |||
1031 | for(i = 0; i < codec->num_dai; i++) { | ||
1032 | char* stream = codec->dai[i].playback.stream_name; | ||
1033 | if (stream != NULL) | ||
1034 | snd_soc_dapm_stream_event(codec, stream, | ||
1035 | SND_SOC_DAPM_STREAM_RESUME); | ||
1036 | stream = codec->dai[i].capture.stream_name; | ||
1037 | if (stream != NULL) | ||
1038 | snd_soc_dapm_stream_event(codec, stream, | ||
1039 | SND_SOC_DAPM_STREAM_RESUME); | ||
1040 | } | ||
1041 | |||
1042 | /* unmute any active DAC's */ | ||
1043 | for(i = 0; i < machine->num_links; i++) { | ||
1044 | struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai; | ||
1045 | if (dai->digital_mute && dai->playback.active) | ||
1046 | dai->digital_mute(codec, dai, 0); | ||
1047 | } | ||
1048 | |||
1049 | for(i = 0; i < machine->num_links; i++) { | ||
1050 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | ||
1051 | if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97) | ||
1052 | cpu_dai->resume(pdev, cpu_dai); | ||
1053 | if (platform->resume) | ||
1054 | platform->resume(pdev, cpu_dai); | ||
1055 | } | ||
1056 | |||
1057 | if (machine->resume_post) | ||
1058 | machine->resume_post(pdev); | ||
1059 | |||
1060 | return 0; | ||
1061 | } | ||
1062 | |||
1063 | #else | ||
1064 | #define soc_suspend NULL | ||
1065 | #define soc_resume NULL | ||
1066 | #endif | ||
1067 | |||
1068 | /* probes a new socdev */ | ||
1069 | static int soc_probe(struct platform_device *pdev) | ||
1070 | { | ||
1071 | int ret = 0, i; | ||
1072 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1073 | struct snd_soc_machine *machine = socdev->machine; | ||
1074 | struct snd_soc_platform *platform = socdev->platform; | ||
1075 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; | ||
1076 | |||
1077 | if (machine->probe) { | ||
1078 | ret = machine->probe(pdev); | ||
1079 | if(ret < 0) | ||
1080 | return ret; | ||
1081 | } | ||
1082 | |||
1083 | for (i = 0; i < machine->num_links; i++) { | ||
1084 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | ||
1085 | if (cpu_dai->probe) { | ||
1086 | ret = cpu_dai->probe(pdev); | ||
1087 | if(ret < 0) | ||
1088 | goto cpu_dai_err; | ||
1089 | } | ||
1090 | } | ||
1091 | |||
1092 | if (codec_dev->probe) { | ||
1093 | ret = codec_dev->probe(pdev); | ||
1094 | if(ret < 0) | ||
1095 | goto cpu_dai_err; | ||
1096 | } | ||
1097 | |||
1098 | if (platform->probe) { | ||
1099 | ret = platform->probe(pdev); | ||
1100 | if(ret < 0) | ||
1101 | goto platform_err; | ||
1102 | } | ||
1103 | |||
1104 | /* DAPM stream work */ | ||
1105 | soc_workq = create_workqueue("kdapm"); | ||
1106 | if (soc_workq == NULL) | ||
1107 | goto work_err; | ||
1108 | INIT_WORK(&soc_stream_work, close_delayed_work, socdev); | ||
1109 | return 0; | ||
1110 | |||
1111 | work_err: | ||
1112 | if (platform->remove) | ||
1113 | platform->remove(pdev); | ||
1114 | |||
1115 | platform_err: | ||
1116 | if (codec_dev->remove) | ||
1117 | codec_dev->remove(pdev); | ||
1118 | |||
1119 | cpu_dai_err: | ||
1120 | for (i--; i > 0; i--) { | ||
1121 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | ||
1122 | if (cpu_dai->remove) | ||
1123 | cpu_dai->remove(pdev); | ||
1124 | } | ||
1125 | |||
1126 | if (machine->remove) | ||
1127 | machine->remove(pdev); | ||
1128 | |||
1129 | return ret; | ||
1130 | } | ||
1131 | |||
1132 | /* removes a socdev */ | ||
1133 | static int soc_remove(struct platform_device *pdev) | ||
1134 | { | ||
1135 | int i; | ||
1136 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1137 | struct snd_soc_machine *machine = socdev->machine; | ||
1138 | struct snd_soc_platform *platform = socdev->platform; | ||
1139 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; | ||
1140 | |||
1141 | if (soc_workq) | ||
1142 | destroy_workqueue(soc_workq); | ||
1143 | |||
1144 | if (platform->remove) | ||
1145 | platform->remove(pdev); | ||
1146 | |||
1147 | if (codec_dev->remove) | ||
1148 | codec_dev->remove(pdev); | ||
1149 | |||
1150 | for (i = 0; i < machine->num_links; i++) { | ||
1151 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | ||
1152 | if (cpu_dai->remove) | ||
1153 | cpu_dai->remove(pdev); | ||
1154 | } | ||
1155 | |||
1156 | if (machine->remove) | ||
1157 | machine->remove(pdev); | ||
1158 | |||
1159 | return 0; | ||
1160 | } | ||
1161 | |||
1162 | /* ASoC platform driver */ | ||
1163 | static struct platform_driver soc_driver = { | ||
1164 | .driver = { | ||
1165 | .name = "soc-audio", | ||
1166 | }, | ||
1167 | .probe = soc_probe, | ||
1168 | .remove = soc_remove, | ||
1169 | .suspend = soc_suspend, | ||
1170 | .resume = soc_resume, | ||
1171 | }; | ||
1172 | |||
1173 | /* create a new pcm */ | ||
1174 | static int soc_new_pcm(struct snd_soc_device *socdev, | ||
1175 | struct snd_soc_dai_link *dai_link, int num) | ||
1176 | { | ||
1177 | struct snd_soc_codec *codec = socdev->codec; | ||
1178 | struct snd_soc_codec_dai *codec_dai = dai_link->codec_dai; | ||
1179 | struct snd_soc_cpu_dai *cpu_dai = dai_link->cpu_dai; | ||
1180 | struct snd_soc_pcm_runtime *rtd; | ||
1181 | struct snd_pcm *pcm; | ||
1182 | char new_name[64]; | ||
1183 | int ret = 0, playback = 0, capture = 0; | ||
1184 | |||
1185 | rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL); | ||
1186 | if (rtd == NULL) | ||
1187 | return -ENOMEM; | ||
1188 | rtd->cpu_dai = cpu_dai; | ||
1189 | rtd->codec_dai = codec_dai; | ||
1190 | rtd->socdev = socdev; | ||
1191 | |||
1192 | /* check client and interface hw capabilities */ | ||
1193 | sprintf(new_name, "%s %s-%s-%d",dai_link->stream_name, codec_dai->name, | ||
1194 | get_dai_name(cpu_dai->type), num); | ||
1195 | |||
1196 | if (codec_dai->playback.channels_min) | ||
1197 | playback = 1; | ||
1198 | if (codec_dai->capture.channels_min) | ||
1199 | capture = 1; | ||
1200 | |||
1201 | ret = snd_pcm_new(codec->card, new_name, codec->pcm_devs++, playback, | ||
1202 | capture, &pcm); | ||
1203 | if (ret < 0) { | ||
1204 | printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name); | ||
1205 | kfree(rtd); | ||
1206 | return ret; | ||
1207 | } | ||
1208 | |||
1209 | pcm->private_data = rtd; | ||
1210 | soc_pcm_ops.mmap = socdev->platform->pcm_ops->mmap; | ||
1211 | soc_pcm_ops.pointer = socdev->platform->pcm_ops->pointer; | ||
1212 | soc_pcm_ops.ioctl = socdev->platform->pcm_ops->ioctl; | ||
1213 | soc_pcm_ops.copy = socdev->platform->pcm_ops->copy; | ||
1214 | soc_pcm_ops.silence = socdev->platform->pcm_ops->silence; | ||
1215 | soc_pcm_ops.ack = socdev->platform->pcm_ops->ack; | ||
1216 | soc_pcm_ops.page = socdev->platform->pcm_ops->page; | ||
1217 | |||
1218 | if (playback) | ||
1219 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops); | ||
1220 | |||
1221 | if (capture) | ||
1222 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops); | ||
1223 | |||
1224 | ret = socdev->platform->pcm_new(codec->card, codec_dai, pcm); | ||
1225 | if (ret < 0) { | ||
1226 | printk(KERN_ERR "asoc: platform pcm constructor failed\n"); | ||
1227 | kfree(rtd); | ||
1228 | return ret; | ||
1229 | } | ||
1230 | |||
1231 | pcm->private_free = socdev->platform->pcm_free; | ||
1232 | printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name, | ||
1233 | cpu_dai->name); | ||
1234 | return ret; | ||
1235 | } | ||
1236 | |||
1237 | /* codec register dump */ | ||
1238 | static ssize_t codec_reg_show(struct device *dev, | ||
1239 | struct device_attribute *attr, char *buf) | ||
1240 | { | ||
1241 | struct snd_soc_device *devdata = dev_get_drvdata(dev); | ||
1242 | struct snd_soc_codec *codec = devdata->codec; | ||
1243 | int i, step = 1, count = 0; | ||
1244 | |||
1245 | if (!codec->reg_cache_size) | ||
1246 | return 0; | ||
1247 | |||
1248 | if (codec->reg_cache_step) | ||
1249 | step = codec->reg_cache_step; | ||
1250 | |||
1251 | count += sprintf(buf, "%s registers\n", codec->name); | ||
1252 | for(i = 0; i < codec->reg_cache_size; i += step) | ||
1253 | count += sprintf(buf + count, "%2x: %4x\n", i, codec->read(codec, i)); | ||
1254 | |||
1255 | return count; | ||
1256 | } | ||
1257 | static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL); | ||
1258 | |||
1259 | /** | ||
1260 | * snd_soc_new_ac97_codec - initailise AC97 device | ||
1261 | * @codec: audio codec | ||
1262 | * @ops: AC97 bus operations | ||
1263 | * @num: AC97 codec number | ||
1264 | * | ||
1265 | * Initialises AC97 codec resources for use by ad-hoc devices only. | ||
1266 | */ | ||
1267 | int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, | ||
1268 | struct snd_ac97_bus_ops *ops, int num) | ||
1269 | { | ||
1270 | mutex_lock(&codec->mutex); | ||
1271 | |||
1272 | codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); | ||
1273 | if (codec->ac97 == NULL) { | ||
1274 | mutex_unlock(&codec->mutex); | ||
1275 | return -ENOMEM; | ||
1276 | } | ||
1277 | |||
1278 | codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL); | ||
1279 | if (codec->ac97->bus == NULL) { | ||
1280 | kfree(codec->ac97); | ||
1281 | codec->ac97 = NULL; | ||
1282 | mutex_unlock(&codec->mutex); | ||
1283 | return -ENOMEM; | ||
1284 | } | ||
1285 | |||
1286 | codec->ac97->bus->ops = ops; | ||
1287 | codec->ac97->num = num; | ||
1288 | mutex_unlock(&codec->mutex); | ||
1289 | return 0; | ||
1290 | } | ||
1291 | EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); | ||
1292 | |||
1293 | /** | ||
1294 | * snd_soc_free_ac97_codec - free AC97 codec device | ||
1295 | * @codec: audio codec | ||
1296 | * | ||
1297 | * Frees AC97 codec device resources. | ||
1298 | */ | ||
1299 | void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) | ||
1300 | { | ||
1301 | mutex_lock(&codec->mutex); | ||
1302 | kfree(codec->ac97->bus); | ||
1303 | kfree(codec->ac97); | ||
1304 | codec->ac97 = NULL; | ||
1305 | mutex_unlock(&codec->mutex); | ||
1306 | } | ||
1307 | EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); | ||
1308 | |||
1309 | /** | ||
1310 | * snd_soc_update_bits - update codec register bits | ||
1311 | * @codec: audio codec | ||
1312 | * @reg: codec register | ||
1313 | * @mask: register mask | ||
1314 | * @value: new value | ||
1315 | * | ||
1316 | * Writes new register value. | ||
1317 | * | ||
1318 | * Returns 1 for change else 0. | ||
1319 | */ | ||
1320 | int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, | ||
1321 | unsigned short mask, unsigned short value) | ||
1322 | { | ||
1323 | int change; | ||
1324 | unsigned short old, new; | ||
1325 | |||
1326 | mutex_lock(&io_mutex); | ||
1327 | old = snd_soc_read(codec, reg); | ||
1328 | new = (old & ~mask) | value; | ||
1329 | change = old != new; | ||
1330 | if (change) | ||
1331 | snd_soc_write(codec, reg, new); | ||
1332 | |||
1333 | mutex_unlock(&io_mutex); | ||
1334 | return change; | ||
1335 | } | ||
1336 | EXPORT_SYMBOL_GPL(snd_soc_update_bits); | ||
1337 | |||
1338 | /** | ||
1339 | * snd_soc_test_bits - test register for change | ||
1340 | * @codec: audio codec | ||
1341 | * @reg: codec register | ||
1342 | * @mask: register mask | ||
1343 | * @value: new value | ||
1344 | * | ||
1345 | * Tests a register with a new value and checks if the new value is | ||
1346 | * different from the old value. | ||
1347 | * | ||
1348 | * Returns 1 for change else 0. | ||
1349 | */ | ||
1350 | int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, | ||
1351 | unsigned short mask, unsigned short value) | ||
1352 | { | ||
1353 | int change; | ||
1354 | unsigned short old, new; | ||
1355 | |||
1356 | mutex_lock(&io_mutex); | ||
1357 | old = snd_soc_read(codec, reg); | ||
1358 | new = (old & ~mask) | value; | ||
1359 | change = old != new; | ||
1360 | mutex_unlock(&io_mutex); | ||
1361 | |||
1362 | return change; | ||
1363 | } | ||
1364 | EXPORT_SYMBOL_GPL(snd_soc_test_bits); | ||
1365 | |||
1366 | /** | ||
1367 | * snd_soc_get_rate - get int sample rate | ||
1368 | * @hwpcmrate: the hardware pcm rate | ||
1369 | * | ||
1370 | * Returns the audio rate integaer value, else 0. | ||
1371 | */ | ||
1372 | int snd_soc_get_rate(int hwpcmrate) | ||
1373 | { | ||
1374 | int rate = ffs(hwpcmrate) - 1; | ||
1375 | |||
1376 | if (rate > ARRAY_SIZE(rates)) | ||
1377 | return 0; | ||
1378 | return rates[rate]; | ||
1379 | } | ||
1380 | EXPORT_SYMBOL_GPL(snd_soc_get_rate); | ||
1381 | |||
1382 | /** | ||
1383 | * snd_soc_new_pcms - create new sound card and pcms | ||
1384 | * @socdev: the SoC audio device | ||
1385 | * | ||
1386 | * Create a new sound card based upon the codec and interface pcms. | ||
1387 | * | ||
1388 | * Returns 0 for success, else error. | ||
1389 | */ | ||
1390 | int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char * xid) | ||
1391 | { | ||
1392 | struct snd_soc_codec *codec = socdev->codec; | ||
1393 | struct snd_soc_machine *machine = socdev->machine; | ||
1394 | int ret = 0, i; | ||
1395 | |||
1396 | mutex_lock(&codec->mutex); | ||
1397 | |||
1398 | /* register a sound card */ | ||
1399 | codec->card = snd_card_new(idx, xid, codec->owner, 0); | ||
1400 | if (!codec->card) { | ||
1401 | printk(KERN_ERR "asoc: can't create sound card for codec %s\n", | ||
1402 | codec->name); | ||
1403 | mutex_unlock(&codec->mutex); | ||
1404 | return -ENODEV; | ||
1405 | } | ||
1406 | |||
1407 | codec->card->dev = socdev->dev; | ||
1408 | codec->card->private_data = codec; | ||
1409 | strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver)); | ||
1410 | |||
1411 | /* create the pcms */ | ||
1412 | for(i = 0; i < machine->num_links; i++) { | ||
1413 | ret = soc_new_pcm(socdev, &machine->dai_link[i], i); | ||
1414 | if (ret < 0) { | ||
1415 | printk(KERN_ERR "asoc: can't create pcm %s\n", | ||
1416 | machine->dai_link[i].stream_name); | ||
1417 | mutex_unlock(&codec->mutex); | ||
1418 | return ret; | ||
1419 | } | ||
1420 | } | ||
1421 | |||
1422 | mutex_unlock(&codec->mutex); | ||
1423 | return ret; | ||
1424 | } | ||
1425 | EXPORT_SYMBOL_GPL(snd_soc_new_pcms); | ||
1426 | |||
1427 | /** | ||
1428 | * snd_soc_register_card - register sound card | ||
1429 | * @socdev: the SoC audio device | ||
1430 | * | ||
1431 | * Register a SoC sound card. Also registers an AC97 device if the | ||
1432 | * codec is AC97 for ad hoc devices. | ||
1433 | * | ||
1434 | * Returns 0 for success, else error. | ||
1435 | */ | ||
1436 | int snd_soc_register_card(struct snd_soc_device *socdev) | ||
1437 | { | ||
1438 | struct snd_soc_codec *codec = socdev->codec; | ||
1439 | struct snd_soc_machine *machine = socdev->machine; | ||
1440 | int ret = 0, i, ac97 = 0; | ||
1441 | |||
1442 | mutex_lock(&codec->mutex); | ||
1443 | for(i = 0; i < machine->num_links; i++) { | ||
1444 | if (socdev->machine->dai_link[i].init) | ||
1445 | socdev->machine->dai_link[i].init(codec); | ||
1446 | if (socdev->machine->dai_link[i].cpu_dai->type == SND_SOC_DAI_AC97) | ||
1447 | ac97 = 1; | ||
1448 | } | ||
1449 | snprintf(codec->card->shortname, sizeof(codec->card->shortname), | ||
1450 | "%s", machine->name); | ||
1451 | snprintf(codec->card->longname, sizeof(codec->card->longname), | ||
1452 | "%s (%s)", machine->name, codec->name); | ||
1453 | |||
1454 | ret = snd_card_register(codec->card); | ||
1455 | if (ret < 0) { | ||
1456 | printk(KERN_ERR "asoc: failed to register soundcard for codec %s\n", | ||
1457 | codec->name); | ||
1458 | mutex_unlock(&codec->mutex); | ||
1459 | return ret; | ||
1460 | } | ||
1461 | |||
1462 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
1463 | if (ac97) | ||
1464 | soc_ac97_dev_register(codec); | ||
1465 | #endif | ||
1466 | |||
1467 | snd_soc_dapm_sys_add(socdev->dev); | ||
1468 | device_create_file(socdev->dev, &dev_attr_codec_reg); | ||
1469 | mutex_unlock(&codec->mutex); | ||
1470 | return ret; | ||
1471 | } | ||
1472 | EXPORT_SYMBOL_GPL(snd_soc_register_card); | ||
1473 | |||
1474 | /** | ||
1475 | * snd_soc_free_pcms - free sound card and pcms | ||
1476 | * @socdev: the SoC audio device | ||
1477 | * | ||
1478 | * Frees sound card and pcms associated with the socdev. | ||
1479 | * Also unregister the codec if it is an AC97 device. | ||
1480 | */ | ||
1481 | void snd_soc_free_pcms(struct snd_soc_device *socdev) | ||
1482 | { | ||
1483 | struct snd_soc_codec *codec = socdev->codec; | ||
1484 | |||
1485 | mutex_lock(&codec->mutex); | ||
1486 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
1487 | if (codec->ac97) | ||
1488 | soc_ac97_dev_unregister(codec); | ||
1489 | #endif | ||
1490 | |||
1491 | if (codec->card) | ||
1492 | snd_card_free(codec->card); | ||
1493 | device_remove_file(socdev->dev, &dev_attr_codec_reg); | ||
1494 | mutex_unlock(&codec->mutex); | ||
1495 | } | ||
1496 | EXPORT_SYMBOL_GPL(snd_soc_free_pcms); | ||
1497 | |||
1498 | /** | ||
1499 | * snd_soc_set_runtime_hwparams - set the runtime hardware parameters | ||
1500 | * @substream: the pcm substream | ||
1501 | * @hw: the hardware parameters | ||
1502 | * | ||
1503 | * Sets the substream runtime hardware parameters. | ||
1504 | */ | ||
1505 | int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, | ||
1506 | const struct snd_pcm_hardware *hw) | ||
1507 | { | ||
1508 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1509 | runtime->hw.info = hw->info; | ||
1510 | runtime->hw.formats = hw->formats; | ||
1511 | runtime->hw.period_bytes_min = hw->period_bytes_min; | ||
1512 | runtime->hw.period_bytes_max = hw->period_bytes_max; | ||
1513 | runtime->hw.periods_min = hw->periods_min; | ||
1514 | runtime->hw.periods_max = hw->periods_max; | ||
1515 | runtime->hw.buffer_bytes_max = hw->buffer_bytes_max; | ||
1516 | runtime->hw.fifo_size = hw->fifo_size; | ||
1517 | return 0; | ||
1518 | } | ||
1519 | EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams); | ||
1520 | |||
1521 | /** | ||
1522 | * snd_soc_cnew - create new control | ||
1523 | * @_template: control template | ||
1524 | * @data: control private data | ||
1525 | * @lnng_name: control long name | ||
1526 | * | ||
1527 | * Create a new mixer control from a template control. | ||
1528 | * | ||
1529 | * Returns 0 for success, else error. | ||
1530 | */ | ||
1531 | struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, | ||
1532 | void *data, char *long_name) | ||
1533 | { | ||
1534 | struct snd_kcontrol_new template; | ||
1535 | |||
1536 | memcpy(&template, _template, sizeof(template)); | ||
1537 | if (long_name) | ||
1538 | template.name = long_name; | ||
1539 | template.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
1540 | template.index = 0; | ||
1541 | |||
1542 | return snd_ctl_new1(&template, data); | ||
1543 | } | ||
1544 | EXPORT_SYMBOL_GPL(snd_soc_cnew); | ||
1545 | |||
1546 | /** | ||
1547 | * snd_soc_info_enum_double - enumerated double mixer info callback | ||
1548 | * @kcontrol: mixer control | ||
1549 | * @uinfo: control element information | ||
1550 | * | ||
1551 | * Callback to provide information about a double enumerated | ||
1552 | * mixer control. | ||
1553 | * | ||
1554 | * Returns 0 for success. | ||
1555 | */ | ||
1556 | int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, | ||
1557 | struct snd_ctl_elem_info *uinfo) | ||
1558 | { | ||
1559 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
1560 | |||
1561 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1562 | uinfo->count = e->shift_l == e->shift_r ? 1 : 2; | ||
1563 | uinfo->value.enumerated.items = e->mask; | ||
1564 | |||
1565 | if (uinfo->value.enumerated.item > e->mask - 1) | ||
1566 | uinfo->value.enumerated.item = e->mask - 1; | ||
1567 | strcpy(uinfo->value.enumerated.name, | ||
1568 | e->texts[uinfo->value.enumerated.item]); | ||
1569 | return 0; | ||
1570 | } | ||
1571 | EXPORT_SYMBOL_GPL(snd_soc_info_enum_double); | ||
1572 | |||
1573 | /** | ||
1574 | * snd_soc_get_enum_double - enumerated double mixer get callback | ||
1575 | * @kcontrol: mixer control | ||
1576 | * @uinfo: control element information | ||
1577 | * | ||
1578 | * Callback to get the value of a double enumerated mixer. | ||
1579 | * | ||
1580 | * Returns 0 for success. | ||
1581 | */ | ||
1582 | int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | ||
1583 | struct snd_ctl_elem_value *ucontrol) | ||
1584 | { | ||
1585 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1586 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
1587 | unsigned short val, bitmask; | ||
1588 | |||
1589 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) | ||
1590 | ; | ||
1591 | val = snd_soc_read(codec, e->reg); | ||
1592 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); | ||
1593 | if (e->shift_l != e->shift_r) | ||
1594 | ucontrol->value.enumerated.item[1] = | ||
1595 | (val >> e->shift_r) & (bitmask - 1); | ||
1596 | |||
1597 | return 0; | ||
1598 | } | ||
1599 | EXPORT_SYMBOL_GPL(snd_soc_get_enum_double); | ||
1600 | |||
1601 | /** | ||
1602 | * snd_soc_put_enum_double - enumerated double mixer put callback | ||
1603 | * @kcontrol: mixer control | ||
1604 | * @uinfo: control element information | ||
1605 | * | ||
1606 | * Callback to set the value of a double enumerated mixer. | ||
1607 | * | ||
1608 | * Returns 0 for success. | ||
1609 | */ | ||
1610 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | ||
1611 | struct snd_ctl_elem_value *ucontrol) | ||
1612 | { | ||
1613 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1614 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
1615 | unsigned short val; | ||
1616 | unsigned short mask, bitmask; | ||
1617 | |||
1618 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) | ||
1619 | ; | ||
1620 | if (ucontrol->value.enumerated.item[0] > e->mask - 1) | ||
1621 | return -EINVAL; | ||
1622 | val = ucontrol->value.enumerated.item[0] << e->shift_l; | ||
1623 | mask = (bitmask - 1) << e->shift_l; | ||
1624 | if (e->shift_l != e->shift_r) { | ||
1625 | if (ucontrol->value.enumerated.item[1] > e->mask - 1) | ||
1626 | return -EINVAL; | ||
1627 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; | ||
1628 | mask |= (bitmask - 1) << e->shift_r; | ||
1629 | } | ||
1630 | |||
1631 | return snd_soc_update_bits(codec, e->reg, mask, val); | ||
1632 | } | ||
1633 | EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); | ||
1634 | |||
1635 | /** | ||
1636 | * snd_soc_info_enum_ext - external enumerated single mixer info callback | ||
1637 | * @kcontrol: mixer control | ||
1638 | * @uinfo: control element information | ||
1639 | * | ||
1640 | * Callback to provide information about an external enumerated | ||
1641 | * single mixer. | ||
1642 | * | ||
1643 | * Returns 0 for success. | ||
1644 | */ | ||
1645 | int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, | ||
1646 | struct snd_ctl_elem_info *uinfo) | ||
1647 | { | ||
1648 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
1649 | |||
1650 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1651 | uinfo->count = 1; | ||
1652 | uinfo->value.enumerated.items = e->mask; | ||
1653 | |||
1654 | if (uinfo->value.enumerated.item > e->mask - 1) | ||
1655 | uinfo->value.enumerated.item = e->mask - 1; | ||
1656 | strcpy(uinfo->value.enumerated.name, | ||
1657 | e->texts[uinfo->value.enumerated.item]); | ||
1658 | return 0; | ||
1659 | } | ||
1660 | EXPORT_SYMBOL_GPL(snd_soc_info_enum_ext); | ||
1661 | |||
1662 | /** | ||
1663 | * snd_soc_info_volsw_ext - external single mixer info callback | ||
1664 | * @kcontrol: mixer control | ||
1665 | * @uinfo: control element information | ||
1666 | * | ||
1667 | * Callback to provide information about a single external mixer control. | ||
1668 | * | ||
1669 | * Returns 0 for success. | ||
1670 | */ | ||
1671 | int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, | ||
1672 | struct snd_ctl_elem_info *uinfo) | ||
1673 | { | ||
1674 | int mask = kcontrol->private_value; | ||
1675 | |||
1676 | uinfo->type = | ||
1677 | mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1678 | uinfo->count = 1; | ||
1679 | uinfo->value.integer.min = 0; | ||
1680 | uinfo->value.integer.max = mask; | ||
1681 | return 0; | ||
1682 | } | ||
1683 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext); | ||
1684 | |||
1685 | /** | ||
1686 | * snd_soc_info_bool_ext - external single boolean mixer info callback | ||
1687 | * @kcontrol: mixer control | ||
1688 | * @uinfo: control element information | ||
1689 | * | ||
1690 | * Callback to provide information about a single boolean external mixer control. | ||
1691 | * | ||
1692 | * Returns 0 for success. | ||
1693 | */ | ||
1694 | int snd_soc_info_bool_ext(struct snd_kcontrol *kcontrol, | ||
1695 | struct snd_ctl_elem_info *uinfo) | ||
1696 | { | ||
1697 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
1698 | uinfo->count = 1; | ||
1699 | uinfo->value.integer.min = 0; | ||
1700 | uinfo->value.integer.max = 1; | ||
1701 | return 0; | ||
1702 | } | ||
1703 | EXPORT_SYMBOL_GPL(snd_soc_info_bool_ext); | ||
1704 | |||
1705 | /** | ||
1706 | * snd_soc_info_volsw - single mixer info callback | ||
1707 | * @kcontrol: mixer control | ||
1708 | * @uinfo: control element information | ||
1709 | * | ||
1710 | * Callback to provide information about a single mixer control. | ||
1711 | * | ||
1712 | * Returns 0 for success. | ||
1713 | */ | ||
1714 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | ||
1715 | struct snd_ctl_elem_info *uinfo) | ||
1716 | { | ||
1717 | int mask = (kcontrol->private_value >> 16) & 0xff; | ||
1718 | int shift = (kcontrol->private_value >> 8) & 0x0f; | ||
1719 | int rshift = (kcontrol->private_value >> 12) & 0x0f; | ||
1720 | |||
1721 | uinfo->type = | ||
1722 | mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1723 | uinfo->count = shift == rshift ? 1 : 2; | ||
1724 | uinfo->value.integer.min = 0; | ||
1725 | uinfo->value.integer.max = mask; | ||
1726 | return 0; | ||
1727 | } | ||
1728 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); | ||
1729 | |||
1730 | /** | ||
1731 | * snd_soc_get_volsw - single mixer get callback | ||
1732 | * @kcontrol: mixer control | ||
1733 | * @uinfo: control element information | ||
1734 | * | ||
1735 | * Callback to get the value of a single mixer control. | ||
1736 | * | ||
1737 | * Returns 0 for success. | ||
1738 | */ | ||
1739 | int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | ||
1740 | struct snd_ctl_elem_value *ucontrol) | ||
1741 | { | ||
1742 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1743 | int reg = kcontrol->private_value & 0xff; | ||
1744 | int shift = (kcontrol->private_value >> 8) & 0x0f; | ||
1745 | int rshift = (kcontrol->private_value >> 12) & 0x0f; | ||
1746 | int mask = (kcontrol->private_value >> 16) & 0xff; | ||
1747 | int invert = (kcontrol->private_value >> 24) & 0x01; | ||
1748 | |||
1749 | ucontrol->value.integer.value[0] = | ||
1750 | (snd_soc_read(codec, reg) >> shift) & mask; | ||
1751 | if (shift != rshift) | ||
1752 | ucontrol->value.integer.value[1] = | ||
1753 | (snd_soc_read(codec, reg) >> rshift) & mask; | ||
1754 | if (invert) { | ||
1755 | ucontrol->value.integer.value[0] = | ||
1756 | mask - ucontrol->value.integer.value[0]; | ||
1757 | if (shift != rshift) | ||
1758 | ucontrol->value.integer.value[1] = | ||
1759 | mask - ucontrol->value.integer.value[1]; | ||
1760 | } | ||
1761 | |||
1762 | return 0; | ||
1763 | } | ||
1764 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw); | ||
1765 | |||
1766 | /** | ||
1767 | * snd_soc_put_volsw - single mixer put callback | ||
1768 | * @kcontrol: mixer control | ||
1769 | * @uinfo: control element information | ||
1770 | * | ||
1771 | * Callback to set the value of a single mixer control. | ||
1772 | * | ||
1773 | * Returns 0 for success. | ||
1774 | */ | ||
1775 | int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | ||
1776 | struct snd_ctl_elem_value *ucontrol) | ||
1777 | { | ||
1778 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1779 | int reg = kcontrol->private_value & 0xff; | ||
1780 | int shift = (kcontrol->private_value >> 8) & 0x0f; | ||
1781 | int rshift = (kcontrol->private_value >> 12) & 0x0f; | ||
1782 | int mask = (kcontrol->private_value >> 16) & 0xff; | ||
1783 | int invert = (kcontrol->private_value >> 24) & 0x01; | ||
1784 | int err; | ||
1785 | unsigned short val, val2, val_mask; | ||
1786 | |||
1787 | val = (ucontrol->value.integer.value[0] & mask); | ||
1788 | if (invert) | ||
1789 | val = mask - val; | ||
1790 | val_mask = mask << shift; | ||
1791 | val = val << shift; | ||
1792 | if (shift != rshift) { | ||
1793 | val2 = (ucontrol->value.integer.value[1] & mask); | ||
1794 | if (invert) | ||
1795 | val2 = mask - val2; | ||
1796 | val_mask |= mask << rshift; | ||
1797 | val |= val2 << rshift; | ||
1798 | } | ||
1799 | err = snd_soc_update_bits(codec, reg, val_mask, val); | ||
1800 | return err; | ||
1801 | } | ||
1802 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw); | ||
1803 | |||
1804 | /** | ||
1805 | * snd_soc_info_volsw_2r - double mixer info callback | ||
1806 | * @kcontrol: mixer control | ||
1807 | * @uinfo: control element information | ||
1808 | * | ||
1809 | * Callback to provide information about a double mixer control that | ||
1810 | * spans 2 codec registers. | ||
1811 | * | ||
1812 | * Returns 0 for success. | ||
1813 | */ | ||
1814 | int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, | ||
1815 | struct snd_ctl_elem_info *uinfo) | ||
1816 | { | ||
1817 | int mask = (kcontrol->private_value >> 12) & 0xff; | ||
1818 | |||
1819 | uinfo->type = | ||
1820 | mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1821 | uinfo->count = 2; | ||
1822 | uinfo->value.integer.min = 0; | ||
1823 | uinfo->value.integer.max = mask; | ||
1824 | return 0; | ||
1825 | } | ||
1826 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r); | ||
1827 | |||
1828 | /** | ||
1829 | * snd_soc_get_volsw_2r - double mixer get callback | ||
1830 | * @kcontrol: mixer control | ||
1831 | * @uinfo: control element information | ||
1832 | * | ||
1833 | * Callback to get the value of a double mixer control that spans 2 registers. | ||
1834 | * | ||
1835 | * Returns 0 for success. | ||
1836 | */ | ||
1837 | int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol, | ||
1838 | struct snd_ctl_elem_value *ucontrol) | ||
1839 | { | ||
1840 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1841 | int reg = kcontrol->private_value & 0xff; | ||
1842 | int reg2 = (kcontrol->private_value >> 24) & 0xff; | ||
1843 | int shift = (kcontrol->private_value >> 8) & 0x0f; | ||
1844 | int mask = (kcontrol->private_value >> 12) & 0xff; | ||
1845 | int invert = (kcontrol->private_value >> 20) & 0x01; | ||
1846 | |||
1847 | ucontrol->value.integer.value[0] = | ||
1848 | (snd_soc_read(codec, reg) >> shift) & mask; | ||
1849 | ucontrol->value.integer.value[1] = | ||
1850 | (snd_soc_read(codec, reg2) >> shift) & mask; | ||
1851 | if (invert) { | ||
1852 | ucontrol->value.integer.value[0] = | ||
1853 | mask - ucontrol->value.integer.value[0]; | ||
1854 | ucontrol->value.integer.value[1] = | ||
1855 | mask - ucontrol->value.integer.value[1]; | ||
1856 | } | ||
1857 | |||
1858 | return 0; | ||
1859 | } | ||
1860 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r); | ||
1861 | |||
1862 | /** | ||
1863 | * snd_soc_put_volsw_2r - double mixer set callback | ||
1864 | * @kcontrol: mixer control | ||
1865 | * @uinfo: control element information | ||
1866 | * | ||
1867 | * Callback to set the value of a double mixer control that spans 2 registers. | ||
1868 | * | ||
1869 | * Returns 0 for success. | ||
1870 | */ | ||
1871 | int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, | ||
1872 | struct snd_ctl_elem_value *ucontrol) | ||
1873 | { | ||
1874 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1875 | int reg = kcontrol->private_value & 0xff; | ||
1876 | int reg2 = (kcontrol->private_value >> 24) & 0xff; | ||
1877 | int shift = (kcontrol->private_value >> 8) & 0x0f; | ||
1878 | int mask = (kcontrol->private_value >> 12) & 0xff; | ||
1879 | int invert = (kcontrol->private_value >> 20) & 0x01; | ||
1880 | int err; | ||
1881 | unsigned short val, val2, val_mask; | ||
1882 | |||
1883 | val_mask = mask << shift; | ||
1884 | val = (ucontrol->value.integer.value[0] & mask); | ||
1885 | val2 = (ucontrol->value.integer.value[1] & mask); | ||
1886 | |||
1887 | if (invert) { | ||
1888 | val = mask - val; | ||
1889 | val2 = mask - val2; | ||
1890 | } | ||
1891 | |||
1892 | val = val << shift; | ||
1893 | val2 = val2 << shift; | ||
1894 | |||
1895 | if ((err = snd_soc_update_bits(codec, reg, val_mask, val)) < 0) | ||
1896 | return err; | ||
1897 | |||
1898 | err = snd_soc_update_bits(codec, reg2, val_mask, val2); | ||
1899 | return err; | ||
1900 | } | ||
1901 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r); | ||
1902 | |||
1903 | static int __devinit snd_soc_init(void) | ||
1904 | { | ||
1905 | printk(KERN_INFO "ASoC version %s\n", SND_SOC_VERSION); | ||
1906 | return platform_driver_register(&soc_driver); | ||
1907 | } | ||
1908 | |||
1909 | static void snd_soc_exit(void) | ||
1910 | { | ||
1911 | platform_driver_unregister(&soc_driver); | ||
1912 | } | ||
1913 | |||
1914 | module_init(snd_soc_init); | ||
1915 | module_exit(snd_soc_exit); | ||
1916 | |||
1917 | /* Module information */ | ||
1918 | MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); | ||
1919 | MODULE_DESCRIPTION("ALSA SoC Core"); | ||
1920 | MODULE_LICENSE("GPL"); | ||