diff options
author | Liam Girdwood <lg@opensource.wolfsonmicro.com> | 2007-02-02 11:13:49 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2007-02-09 03:03:36 -0500 |
commit | cb666e5bd865cc991c0048d6e81581019a141820 (patch) | |
tree | c5dafb6f597df92f0559922c40cc6c64cb396221 | |
parent | 1c433fbda4896a6455d97b66a4f2646cbdd52a8c (diff) |
[ALSA] soc - ASoC 0.13 core changes
This patch updates the ASoC core to the new DAI matching and clocking
API in version 0.13
Changes:-
o Removed DAI capabilities matching code in favour of manual matching
in the machine drivers.
o Added DAI operations for codec and CPU interfaces.
o Removed config_sysclk() function and struct snd_soc_clock_info. No
longer needed as clocking is now configured manually in the machine
drivers. Also removed other clocking data from structures.
o Added machine driver prepare callback.
Signed-off-by: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
-rw-r--r-- | sound/soc/soc-core.c | 781 |
1 files changed, 148 insertions, 633 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 87be938622dd..36519aef55d9 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -47,27 +47,11 @@ | |||
47 | #else | 47 | #else |
48 | #define dbg(format, arg...) | 48 | #define dbg(format, arg...) |
49 | #endif | 49 | #endif |
50 | /* debug DAI capabilities matching */ | ||
51 | #define SOC_DEBUG_DAI 0 | ||
52 | #if SOC_DEBUG_DAI | ||
53 | #define dbgc(format, arg...) printk(format, ## arg) | ||
54 | #else | ||
55 | #define dbgc(format, arg...) | ||
56 | #endif | ||
57 | |||
58 | #define CODEC_CPU(codec, cpu) ((codec << 4) | cpu) | ||
59 | 50 | ||
60 | static DEFINE_MUTEX(pcm_mutex); | 51 | static DEFINE_MUTEX(pcm_mutex); |
61 | static DEFINE_MUTEX(io_mutex); | 52 | static DEFINE_MUTEX(io_mutex); |
62 | static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); | 53 | static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); |
63 | 54 | ||
64 | /* supported sample rates */ | ||
65 | /* ATTENTION: these values depend on the definition in pcm.h! */ | ||
66 | static const unsigned int rates[] = { | ||
67 | 5512, 8000, 11025, 16000, 22050, 32000, 44100, | ||
68 | 48000, 64000, 88200, 96000, 176400, 192000 | ||
69 | }; | ||
70 | |||
71 | /* | 55 | /* |
72 | * This is a timeout to do a DAPM powerdown after a stream is closed(). | 56 | * This is a timeout to do a DAPM powerdown after a stream is closed(). |
73 | * It can be used to eliminate pops between different playback streams, e.g. | 57 | * It can be used to eliminate pops between different playback streams, e.g. |
@@ -142,458 +126,6 @@ static inline const char* get_dai_name(int type) | |||
142 | return NULL; | 126 | return NULL; |
143 | } | 127 | } |
144 | 128 | ||
145 | /* get rate format from rate */ | ||
146 | static inline int soc_get_rate_format(int rate) | ||
147 | { | ||
148 | int i; | ||
149 | |||
150 | for (i = 0; i < ARRAY_SIZE(rates); i++) { | ||
151 | if (rates[i] == rate) | ||
152 | return 1 << i; | ||
153 | } | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | /* gets the audio system mclk/sysclk for the given parameters */ | ||
158 | static unsigned inline int soc_get_mclk(struct snd_soc_pcm_runtime *rtd, | ||
159 | struct snd_soc_clock_info *info) | ||
160 | { | ||
161 | struct snd_soc_device *socdev = rtd->socdev; | ||
162 | struct snd_soc_machine *machine = socdev->machine; | ||
163 | int i; | ||
164 | |||
165 | /* find the matching machine config and get it's mclk for the given | ||
166 | * sample rate and hardware format */ | ||
167 | for(i = 0; i < machine->num_links; i++) { | ||
168 | if (machine->dai_link[i].cpu_dai == rtd->cpu_dai && | ||
169 | machine->dai_link[i].config_sysclk) | ||
170 | return machine->dai_link[i].config_sysclk(rtd, info); | ||
171 | } | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | /* changes a bitclk multiplier mask to a divider mask */ | ||
176 | static u64 soc_bfs_rcw_to_div(u64 bfs, int rate, unsigned int mclk, | ||
177 | unsigned int pcmfmt, unsigned int chn) | ||
178 | { | ||
179 | int i, j; | ||
180 | u64 bfs_ = 0; | ||
181 | int size = snd_pcm_format_physical_width(pcmfmt), min = 0; | ||
182 | |||
183 | if (size <= 0) | ||
184 | return 0; | ||
185 | |||
186 | /* the minimum bit clock that has enough bandwidth */ | ||
187 | min = size * rate * chn; | ||
188 | dbgc("rcw --> div min bclk %d with mclk %d\n", min, mclk); | ||
189 | |||
190 | for (i = 0; i < 64; i++) { | ||
191 | if ((bfs >> i) & 0x1) { | ||
192 | j = min * (i + 1); | ||
193 | bfs_ |= SND_SOC_FSBD(mclk/j); | ||
194 | dbgc("rcw --> div support mult %d\n", | ||
195 | SND_SOC_FSBD_REAL(1<<i)); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | return bfs_; | ||
200 | } | ||
201 | |||
202 | /* changes a bitclk divider mask to a multiplier mask */ | ||
203 | static u64 soc_bfs_div_to_rcw(u64 bfs, int rate, unsigned int mclk, | ||
204 | unsigned int pcmfmt, unsigned int chn) | ||
205 | { | ||
206 | int i, j; | ||
207 | u64 bfs_ = 0; | ||
208 | |||
209 | int size = snd_pcm_format_physical_width(pcmfmt), min = 0; | ||
210 | |||
211 | if (size <= 0) | ||
212 | return 0; | ||
213 | |||
214 | /* the minimum bit clock that has enough bandwidth */ | ||
215 | min = size * rate * chn; | ||
216 | dbgc("div to rcw min bclk %d with mclk %d\n", min, mclk); | ||
217 | |||
218 | for (i = 0; i < 64; i++) { | ||
219 | if ((bfs >> i) & 0x1) { | ||
220 | j = mclk / (i + 1); | ||
221 | if (j >= min) { | ||
222 | bfs_ |= SND_SOC_FSBW(j/min); | ||
223 | dbgc("div --> rcw support div %d\n", | ||
224 | SND_SOC_FSBW_REAL(1<<i)); | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | |||
229 | return bfs_; | ||
230 | } | ||
231 | |||
232 | /* changes a constant bitclk to a multiplier mask */ | ||
233 | static u64 soc_bfs_rate_to_rcw(u64 bfs, int rate, unsigned int mclk, | ||
234 | unsigned int pcmfmt, unsigned int chn) | ||
235 | { | ||
236 | unsigned int bfs_ = rate * bfs; | ||
237 | int size = snd_pcm_format_physical_width(pcmfmt), min = 0; | ||
238 | |||
239 | if (size <= 0) | ||
240 | return 0; | ||
241 | |||
242 | /* the minimum bit clock that has enough bandwidth */ | ||
243 | min = size * rate * chn; | ||
244 | dbgc("rate --> rcw min bclk %d with mclk %d\n", min, mclk); | ||
245 | |||
246 | if (bfs_ < min) | ||
247 | return 0; | ||
248 | else { | ||
249 | bfs_ = SND_SOC_FSBW(bfs_/min); | ||
250 | dbgc("rate --> rcw support div %d\n", SND_SOC_FSBW_REAL(bfs_)); | ||
251 | return bfs_; | ||
252 | } | ||
253 | } | ||
254 | |||
255 | /* changes a bitclk multiplier mask to a divider mask */ | ||
256 | static u64 soc_bfs_rate_to_div(u64 bfs, int rate, unsigned int mclk, | ||
257 | unsigned int pcmfmt, unsigned int chn) | ||
258 | { | ||
259 | unsigned int bfs_ = rate * bfs; | ||
260 | int size = snd_pcm_format_physical_width(pcmfmt), min = 0; | ||
261 | |||
262 | if (size <= 0) | ||
263 | return 0; | ||
264 | |||
265 | /* the minimum bit clock that has enough bandwidth */ | ||
266 | min = size * rate * chn; | ||
267 | dbgc("rate --> div min bclk %d with mclk %d\n", min, mclk); | ||
268 | |||
269 | if (bfs_ < min) | ||
270 | return 0; | ||
271 | else { | ||
272 | bfs_ = SND_SOC_FSBW(mclk/bfs_); | ||
273 | dbgc("rate --> div support div %d\n", SND_SOC_FSBD_REAL(bfs_)); | ||
274 | return bfs_; | ||
275 | } | ||
276 | } | ||
277 | |||
278 | /* Matches codec DAI and SoC CPU DAI hardware parameters */ | ||
279 | static int soc_hw_match_params(struct snd_pcm_substream *substream, | ||
280 | struct snd_pcm_hw_params *params) | ||
281 | { | ||
282 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
283 | struct snd_soc_dai_mode *codec_dai_mode = NULL; | ||
284 | struct snd_soc_dai_mode *cpu_dai_mode = NULL; | ||
285 | struct snd_soc_clock_info clk_info; | ||
286 | unsigned int fs, mclk, rate = params_rate(params), | ||
287 | chn, j, k, cpu_bclk, codec_bclk, pcmrate; | ||
288 | u16 fmt = 0; | ||
289 | u64 codec_bfs, cpu_bfs; | ||
290 | |||
291 | dbg("asoc: match version %s\n", SND_SOC_VERSION); | ||
292 | clk_info.rate = rate; | ||
293 | pcmrate = soc_get_rate_format(rate); | ||
294 | |||
295 | /* try and find a match from the codec and cpu DAI capabilities */ | ||
296 | for (j = 0; j < rtd->codec_dai->caps.num_modes; j++) { | ||
297 | for (k = 0; k < rtd->cpu_dai->caps.num_modes; k++) { | ||
298 | codec_dai_mode = &rtd->codec_dai->caps.mode[j]; | ||
299 | cpu_dai_mode = &rtd->cpu_dai->caps.mode[k]; | ||
300 | |||
301 | if (!(codec_dai_mode->pcmrate & cpu_dai_mode->pcmrate & | ||
302 | pcmrate)) { | ||
303 | dbgc("asoc: DAI[%d:%d] failed to match rate\n", j, k); | ||
304 | continue; | ||
305 | } | ||
306 | |||
307 | fmt = codec_dai_mode->fmt & cpu_dai_mode->fmt; | ||
308 | if (!(fmt & SND_SOC_DAIFMT_FORMAT_MASK)) { | ||
309 | dbgc("asoc: DAI[%d:%d] failed to match format\n", j, k); | ||
310 | continue; | ||
311 | } | ||
312 | |||
313 | if (!(fmt & SND_SOC_DAIFMT_CLOCK_MASK)) { | ||
314 | dbgc("asoc: DAI[%d:%d] failed to match clock masters\n", | ||
315 | j, k); | ||
316 | continue; | ||
317 | } | ||
318 | |||
319 | if (!(fmt & SND_SOC_DAIFMT_INV_MASK)) { | ||
320 | dbgc("asoc: DAI[%d:%d] failed to match invert\n", j, k); | ||
321 | continue; | ||
322 | } | ||
323 | |||
324 | if (!(codec_dai_mode->pcmfmt & cpu_dai_mode->pcmfmt)) { | ||
325 | dbgc("asoc: DAI[%d:%d] failed to match pcm format\n", j, k); | ||
326 | continue; | ||
327 | } | ||
328 | |||
329 | if (!(codec_dai_mode->pcmdir & cpu_dai_mode->pcmdir)) { | ||
330 | dbgc("asoc: DAI[%d:%d] failed to match direction\n", j, k); | ||
331 | continue; | ||
332 | } | ||
333 | |||
334 | /* todo - still need to add tdm selection */ | ||
335 | rtd->cpu_dai->dai_runtime.fmt = | ||
336 | rtd->codec_dai->dai_runtime.fmt = | ||
337 | 1 << (ffs(fmt & SND_SOC_DAIFMT_FORMAT_MASK) -1) | | ||
338 | 1 << (ffs(fmt & SND_SOC_DAIFMT_CLOCK_MASK) - 1) | | ||
339 | 1 << (ffs(fmt & SND_SOC_DAIFMT_INV_MASK) - 1); | ||
340 | clk_info.bclk_master = | ||
341 | rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK; | ||
342 | |||
343 | /* make sure the ratio between rate and master | ||
344 | * clock is acceptable*/ | ||
345 | fs = (cpu_dai_mode->fs & codec_dai_mode->fs); | ||
346 | if (fs == 0) { | ||
347 | dbgc("asoc: DAI[%d:%d] failed to match FS\n", j, k); | ||
348 | continue; | ||
349 | } | ||
350 | clk_info.fs = rtd->cpu_dai->dai_runtime.fs = | ||
351 | rtd->codec_dai->dai_runtime.fs = fs; | ||
352 | |||
353 | /* calculate audio system clocking using slowest clocks possible*/ | ||
354 | mclk = soc_get_mclk(rtd, &clk_info); | ||
355 | if (mclk == 0) { | ||
356 | dbgc("asoc: DAI[%d:%d] configuration not clockable\n", j, k); | ||
357 | dbgc("asoc: rate %d fs %d master %x\n", rate, fs, | ||
358 | clk_info.bclk_master); | ||
359 | continue; | ||
360 | } | ||
361 | |||
362 | /* calculate word size (per channel) and frame size */ | ||
363 | rtd->codec_dai->dai_runtime.pcmfmt = | ||
364 | rtd->cpu_dai->dai_runtime.pcmfmt = | ||
365 | 1 << params_format(params); | ||
366 | |||
367 | chn = params_channels(params); | ||
368 | /* i2s always has left and right */ | ||
369 | if (params_channels(params) == 1 && | ||
370 | rtd->cpu_dai->dai_runtime.fmt & (SND_SOC_DAIFMT_I2S | | ||
371 | SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_LEFT_J)) | ||
372 | chn <<= 1; | ||
373 | |||
374 | /* Calculate bfs - the ratio between bitclock and the sample rate | ||
375 | * We must take into consideration the dividers and multipliers | ||
376 | * used in the codec and cpu DAI modes. We always choose the | ||
377 | * lowest possible clocks to reduce power. | ||
378 | */ | ||
379 | switch (CODEC_CPU(codec_dai_mode->flags, cpu_dai_mode->flags)) { | ||
380 | case CODEC_CPU(SND_SOC_DAI_BFS_DIV, SND_SOC_DAI_BFS_DIV): | ||
381 | /* cpu & codec bfs dividers */ | ||
382 | rtd->cpu_dai->dai_runtime.bfs = | ||
383 | rtd->codec_dai->dai_runtime.bfs = | ||
384 | 1 << (fls(codec_dai_mode->bfs & cpu_dai_mode->bfs) - 1); | ||
385 | break; | ||
386 | case CODEC_CPU(SND_SOC_DAI_BFS_DIV, SND_SOC_DAI_BFS_RCW): | ||
387 | /* normalise bfs codec divider & cpu rcw mult */ | ||
388 | codec_bfs = soc_bfs_div_to_rcw(codec_dai_mode->bfs, rate, | ||
389 | mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); | ||
390 | rtd->cpu_dai->dai_runtime.bfs = | ||
391 | 1 << (ffs(codec_bfs & cpu_dai_mode->bfs) - 1); | ||
392 | cpu_bfs = soc_bfs_rcw_to_div(cpu_dai_mode->bfs, rate, mclk, | ||
393 | rtd->codec_dai->dai_runtime.pcmfmt, chn); | ||
394 | rtd->codec_dai->dai_runtime.bfs = | ||
395 | 1 << (fls(codec_dai_mode->bfs & cpu_bfs) - 1); | ||
396 | break; | ||
397 | case CODEC_CPU(SND_SOC_DAI_BFS_RCW, SND_SOC_DAI_BFS_DIV): | ||
398 | /* normalise bfs codec rcw mult & cpu divider */ | ||
399 | codec_bfs = soc_bfs_rcw_to_div(codec_dai_mode->bfs, rate, | ||
400 | mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); | ||
401 | rtd->cpu_dai->dai_runtime.bfs = | ||
402 | 1 << (fls(codec_bfs & cpu_dai_mode->bfs) -1); | ||
403 | cpu_bfs = soc_bfs_div_to_rcw(cpu_dai_mode->bfs, rate, mclk, | ||
404 | rtd->codec_dai->dai_runtime.pcmfmt, chn); | ||
405 | rtd->codec_dai->dai_runtime.bfs = | ||
406 | 1 << (ffs(codec_dai_mode->bfs & cpu_bfs) -1); | ||
407 | break; | ||
408 | case CODEC_CPU(SND_SOC_DAI_BFS_RCW, SND_SOC_DAI_BFS_RCW): | ||
409 | /* codec & cpu bfs rate rcw multipliers */ | ||
410 | rtd->cpu_dai->dai_runtime.bfs = | ||
411 | rtd->codec_dai->dai_runtime.bfs = | ||
412 | 1 << (ffs(codec_dai_mode->bfs & cpu_dai_mode->bfs) -1); | ||
413 | break; | ||
414 | case CODEC_CPU(SND_SOC_DAI_BFS_DIV, SND_SOC_DAI_BFS_RATE): | ||
415 | /* normalise cpu bfs rate const multiplier & codec div */ | ||
416 | cpu_bfs = soc_bfs_rate_to_div(cpu_dai_mode->bfs, rate, | ||
417 | mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); | ||
418 | if(codec_dai_mode->bfs & cpu_bfs) { | ||
419 | rtd->codec_dai->dai_runtime.bfs = cpu_bfs; | ||
420 | rtd->cpu_dai->dai_runtime.bfs = cpu_dai_mode->bfs; | ||
421 | } else | ||
422 | rtd->cpu_dai->dai_runtime.bfs = 0; | ||
423 | break; | ||
424 | case CODEC_CPU(SND_SOC_DAI_BFS_RCW, SND_SOC_DAI_BFS_RATE): | ||
425 | /* normalise cpu bfs rate const multiplier & codec rcw mult */ | ||
426 | cpu_bfs = soc_bfs_rate_to_rcw(cpu_dai_mode->bfs, rate, | ||
427 | mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); | ||
428 | if(codec_dai_mode->bfs & cpu_bfs) { | ||
429 | rtd->codec_dai->dai_runtime.bfs = cpu_bfs; | ||
430 | rtd->cpu_dai->dai_runtime.bfs = cpu_dai_mode->bfs; | ||
431 | } else | ||
432 | rtd->cpu_dai->dai_runtime.bfs = 0; | ||
433 | break; | ||
434 | case CODEC_CPU(SND_SOC_DAI_BFS_RATE, SND_SOC_DAI_BFS_RCW): | ||
435 | /* normalise cpu bfs rate rcw multiplier & codec const mult */ | ||
436 | codec_bfs = soc_bfs_rate_to_rcw(codec_dai_mode->bfs, rate, | ||
437 | mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); | ||
438 | if(cpu_dai_mode->bfs & codec_bfs) { | ||
439 | rtd->cpu_dai->dai_runtime.bfs = codec_bfs; | ||
440 | rtd->codec_dai->dai_runtime.bfs = codec_dai_mode->bfs; | ||
441 | } else | ||
442 | rtd->cpu_dai->dai_runtime.bfs = 0; | ||
443 | break; | ||
444 | case CODEC_CPU(SND_SOC_DAI_BFS_RATE, SND_SOC_DAI_BFS_DIV): | ||
445 | /* normalise cpu bfs div & codec const mult */ | ||
446 | codec_bfs = soc_bfs_rate_to_div(codec_dai_mode->bfs, rate, | ||
447 | mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); | ||
448 | if(cpu_dai_mode->bfs & codec_bfs) { | ||
449 | rtd->cpu_dai->dai_runtime.bfs = codec_bfs; | ||
450 | rtd->codec_dai->dai_runtime.bfs = codec_dai_mode->bfs; | ||
451 | } else | ||
452 | rtd->cpu_dai->dai_runtime.bfs = 0; | ||
453 | break; | ||
454 | case CODEC_CPU(SND_SOC_DAI_BFS_RATE, SND_SOC_DAI_BFS_RATE): | ||
455 | /* cpu & codec constant mult */ | ||
456 | if(codec_dai_mode->bfs == cpu_dai_mode->bfs) | ||
457 | rtd->cpu_dai->dai_runtime.bfs = | ||
458 | rtd->codec_dai->dai_runtime.bfs = | ||
459 | codec_dai_mode->bfs; | ||
460 | else | ||
461 | rtd->cpu_dai->dai_runtime.bfs = | ||
462 | rtd->codec_dai->dai_runtime.bfs = 0; | ||
463 | break; | ||
464 | } | ||
465 | |||
466 | /* make sure the bit clock speed is acceptable */ | ||
467 | if (!rtd->cpu_dai->dai_runtime.bfs || | ||
468 | !rtd->codec_dai->dai_runtime.bfs) { | ||
469 | dbgc("asoc: DAI[%d:%d] failed to match BFS\n", j, k); | ||
470 | dbgc("asoc: cpu_dai %llu codec %llu\n", | ||
471 | rtd->cpu_dai->dai_runtime.bfs, | ||
472 | rtd->codec_dai->dai_runtime.bfs); | ||
473 | dbgc("asoc: mclk %d hwfmt %x\n", mclk, fmt); | ||
474 | continue; | ||
475 | } | ||
476 | |||
477 | goto found; | ||
478 | } | ||
479 | } | ||
480 | printk(KERN_ERR "asoc: no matching DAI found between codec and CPU\n"); | ||
481 | return -EINVAL; | ||
482 | |||
483 | found: | ||
484 | /* we have matching DAI's, so complete the runtime info */ | ||
485 | rtd->codec_dai->dai_runtime.pcmrate = | ||
486 | rtd->cpu_dai->dai_runtime.pcmrate = | ||
487 | soc_get_rate_format(rate); | ||
488 | |||
489 | rtd->codec_dai->dai_runtime.priv = codec_dai_mode->priv; | ||
490 | rtd->cpu_dai->dai_runtime.priv = cpu_dai_mode->priv; | ||
491 | rtd->codec_dai->dai_runtime.flags = codec_dai_mode->flags; | ||
492 | rtd->cpu_dai->dai_runtime.flags = cpu_dai_mode->flags; | ||
493 | |||
494 | /* for debug atm */ | ||
495 | dbg("asoc: DAI[%d:%d] Match OK\n", j, k); | ||
496 | if (rtd->codec_dai->dai_runtime.flags == SND_SOC_DAI_BFS_DIV) { | ||
497 | codec_bclk = (rtd->codec_dai->dai_runtime.fs * params_rate(params)) / | ||
498 | SND_SOC_FSBD_REAL(rtd->codec_dai->dai_runtime.bfs); | ||
499 | dbg("asoc: codec fs %d mclk %d bfs div %d bclk %d\n", | ||
500 | rtd->codec_dai->dai_runtime.fs, mclk, | ||
501 | SND_SOC_FSBD_REAL(rtd->codec_dai->dai_runtime.bfs), codec_bclk); | ||
502 | } else if(rtd->codec_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RATE) { | ||
503 | codec_bclk = params_rate(params) * rtd->codec_dai->dai_runtime.bfs; | ||
504 | dbg("asoc: codec fs %d mclk %d bfs rate mult %llu bclk %d\n", | ||
505 | rtd->codec_dai->dai_runtime.fs, mclk, | ||
506 | rtd->codec_dai->dai_runtime.bfs, codec_bclk); | ||
507 | } else if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RCW) { | ||
508 | codec_bclk = params_rate(params) * params_channels(params) * | ||
509 | snd_pcm_format_physical_width(rtd->codec_dai->dai_runtime.pcmfmt) * | ||
510 | SND_SOC_FSBW_REAL(rtd->codec_dai->dai_runtime.bfs); | ||
511 | dbg("asoc: codec fs %d mclk %d bfs rcw mult %d bclk %d\n", | ||
512 | rtd->codec_dai->dai_runtime.fs, mclk, | ||
513 | SND_SOC_FSBW_REAL(rtd->codec_dai->dai_runtime.bfs), codec_bclk); | ||
514 | } else | ||
515 | codec_bclk = 0; | ||
516 | |||
517 | if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_DIV) { | ||
518 | cpu_bclk = (rtd->cpu_dai->dai_runtime.fs * params_rate(params)) / | ||
519 | SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs); | ||
520 | dbg("asoc: cpu fs %d mclk %d bfs div %d bclk %d\n", | ||
521 | rtd->cpu_dai->dai_runtime.fs, mclk, | ||
522 | SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk); | ||
523 | } else if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RATE) { | ||
524 | cpu_bclk = params_rate(params) * rtd->cpu_dai->dai_runtime.bfs; | ||
525 | dbg("asoc: cpu fs %d mclk %d bfs rate mult %llu bclk %d\n", | ||
526 | rtd->cpu_dai->dai_runtime.fs, mclk, | ||
527 | rtd->cpu_dai->dai_runtime.bfs, cpu_bclk); | ||
528 | } else if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RCW) { | ||
529 | cpu_bclk = params_rate(params) * params_channels(params) * | ||
530 | snd_pcm_format_physical_width(rtd->cpu_dai->dai_runtime.pcmfmt) * | ||
531 | SND_SOC_FSBW_REAL(rtd->cpu_dai->dai_runtime.bfs); | ||
532 | dbg("asoc: cpu fs %d mclk %d bfs mult rcw %d bclk %d\n", | ||
533 | rtd->cpu_dai->dai_runtime.fs, mclk, | ||
534 | SND_SOC_FSBW_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk); | ||
535 | } else | ||
536 | cpu_bclk = 0; | ||
537 | |||
538 | /* | ||
539 | * Check we have matching bitclocks. If we don't then it means the | ||
540 | * sysclock returned by either the codec or cpu DAI (selected by the | ||
541 | * machine sysclock function) is wrong compared with the supported DAI | ||
542 | * modes for the codec or cpu DAI. Check your codec or CPU DAI | ||
543 | * config_sysclock() functions. | ||
544 | */ | ||
545 | if (cpu_bclk != codec_bclk && cpu_bclk){ | ||
546 | printk(KERN_ERR | ||
547 | "asoc: codec and cpu bitclocks differ, audio may be wrong speed\n" | ||
548 | ); | ||
549 | printk(KERN_ERR "asoc: codec %d != cpu %d\n", codec_bclk, cpu_bclk); | ||
550 | } | ||
551 | |||
552 | switch(rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK) { | ||
553 | case SND_SOC_DAIFMT_CBM_CFM: | ||
554 | dbg("asoc: DAI codec BCLK master, LRC master\n"); | ||
555 | break; | ||
556 | case SND_SOC_DAIFMT_CBS_CFM: | ||
557 | dbg("asoc: DAI codec BCLK slave, LRC master\n"); | ||
558 | break; | ||
559 | case SND_SOC_DAIFMT_CBM_CFS: | ||
560 | dbg("asoc: DAI codec BCLK master, LRC slave\n"); | ||
561 | break; | ||
562 | case SND_SOC_DAIFMT_CBS_CFS: | ||
563 | dbg("asoc: DAI codec BCLK slave, LRC slave\n"); | ||
564 | break; | ||
565 | } | ||
566 | dbg("asoc: mode %x, invert %x\n", | ||
567 | rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_FORMAT_MASK, | ||
568 | rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_INV_MASK); | ||
569 | dbg("asoc: audio rate %d chn %d fmt %x\n", params_rate(params), | ||
570 | params_channels(params), params_format(params)); | ||
571 | |||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | static inline u32 get_rates(struct snd_soc_dai_mode *modes, int nmodes) | ||
576 | { | ||
577 | int i; | ||
578 | u32 rates = 0; | ||
579 | |||
580 | for(i = 0; i < nmodes; i++) | ||
581 | rates |= modes[i].pcmrate; | ||
582 | |||
583 | return rates; | ||
584 | } | ||
585 | |||
586 | static inline u64 get_formats(struct snd_soc_dai_mode *modes, int nmodes) | ||
587 | { | ||
588 | int i; | ||
589 | u64 formats = 0; | ||
590 | |||
591 | for(i = 0; i < nmodes; i++) | ||
592 | formats |= modes[i].pcmfmt; | ||
593 | |||
594 | return formats; | ||
595 | } | ||
596 | |||
597 | /* | 129 | /* |
598 | * Called by ALSA when a PCM substream is opened, the runtime->hw record is | 130 | * Called by ALSA when a PCM substream is opened, the runtime->hw record is |
599 | * then initialized and any private data can be allocated. This also calls | 131 | * then initialized and any private data can be allocated. This also calls |
@@ -604,20 +136,20 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
604 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 136 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
605 | struct snd_soc_device *socdev = rtd->socdev; | 137 | struct snd_soc_device *socdev = rtd->socdev; |
606 | struct snd_pcm_runtime *runtime = substream->runtime; | 138 | struct snd_pcm_runtime *runtime = substream->runtime; |
607 | struct snd_soc_machine *machine = socdev->machine; | 139 | struct snd_soc_dai_link *machine = rtd->dai; |
608 | struct snd_soc_platform *platform = socdev->platform; | 140 | struct snd_soc_platform *platform = socdev->platform; |
609 | struct snd_soc_codec_dai *codec_dai = rtd->codec_dai; | 141 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; |
610 | struct snd_soc_cpu_dai *cpu_dai = rtd->cpu_dai; | 142 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; |
611 | int ret = 0; | 143 | int ret = 0; |
612 | 144 | ||
613 | mutex_lock(&pcm_mutex); | 145 | mutex_lock(&pcm_mutex); |
614 | 146 | ||
615 | /* startup the audio subsystem */ | 147 | /* startup the audio subsystem */ |
616 | if (rtd->cpu_dai->ops.startup) { | 148 | if (cpu_dai->ops.startup) { |
617 | ret = rtd->cpu_dai->ops.startup(substream); | 149 | ret = cpu_dai->ops.startup(substream); |
618 | if (ret < 0) { | 150 | if (ret < 0) { |
619 | printk(KERN_ERR "asoc: can't open interface %s\n", | 151 | printk(KERN_ERR "asoc: can't open interface %s\n", |
620 | rtd->cpu_dai->name); | 152 | cpu_dai->name); |
621 | goto out; | 153 | goto out; |
622 | } | 154 | } |
623 | } | 155 | } |
@@ -630,116 +162,101 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
630 | } | 162 | } |
631 | } | 163 | } |
632 | 164 | ||
633 | if (machine->ops && machine->ops->startup) { | 165 | if (codec_dai->ops.startup) { |
634 | ret = machine->ops->startup(substream); | 166 | ret = codec_dai->ops.startup(substream); |
635 | if (ret < 0) { | 167 | if (ret < 0) { |
636 | printk(KERN_ERR "asoc: %s startup failed\n", machine->name); | 168 | printk(KERN_ERR "asoc: can't open codec %s\n", |
637 | goto machine_err; | 169 | codec_dai->name); |
170 | goto codec_dai_err; | ||
638 | } | 171 | } |
639 | } | 172 | } |
640 | 173 | ||
641 | if (rtd->codec_dai->ops.startup) { | 174 | if (machine->ops && machine->ops->startup) { |
642 | ret = rtd->codec_dai->ops.startup(substream); | 175 | ret = machine->ops->startup(substream); |
643 | if (ret < 0) { | 176 | if (ret < 0) { |
644 | printk(KERN_ERR "asoc: can't open codec %s\n", | 177 | printk(KERN_ERR "asoc: %s startup failed\n", machine->name); |
645 | rtd->codec_dai->name); | 178 | goto machine_err; |
646 | goto codec_dai_err; | ||
647 | } | 179 | } |
648 | } | 180 | } |
649 | 181 | ||
650 | /* create runtime params from DMA, codec and cpu DAI */ | ||
651 | if (runtime->hw.rates) | ||
652 | runtime->hw.rates &= | ||
653 | get_rates(codec_dai->caps.mode, codec_dai->caps.num_modes) & | ||
654 | get_rates(cpu_dai->caps.mode, cpu_dai->caps.num_modes); | ||
655 | else | ||
656 | runtime->hw.rates = | ||
657 | get_rates(codec_dai->caps.mode, codec_dai->caps.num_modes) & | ||
658 | get_rates(cpu_dai->caps.mode, cpu_dai->caps.num_modes); | ||
659 | if (runtime->hw.formats) | ||
660 | runtime->hw.formats &= | ||
661 | get_formats(codec_dai->caps.mode, codec_dai->caps.num_modes) & | ||
662 | get_formats(cpu_dai->caps.mode, cpu_dai->caps.num_modes); | ||
663 | else | ||
664 | runtime->hw.formats = | ||
665 | get_formats(codec_dai->caps.mode, codec_dai->caps.num_modes) & | ||
666 | get_formats(cpu_dai->caps.mode, cpu_dai->caps.num_modes); | ||
667 | |||
668 | /* Check that the codec and cpu DAI's are compatible */ | 182 | /* Check that the codec and cpu DAI's are compatible */ |
669 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 183 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
670 | runtime->hw.rate_min = | 184 | runtime->hw.rate_min = |
671 | max(rtd->codec_dai->playback.rate_min, | 185 | max(codec_dai->playback.rate_min, cpu_dai->playback.rate_min); |
672 | rtd->cpu_dai->playback.rate_min); | ||
673 | runtime->hw.rate_max = | 186 | runtime->hw.rate_max = |
674 | min(rtd->codec_dai->playback.rate_max, | 187 | min(codec_dai->playback.rate_max, cpu_dai->playback.rate_max); |
675 | rtd->cpu_dai->playback.rate_max); | ||
676 | runtime->hw.channels_min = | 188 | runtime->hw.channels_min = |
677 | max(rtd->codec_dai->playback.channels_min, | 189 | max(codec_dai->playback.channels_min, |
678 | rtd->cpu_dai->playback.channels_min); | 190 | cpu_dai->playback.channels_min); |
679 | runtime->hw.channels_max = | 191 | runtime->hw.channels_max = |
680 | min(rtd->codec_dai->playback.channels_max, | 192 | min(codec_dai->playback.channels_max, |
681 | rtd->cpu_dai->playback.channels_max); | 193 | cpu_dai->playback.channels_max); |
194 | runtime->hw.formats = | ||
195 | codec_dai->playback.formats & cpu_dai->playback.formats; | ||
196 | runtime->hw.rates = | ||
197 | codec_dai->playback.rates & cpu_dai->playback.rates; | ||
682 | } else { | 198 | } else { |
683 | runtime->hw.rate_min = | 199 | runtime->hw.rate_min = |
684 | max(rtd->codec_dai->capture.rate_min, | 200 | max(codec_dai->capture.rate_min, cpu_dai->capture.rate_min); |
685 | rtd->cpu_dai->capture.rate_min); | ||
686 | runtime->hw.rate_max = | 201 | runtime->hw.rate_max = |
687 | min(rtd->codec_dai->capture.rate_max, | 202 | min(codec_dai->capture.rate_max, cpu_dai->capture.rate_max); |
688 | rtd->cpu_dai->capture.rate_max); | ||
689 | runtime->hw.channels_min = | 203 | runtime->hw.channels_min = |
690 | max(rtd->codec_dai->capture.channels_min, | 204 | max(codec_dai->capture.channels_min, |
691 | rtd->cpu_dai->capture.channels_min); | 205 | cpu_dai->capture.channels_min); |
692 | runtime->hw.channels_max = | 206 | runtime->hw.channels_max = |
693 | min(rtd->codec_dai->capture.channels_max, | 207 | min(codec_dai->capture.channels_max, |
694 | rtd->cpu_dai->capture.channels_max); | 208 | cpu_dai->capture.channels_max); |
209 | runtime->hw.formats = | ||
210 | codec_dai->capture.formats & cpu_dai->capture.formats; | ||
211 | runtime->hw.rates = | ||
212 | codec_dai->capture.rates & cpu_dai->capture.rates; | ||
695 | } | 213 | } |
696 | 214 | ||
697 | snd_pcm_limit_hw_rates(runtime); | 215 | snd_pcm_limit_hw_rates(runtime); |
698 | if (!runtime->hw.rates) { | 216 | if (!runtime->hw.rates) { |
699 | printk(KERN_ERR "asoc: %s <-> %s No matching rates\n", | 217 | printk(KERN_ERR "asoc: %s <-> %s No matching rates\n", |
700 | rtd->codec_dai->name, rtd->cpu_dai->name); | 218 | codec_dai->name, cpu_dai->name); |
701 | goto codec_dai_err; | 219 | goto machine_err; |
702 | } | 220 | } |
703 | if (!runtime->hw.formats) { | 221 | if (!runtime->hw.formats) { |
704 | printk(KERN_ERR "asoc: %s <-> %s No matching formats\n", | 222 | printk(KERN_ERR "asoc: %s <-> %s No matching formats\n", |
705 | rtd->codec_dai->name, rtd->cpu_dai->name); | 223 | codec_dai->name, cpu_dai->name); |
706 | goto codec_dai_err; | 224 | goto machine_err; |
707 | } | 225 | } |
708 | if (!runtime->hw.channels_min || !runtime->hw.channels_max) { | 226 | if (!runtime->hw.channels_min || !runtime->hw.channels_max) { |
709 | printk(KERN_ERR "asoc: %s <-> %s No matching channels\n", | 227 | printk(KERN_ERR "asoc: %s <-> %s No matching channels\n", |
710 | rtd->codec_dai->name, rtd->cpu_dai->name); | 228 | codec_dai->name, cpu_dai->name); |
711 | goto codec_dai_err; | 229 | goto machine_err; |
712 | } | 230 | } |
713 | 231 | ||
714 | dbg("asoc: %s <-> %s info:\n", rtd->codec_dai->name, rtd->cpu_dai->name); | 232 | dbg("asoc: %s <-> %s info:\n",codec_dai->name, cpu_dai->name); |
715 | dbg("asoc: rate mask 0x%x\n", runtime->hw.rates); | 233 | dbg("asoc: rate mask 0x%x\n", runtime->hw.rates); |
716 | dbg("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, | 234 | dbg("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, |
717 | runtime->hw.channels_max); | 235 | runtime->hw.channels_max); |
718 | dbg("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, | 236 | dbg("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, |
719 | runtime->hw.rate_max); | 237 | runtime->hw.rate_max); |
720 | 238 | ||
721 | |||
722 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 239 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
723 | rtd->cpu_dai->playback.active = rtd->codec_dai->playback.active = 1; | 240 | cpu_dai->playback.active = codec_dai->playback.active = 1; |
724 | else | 241 | else |
725 | rtd->cpu_dai->capture.active = rtd->codec_dai->capture.active = 1; | 242 | cpu_dai->capture.active = codec_dai->capture.active = 1; |
726 | rtd->cpu_dai->active = rtd->codec_dai->active = 1; | 243 | cpu_dai->active = codec_dai->active = 1; |
727 | rtd->cpu_dai->runtime = runtime; | 244 | cpu_dai->runtime = runtime; |
728 | socdev->codec->active++; | 245 | socdev->codec->active++; |
729 | mutex_unlock(&pcm_mutex); | 246 | mutex_unlock(&pcm_mutex); |
730 | return 0; | 247 | return 0; |
731 | 248 | ||
732 | codec_dai_err: | 249 | machine_err: |
733 | if (machine->ops && machine->ops->shutdown) | 250 | if (machine->ops && machine->ops->shutdown) |
734 | machine->ops->shutdown(substream); | 251 | machine->ops->shutdown(substream); |
735 | 252 | ||
736 | machine_err: | 253 | codec_dai_err: |
737 | if (platform->pcm_ops->close) | 254 | if (platform->pcm_ops->close) |
738 | platform->pcm_ops->close(substream); | 255 | platform->pcm_ops->close(substream); |
739 | 256 | ||
740 | platform_err: | 257 | platform_err: |
741 | if (rtd->cpu_dai->ops.shutdown) | 258 | if (cpu_dai->ops.shutdown) |
742 | rtd->cpu_dai->ops.shutdown(substream); | 259 | cpu_dai->ops.shutdown(substream); |
743 | out: | 260 | out: |
744 | mutex_unlock(&pcm_mutex); | 261 | mutex_unlock(&pcm_mutex); |
745 | return ret; | 262 | return ret; |
@@ -795,47 +312,49 @@ static int soc_codec_close(struct snd_pcm_substream *substream) | |||
795 | { | 312 | { |
796 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 313 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
797 | struct snd_soc_device *socdev = rtd->socdev; | 314 | struct snd_soc_device *socdev = rtd->socdev; |
798 | struct snd_soc_machine *machine = socdev->machine; | 315 | struct snd_soc_dai_link *machine = rtd->dai; |
799 | struct snd_soc_platform *platform = socdev->platform; | 316 | struct snd_soc_platform *platform = socdev->platform; |
317 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | ||
318 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | ||
800 | struct snd_soc_codec *codec = socdev->codec; | 319 | struct snd_soc_codec *codec = socdev->codec; |
801 | 320 | ||
802 | mutex_lock(&pcm_mutex); | 321 | mutex_lock(&pcm_mutex); |
803 | 322 | ||
804 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 323 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
805 | rtd->cpu_dai->playback.active = rtd->codec_dai->playback.active = 0; | 324 | cpu_dai->playback.active = codec_dai->playback.active = 0; |
806 | else | 325 | else |
807 | rtd->cpu_dai->capture.active = rtd->codec_dai->capture.active = 0; | 326 | cpu_dai->capture.active = codec_dai->capture.active = 0; |
808 | 327 | ||
809 | if (rtd->codec_dai->playback.active == 0 && | 328 | if (codec_dai->playback.active == 0 && |
810 | rtd->codec_dai->capture.active == 0) { | 329 | codec_dai->capture.active == 0) { |
811 | rtd->cpu_dai->active = rtd->codec_dai->active = 0; | 330 | cpu_dai->active = codec_dai->active = 0; |
812 | } | 331 | } |
813 | codec->active--; | 332 | codec->active--; |
814 | 333 | ||
815 | if (rtd->cpu_dai->ops.shutdown) | 334 | if (cpu_dai->ops.shutdown) |
816 | rtd->cpu_dai->ops.shutdown(substream); | 335 | cpu_dai->ops.shutdown(substream); |
817 | 336 | ||
818 | if (rtd->codec_dai->ops.shutdown) | 337 | if (codec_dai->ops.shutdown) |
819 | rtd->codec_dai->ops.shutdown(substream); | 338 | codec_dai->ops.shutdown(substream); |
820 | 339 | ||
821 | if (machine->ops && machine->ops->shutdown) | 340 | if (machine->ops && machine->ops->shutdown) |
822 | machine->ops->shutdown(substream); | 341 | machine->ops->shutdown(substream); |
823 | 342 | ||
824 | if (platform->pcm_ops->close) | 343 | if (platform->pcm_ops->close) |
825 | platform->pcm_ops->close(substream); | 344 | platform->pcm_ops->close(substream); |
826 | rtd->cpu_dai->runtime = NULL; | 345 | cpu_dai->runtime = NULL; |
827 | 346 | ||
828 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 347 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
829 | /* start delayed pop wq here for playback streams */ | 348 | /* start delayed pop wq here for playback streams */ |
830 | rtd->codec_dai->pop_wait = 1; | 349 | codec_dai->pop_wait = 1; |
831 | schedule_delayed_work(&socdev->delayed_work, | 350 | schedule_delayed_work(&socdev->delayed_work, |
832 | msecs_to_jiffies(pmdown_time)); | 351 | msecs_to_jiffies(pmdown_time)); |
833 | } else { | 352 | } else { |
834 | /* capture streams can be powered down now */ | 353 | /* capture streams can be powered down now */ |
835 | snd_soc_dapm_stream_event(codec, rtd->codec_dai->capture.stream_name, | 354 | snd_soc_dapm_stream_event(codec, |
836 | SND_SOC_DAPM_STREAM_STOP); | 355 | codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_STOP); |
837 | 356 | ||
838 | if (codec->active == 0 && rtd->codec_dai->pop_wait == 0){ | 357 | if (codec->active == 0 && codec_dai->pop_wait == 0){ |
839 | if (codec->dapm_event) | 358 | if (codec->dapm_event) |
840 | codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 359 | codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot); |
841 | } | 360 | } |
@@ -854,11 +373,23 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
854 | { | 373 | { |
855 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 374 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
856 | struct snd_soc_device *socdev = rtd->socdev; | 375 | struct snd_soc_device *socdev = rtd->socdev; |
376 | struct snd_soc_dai_link *machine = rtd->dai; | ||
857 | struct snd_soc_platform *platform = socdev->platform; | 377 | struct snd_soc_platform *platform = socdev->platform; |
378 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | ||
379 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | ||
858 | struct snd_soc_codec *codec = socdev->codec; | 380 | struct snd_soc_codec *codec = socdev->codec; |
859 | int ret = 0; | 381 | int ret = 0; |
860 | 382 | ||
861 | mutex_lock(&pcm_mutex); | 383 | mutex_lock(&pcm_mutex); |
384 | |||
385 | if (machine->ops && machine->ops->prepare) { | ||
386 | ret = machine->ops->prepare(substream); | ||
387 | if (ret < 0) { | ||
388 | printk(KERN_ERR "asoc: machine prepare error\n"); | ||
389 | goto out; | ||
390 | } | ||
391 | } | ||
392 | |||
862 | if (platform->pcm_ops->prepare) { | 393 | if (platform->pcm_ops->prepare) { |
863 | ret = platform->pcm_ops->prepare(substream); | 394 | ret = platform->pcm_ops->prepare(substream); |
864 | if (ret < 0) { | 395 | if (ret < 0) { |
@@ -867,30 +398,35 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
867 | } | 398 | } |
868 | } | 399 | } |
869 | 400 | ||
870 | if (rtd->codec_dai->ops.prepare) { | 401 | if (codec_dai->ops.prepare) { |
871 | ret = rtd->codec_dai->ops.prepare(substream); | 402 | ret = codec_dai->ops.prepare(substream); |
872 | if (ret < 0) { | 403 | if (ret < 0) { |
873 | printk(KERN_ERR "asoc: codec DAI prepare error\n"); | 404 | printk(KERN_ERR "asoc: codec DAI prepare error\n"); |
874 | goto out; | 405 | goto out; |
875 | } | 406 | } |
876 | } | 407 | } |
877 | 408 | ||
878 | if (rtd->cpu_dai->ops.prepare) | 409 | if (cpu_dai->ops.prepare) { |
879 | ret = rtd->cpu_dai->ops.prepare(substream); | 410 | ret = cpu_dai->ops.prepare(substream); |
411 | if (ret < 0) { | ||
412 | printk(KERN_ERR "asoc: cpu DAI prepare error\n"); | ||
413 | goto out; | ||
414 | } | ||
415 | } | ||
880 | 416 | ||
881 | /* we only want to start a DAPM playback stream if we are not waiting | 417 | /* we only want to start a DAPM playback stream if we are not waiting |
882 | * on an existing one stopping */ | 418 | * on an existing one stopping */ |
883 | if (rtd->codec_dai->pop_wait) { | 419 | if (codec_dai->pop_wait) { |
884 | /* we are waiting for the delayed work to start */ | 420 | /* we are waiting for the delayed work to start */ |
885 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | 421 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) |
886 | snd_soc_dapm_stream_event(codec, | 422 | snd_soc_dapm_stream_event(socdev->codec, |
887 | rtd->codec_dai->capture.stream_name, | 423 | codec_dai->capture.stream_name, |
888 | SND_SOC_DAPM_STREAM_START); | 424 | SND_SOC_DAPM_STREAM_START); |
889 | else { | 425 | else { |
890 | rtd->codec_dai->pop_wait = 0; | 426 | codec_dai->pop_wait = 0; |
891 | cancel_delayed_work(&socdev->delayed_work); | 427 | cancel_delayed_work(&socdev->delayed_work); |
892 | if (rtd->codec_dai->digital_mute) | 428 | if (codec_dai->dai_ops.digital_mute) |
893 | rtd->codec_dai->digital_mute(codec, rtd->codec_dai, 0); | 429 | codec_dai->dai_ops.digital_mute(codec_dai, 0); |
894 | } | 430 | } |
895 | } else { | 431 | } else { |
896 | /* no delayed work - do we need to power up codec */ | 432 | /* no delayed work - do we need to power up codec */ |
@@ -901,30 +437,30 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
901 | 437 | ||
902 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 438 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
903 | snd_soc_dapm_stream_event(codec, | 439 | snd_soc_dapm_stream_event(codec, |
904 | rtd->codec_dai->playback.stream_name, | 440 | codec_dai->playback.stream_name, |
905 | SND_SOC_DAPM_STREAM_START); | 441 | SND_SOC_DAPM_STREAM_START); |
906 | else | 442 | else |
907 | snd_soc_dapm_stream_event(codec, | 443 | snd_soc_dapm_stream_event(codec, |
908 | rtd->codec_dai->capture.stream_name, | 444 | codec_dai->capture.stream_name, |
909 | SND_SOC_DAPM_STREAM_START); | 445 | SND_SOC_DAPM_STREAM_START); |
910 | 446 | ||
911 | if (codec->dapm_event) | 447 | if (codec->dapm_event) |
912 | codec->dapm_event(codec, SNDRV_CTL_POWER_D0); | 448 | codec->dapm_event(codec, SNDRV_CTL_POWER_D0); |
913 | if (rtd->codec_dai->digital_mute) | 449 | if (codec_dai->dai_ops.digital_mute) |
914 | rtd->codec_dai->digital_mute(codec, rtd->codec_dai, 0); | 450 | codec_dai->dai_ops.digital_mute(codec_dai, 0); |
915 | 451 | ||
916 | } else { | 452 | } else { |
917 | /* codec already powered - power on widgets */ | 453 | /* codec already powered - power on widgets */ |
918 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 454 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
919 | snd_soc_dapm_stream_event(codec, | 455 | snd_soc_dapm_stream_event(codec, |
920 | rtd->codec_dai->playback.stream_name, | 456 | codec_dai->playback.stream_name, |
921 | SND_SOC_DAPM_STREAM_START); | 457 | SND_SOC_DAPM_STREAM_START); |
922 | else | 458 | else |
923 | snd_soc_dapm_stream_event(codec, | 459 | snd_soc_dapm_stream_event(codec, |
924 | rtd->codec_dai->capture.stream_name, | 460 | codec_dai->capture.stream_name, |
925 | SND_SOC_DAPM_STREAM_START); | 461 | SND_SOC_DAPM_STREAM_START); |
926 | if (rtd->codec_dai->digital_mute) | 462 | if (codec_dai->dai_ops.digital_mute) |
927 | rtd->codec_dai->digital_mute(codec, rtd->codec_dai, 0); | 463 | codec_dai->dai_ops.digital_mute(codec_dai, 0); |
928 | } | 464 | } |
929 | } | 465 | } |
930 | 466 | ||
@@ -943,39 +479,36 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
943 | { | 479 | { |
944 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 480 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
945 | struct snd_soc_device *socdev = rtd->socdev; | 481 | struct snd_soc_device *socdev = rtd->socdev; |
482 | struct snd_soc_dai_link *machine = rtd->dai; | ||
946 | struct snd_soc_platform *platform = socdev->platform; | 483 | struct snd_soc_platform *platform = socdev->platform; |
947 | struct snd_soc_machine *machine = socdev->machine; | 484 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; |
485 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | ||
948 | int ret = 0; | 486 | int ret = 0; |
949 | 487 | ||
950 | mutex_lock(&pcm_mutex); | 488 | mutex_lock(&pcm_mutex); |
951 | 489 | ||
952 | /* we don't need to match any AC97 params */ | 490 | if (machine->ops && machine->ops->hw_params) { |
953 | if (rtd->cpu_dai->type != SND_SOC_DAI_AC97) { | 491 | ret = machine->ops->hw_params(substream, params); |
954 | ret = soc_hw_match_params(substream, params); | 492 | if (ret < 0) { |
955 | if (ret < 0) | 493 | printk(KERN_ERR "asoc: machine hw_params failed\n"); |
956 | goto out; | ||
957 | } else { | ||
958 | struct snd_soc_clock_info clk_info; | ||
959 | clk_info.rate = params_rate(params); | ||
960 | ret = soc_get_mclk(rtd, &clk_info); | ||
961 | if (ret < 0) | ||
962 | goto out; | 494 | goto out; |
495 | } | ||
963 | } | 496 | } |
964 | 497 | ||
965 | if (rtd->codec_dai->ops.hw_params) { | 498 | if (codec_dai->ops.hw_params) { |
966 | ret = rtd->codec_dai->ops.hw_params(substream, params); | 499 | ret = codec_dai->ops.hw_params(substream, params); |
967 | if (ret < 0) { | 500 | if (ret < 0) { |
968 | printk(KERN_ERR "asoc: can't set codec %s hw params\n", | 501 | printk(KERN_ERR "asoc: can't set codec %s hw params\n", |
969 | rtd->codec_dai->name); | 502 | codec_dai->name); |
970 | goto out; | 503 | goto codec_err; |
971 | } | 504 | } |
972 | } | 505 | } |
973 | 506 | ||
974 | if (rtd->cpu_dai->ops.hw_params) { | 507 | if (cpu_dai->ops.hw_params) { |
975 | ret = rtd->cpu_dai->ops.hw_params(substream, params); | 508 | ret = cpu_dai->ops.hw_params(substream, params); |
976 | if (ret < 0) { | 509 | if (ret < 0) { |
977 | printk(KERN_ERR "asoc: can't set interface %s hw params\n", | 510 | printk(KERN_ERR "asoc: can't set interface %s hw params\n", |
978 | rtd->cpu_dai->name); | 511 | cpu_dai->name); |
979 | goto interface_err; | 512 | goto interface_err; |
980 | } | 513 | } |
981 | } | 514 | } |
@@ -989,29 +522,21 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
989 | } | 522 | } |
990 | } | 523 | } |
991 | 524 | ||
992 | if (machine->ops && machine->ops->hw_params) { | ||
993 | ret = machine->ops->hw_params(substream, params); | ||
994 | if (ret < 0) { | ||
995 | printk(KERN_ERR "asoc: machine hw_params failed\n"); | ||
996 | goto machine_err; | ||
997 | } | ||
998 | } | ||
999 | |||
1000 | out: | 525 | out: |
1001 | mutex_unlock(&pcm_mutex); | 526 | mutex_unlock(&pcm_mutex); |
1002 | return ret; | 527 | return ret; |
1003 | 528 | ||
1004 | machine_err: | ||
1005 | if (platform->pcm_ops->hw_free) | ||
1006 | platform->pcm_ops->hw_free(substream); | ||
1007 | |||
1008 | platform_err: | 529 | platform_err: |
1009 | if (rtd->cpu_dai->ops.hw_free) | 530 | if (cpu_dai->ops.hw_free) |
1010 | rtd->cpu_dai->ops.hw_free(substream); | 531 | cpu_dai->ops.hw_free(substream); |
1011 | 532 | ||
1012 | interface_err: | 533 | interface_err: |
1013 | if (rtd->codec_dai->ops.hw_free) | 534 | if (codec_dai->ops.hw_free) |
1014 | rtd->codec_dai->ops.hw_free(substream); | 535 | codec_dai->ops.hw_free(substream); |
536 | |||
537 | codec_err: | ||
538 | if(machine->ops && machine->ops->hw_free) | ||
539 | machine->ops->hw_free(substream); | ||
1015 | 540 | ||
1016 | mutex_unlock(&pcm_mutex); | 541 | mutex_unlock(&pcm_mutex); |
1017 | return ret; | 542 | return ret; |
@@ -1024,15 +549,17 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | |||
1024 | { | 549 | { |
1025 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 550 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
1026 | struct snd_soc_device *socdev = rtd->socdev; | 551 | struct snd_soc_device *socdev = rtd->socdev; |
552 | struct snd_soc_dai_link *machine = rtd->dai; | ||
1027 | struct snd_soc_platform *platform = socdev->platform; | 553 | struct snd_soc_platform *platform = socdev->platform; |
554 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | ||
555 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | ||
1028 | struct snd_soc_codec *codec = socdev->codec; | 556 | struct snd_soc_codec *codec = socdev->codec; |
1029 | struct snd_soc_machine *machine = socdev->machine; | ||
1030 | 557 | ||
1031 | mutex_lock(&pcm_mutex); | 558 | mutex_lock(&pcm_mutex); |
1032 | 559 | ||
1033 | /* apply codec digital mute */ | 560 | /* apply codec digital mute */ |
1034 | if (!codec->active && rtd->codec_dai->digital_mute) | 561 | if (!codec->active && codec_dai->dai_ops.digital_mute) |
1035 | rtd->codec_dai->digital_mute(codec, rtd->codec_dai, 1); | 562 | codec_dai->dai_ops.digital_mute(codec_dai, 1); |
1036 | 563 | ||
1037 | /* free any machine hw params */ | 564 | /* free any machine hw params */ |
1038 | if (machine->ops && machine->ops->hw_free) | 565 | if (machine->ops && machine->ops->hw_free) |
@@ -1043,11 +570,11 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | |||
1043 | platform->pcm_ops->hw_free(substream); | 570 | platform->pcm_ops->hw_free(substream); |
1044 | 571 | ||
1045 | /* now free hw params for the DAI's */ | 572 | /* now free hw params for the DAI's */ |
1046 | if (rtd->codec_dai->ops.hw_free) | 573 | if (codec_dai->ops.hw_free) |
1047 | rtd->codec_dai->ops.hw_free(substream); | 574 | codec_dai->ops.hw_free(substream); |
1048 | 575 | ||
1049 | if (rtd->cpu_dai->ops.hw_free) | 576 | if (cpu_dai->ops.hw_free) |
1050 | rtd->cpu_dai->ops.hw_free(substream); | 577 | cpu_dai->ops.hw_free(substream); |
1051 | 578 | ||
1052 | mutex_unlock(&pcm_mutex); | 579 | mutex_unlock(&pcm_mutex); |
1053 | return 0; | 580 | return 0; |
@@ -1057,11 +584,14 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1057 | { | 584 | { |
1058 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 585 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
1059 | struct snd_soc_device *socdev = rtd->socdev; | 586 | struct snd_soc_device *socdev = rtd->socdev; |
587 | struct snd_soc_dai_link *machine = rtd->dai; | ||
1060 | struct snd_soc_platform *platform = socdev->platform; | 588 | struct snd_soc_platform *platform = socdev->platform; |
589 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | ||
590 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | ||
1061 | int ret; | 591 | int ret; |
1062 | 592 | ||
1063 | if (rtd->codec_dai->ops.trigger) { | 593 | if (codec_dai->ops.trigger) { |
1064 | ret = rtd->codec_dai->ops.trigger(substream, cmd); | 594 | ret = codec_dai->ops.trigger(substream, cmd); |
1065 | if (ret < 0) | 595 | if (ret < 0) |
1066 | return ret; | 596 | return ret; |
1067 | } | 597 | } |
@@ -1072,8 +602,8 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1072 | return ret; | 602 | return ret; |
1073 | } | 603 | } |
1074 | 604 | ||
1075 | if (rtd->cpu_dai->ops.trigger) { | 605 | if (cpu_dai->ops.trigger) { |
1076 | ret = rtd->cpu_dai->ops.trigger(substream, cmd); | 606 | ret = cpu_dai->ops.trigger(substream, cmd); |
1077 | if (ret < 0) | 607 | if (ret < 0) |
1078 | return ret; | 608 | return ret; |
1079 | } | 609 | } |
@@ -1104,8 +634,8 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) | |||
1104 | /* mute any active DAC's */ | 634 | /* mute any active DAC's */ |
1105 | for(i = 0; i < machine->num_links; i++) { | 635 | for(i = 0; i < machine->num_links; i++) { |
1106 | struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai; | 636 | struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai; |
1107 | if (dai->digital_mute && dai->playback.active) | 637 | if (dai->dai_ops.digital_mute && dai->playback.active) |
1108 | dai->digital_mute(codec, dai, 1); | 638 | dai->dai_ops.digital_mute(dai, 1); |
1109 | } | 639 | } |
1110 | 640 | ||
1111 | if (machine->suspend_pre) | 641 | if (machine->suspend_pre) |
@@ -1185,8 +715,8 @@ static int soc_resume(struct platform_device *pdev) | |||
1185 | /* unmute any active DAC's */ | 715 | /* unmute any active DAC's */ |
1186 | for(i = 0; i < machine->num_links; i++) { | 716 | for(i = 0; i < machine->num_links; i++) { |
1187 | struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai; | 717 | struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai; |
1188 | if (dai->digital_mute && dai->playback.active) | 718 | if (dai->dai_ops.digital_mute && dai->playback.active) |
1189 | dai->digital_mute(codec, dai, 0); | 719 | dai->dai_ops.digital_mute(dai, 0); |
1190 | } | 720 | } |
1191 | 721 | ||
1192 | for(i = 0; i < machine->num_links; i++) { | 722 | for(i = 0; i < machine->num_links; i++) { |
@@ -1320,9 +850,10 @@ static int soc_new_pcm(struct snd_soc_device *socdev, | |||
1320 | rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL); | 850 | rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL); |
1321 | if (rtd == NULL) | 851 | if (rtd == NULL) |
1322 | return -ENOMEM; | 852 | return -ENOMEM; |
1323 | rtd->cpu_dai = cpu_dai; | 853 | |
1324 | rtd->codec_dai = codec_dai; | 854 | rtd->dai = dai_link; |
1325 | rtd->socdev = socdev; | 855 | rtd->socdev = socdev; |
856 | codec_dai->codec = socdev->codec; | ||
1326 | 857 | ||
1327 | /* check client and interface hw capabilities */ | 858 | /* check client and interface hw capabilities */ |
1328 | sprintf(new_name, "%s %s-%s-%d",dai_link->stream_name, codec_dai->name, | 859 | sprintf(new_name, "%s %s-%s-%d",dai_link->stream_name, codec_dai->name, |
@@ -1499,22 +1030,6 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, | |||
1499 | EXPORT_SYMBOL_GPL(snd_soc_test_bits); | 1030 | EXPORT_SYMBOL_GPL(snd_soc_test_bits); |
1500 | 1031 | ||
1501 | /** | 1032 | /** |
1502 | * snd_soc_get_rate - get int sample rate | ||
1503 | * @hwpcmrate: the hardware pcm rate | ||
1504 | * | ||
1505 | * Returns the audio rate integaer value, else 0. | ||
1506 | */ | ||
1507 | int snd_soc_get_rate(int hwpcmrate) | ||
1508 | { | ||
1509 | int rate = ffs(hwpcmrate) - 1; | ||
1510 | |||
1511 | if (rate > ARRAY_SIZE(rates)) | ||
1512 | return 0; | ||
1513 | return rates[rate]; | ||
1514 | } | ||
1515 | EXPORT_SYMBOL_GPL(snd_soc_get_rate); | ||
1516 | |||
1517 | /** | ||
1518 | * snd_soc_new_pcms - create new sound card and pcms | 1033 | * snd_soc_new_pcms - create new sound card and pcms |
1519 | * @socdev: the SoC audio device | 1034 | * @socdev: the SoC audio device |
1520 | * | 1035 | * |