diff options
author | Raffaele Recalcati <raffaele.recalcati@bticino.it> | 2010-07-06 04:39:02 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-07-06 10:54:06 -0400 |
commit | a4c8ea2ddaed2f461606c2828b19786524b551ac (patch) | |
tree | 0b6b890a47554a276bbb836883f7cf1e2ab8799e | |
parent | 088fbab406e264a60fb06d3ea8d32a3e802a00b8 (diff) |
ASoC: DaVinci: Added two clocking possibilities to McBSP (I2S)
Added two clocking options for dm365 McBSP peripheral when used
with I2S timings, that are SND_SOC_DAIFMT_CBS_CFS (the cpu generates
clock and frame sync) and SND_SOC_DAIFMT_CBS_CFM (the cpu gets clock
from external pin and generates frame sync).
A slave clock management can be important when the external codec needs
the system clock and the bit clock synchronized (tested with uda1345).
This patch has been developed against the:
http://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-davinci.git
git tree and has been tested on bmx board (similar to dm365 evm, but using
uda1345 as external audio codec).
Signed-off-by: Raffaele Recalcati <raffaele.recalcati@bticino.it>
Signed-off-by: Davide Bonfanti <davide.bonfanti@bticino.it>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Acked-by: Sudhakar Rajashekhara <sudhakar.raj@ti.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r-- | sound/soc/davinci/davinci-i2s.c | 110 | ||||
-rw-r--r-- | sound/soc/davinci/davinci-i2s.h | 5 |
2 files changed, 106 insertions, 9 deletions
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index adadcd3aa1b1..c8f038cb4c5e 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <mach/asp.h> | 26 | #include <mach/asp.h> |
27 | 27 | ||
28 | #include "davinci-pcm.h" | 28 | #include "davinci-pcm.h" |
29 | #include "davinci-i2s.h" | ||
29 | 30 | ||
30 | 31 | ||
31 | /* | 32 | /* |
@@ -68,16 +69,21 @@ | |||
68 | #define DAVINCI_MCBSP_RCR_RDATDLY(v) ((v) << 16) | 69 | #define DAVINCI_MCBSP_RCR_RDATDLY(v) ((v) << 16) |
69 | #define DAVINCI_MCBSP_RCR_RFIG (1 << 18) | 70 | #define DAVINCI_MCBSP_RCR_RFIG (1 << 18) |
70 | #define DAVINCI_MCBSP_RCR_RWDLEN2(v) ((v) << 21) | 71 | #define DAVINCI_MCBSP_RCR_RWDLEN2(v) ((v) << 21) |
72 | #define DAVINCI_MCBSP_RCR_RFRLEN2(v) ((v) << 24) | ||
73 | #define DAVINCI_MCBSP_RCR_RPHASE BIT(31) | ||
71 | 74 | ||
72 | #define DAVINCI_MCBSP_XCR_XWDLEN1(v) ((v) << 5) | 75 | #define DAVINCI_MCBSP_XCR_XWDLEN1(v) ((v) << 5) |
73 | #define DAVINCI_MCBSP_XCR_XFRLEN1(v) ((v) << 8) | 76 | #define DAVINCI_MCBSP_XCR_XFRLEN1(v) ((v) << 8) |
74 | #define DAVINCI_MCBSP_XCR_XDATDLY(v) ((v) << 16) | 77 | #define DAVINCI_MCBSP_XCR_XDATDLY(v) ((v) << 16) |
75 | #define DAVINCI_MCBSP_XCR_XFIG (1 << 18) | 78 | #define DAVINCI_MCBSP_XCR_XFIG (1 << 18) |
76 | #define DAVINCI_MCBSP_XCR_XWDLEN2(v) ((v) << 21) | 79 | #define DAVINCI_MCBSP_XCR_XWDLEN2(v) ((v) << 21) |
80 | #define DAVINCI_MCBSP_XCR_XFRLEN2(v) ((v) << 24) | ||
81 | #define DAVINCI_MCBSP_XCR_XPHASE BIT(31) | ||
77 | 82 | ||
78 | #define DAVINCI_MCBSP_SRGR_FWID(v) ((v) << 8) | 83 | #define DAVINCI_MCBSP_SRGR_FWID(v) ((v) << 8) |
79 | #define DAVINCI_MCBSP_SRGR_FPER(v) ((v) << 16) | 84 | #define DAVINCI_MCBSP_SRGR_FPER(v) ((v) << 16) |
80 | #define DAVINCI_MCBSP_SRGR_FSGM (1 << 28) | 85 | #define DAVINCI_MCBSP_SRGR_FSGM (1 << 28) |
86 | #define DAVINCI_MCBSP_SRGR_CLKSM BIT(29) | ||
81 | 87 | ||
82 | #define DAVINCI_MCBSP_PCR_CLKRP (1 << 0) | 88 | #define DAVINCI_MCBSP_PCR_CLKRP (1 << 0) |
83 | #define DAVINCI_MCBSP_PCR_CLKXP (1 << 1) | 89 | #define DAVINCI_MCBSP_PCR_CLKXP (1 << 1) |
@@ -144,6 +150,9 @@ struct davinci_mcbsp_dev { | |||
144 | * won't end up being swapped because of the underrun. | 150 | * won't end up being swapped because of the underrun. |
145 | */ | 151 | */ |
146 | unsigned enable_channel_combine:1; | 152 | unsigned enable_channel_combine:1; |
153 | |||
154 | unsigned int fmt; | ||
155 | int clk_div; | ||
147 | }; | 156 | }; |
148 | 157 | ||
149 | static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev, | 158 | static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev, |
@@ -254,10 +263,12 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
254 | struct davinci_mcbsp_dev *dev = cpu_dai->private_data; | 263 | struct davinci_mcbsp_dev *dev = cpu_dai->private_data; |
255 | unsigned int pcr; | 264 | unsigned int pcr; |
256 | unsigned int srgr; | 265 | unsigned int srgr; |
266 | /* Attention srgr is updated by hw_params! */ | ||
257 | srgr = DAVINCI_MCBSP_SRGR_FSGM | | 267 | srgr = DAVINCI_MCBSP_SRGR_FSGM | |
258 | DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) | | 268 | DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) | |
259 | DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1); | 269 | DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1); |
260 | 270 | ||
271 | dev->fmt = fmt; | ||
261 | /* set master/slave audio interface */ | 272 | /* set master/slave audio interface */ |
262 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 273 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
263 | case SND_SOC_DAIFMT_CBS_CFS: | 274 | case SND_SOC_DAIFMT_CBS_CFS: |
@@ -372,6 +383,18 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
372 | return 0; | 383 | return 0; |
373 | } | 384 | } |
374 | 385 | ||
386 | static int davinci_i2s_dai_set_clkdiv(struct snd_soc_dai *cpu_dai, | ||
387 | int div_id, int div) | ||
388 | { | ||
389 | struct davinci_mcbsp_dev *dev = cpu_dai->private_data; | ||
390 | |||
391 | if (div_id != DAVINCI_MCBSP_CLKGDV) | ||
392 | return -ENODEV; | ||
393 | |||
394 | dev->clk_div = div; | ||
395 | return 0; | ||
396 | } | ||
397 | |||
375 | static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, | 398 | static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, |
376 | struct snd_pcm_hw_params *params, | 399 | struct snd_pcm_hw_params *params, |
377 | struct snd_soc_dai *dai) | 400 | struct snd_soc_dai *dai) |
@@ -380,8 +403,8 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, | |||
380 | struct davinci_pcm_dma_params *dma_params = | 403 | struct davinci_pcm_dma_params *dma_params = |
381 | &dev->dma_params[substream->stream]; | 404 | &dev->dma_params[substream->stream]; |
382 | struct snd_interval *i = NULL; | 405 | struct snd_interval *i = NULL; |
383 | int mcbsp_word_length; | 406 | int mcbsp_word_length, master; |
384 | unsigned int rcr, xcr, srgr; | 407 | unsigned int rcr, xcr, srgr, clk_div, freq, framesize; |
385 | u32 spcr; | 408 | u32 spcr; |
386 | snd_pcm_format_t fmt; | 409 | snd_pcm_format_t fmt; |
387 | unsigned element_cnt = 1; | 410 | unsigned element_cnt = 1; |
@@ -396,12 +419,47 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, | |||
396 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); | 419 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); |
397 | } | 420 | } |
398 | 421 | ||
399 | i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); | 422 | master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK; |
400 | srgr = DAVINCI_MCBSP_SRGR_FSGM; | 423 | fmt = params_format(params); |
401 | srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1); | 424 | mcbsp_word_length = asp_word_length[fmt]; |
402 | 425 | ||
403 | i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS); | 426 | switch (master) { |
404 | srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1); | 427 | case SND_SOC_DAIFMT_CBS_CFS: |
428 | freq = clk_get_rate(dev->clk); | ||
429 | srgr = DAVINCI_MCBSP_SRGR_FSGM | | ||
430 | DAVINCI_MCBSP_SRGR_CLKSM; | ||
431 | srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * | ||
432 | 8 - 1); | ||
433 | /* symmetric waveforms */ | ||
434 | clk_div = freq / (mcbsp_word_length * 16) / | ||
435 | params->rate_num * params->rate_den; | ||
436 | srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length * | ||
437 | 16 - 1); | ||
438 | clk_div &= 0xFF; | ||
439 | srgr |= clk_div; | ||
440 | break; | ||
441 | case SND_SOC_DAIFMT_CBM_CFS: | ||
442 | srgr = DAVINCI_MCBSP_SRGR_FSGM; | ||
443 | clk_div = dev->clk_div - 1; | ||
444 | srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 8 - 1); | ||
445 | srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length * 16 - 1); | ||
446 | clk_div &= 0xFF; | ||
447 | srgr |= clk_div; | ||
448 | break; | ||
449 | case SND_SOC_DAIFMT_CBM_CFM: | ||
450 | /* Clock and frame sync given from external sources */ | ||
451 | i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); | ||
452 | srgr = DAVINCI_MCBSP_SRGR_FSGM; | ||
453 | srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1); | ||
454 | pr_debug("%s - %d FWID set: re-read srgr = %X\n", | ||
455 | __func__, __LINE__, snd_interval_value(i) - 1); | ||
456 | |||
457 | i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS); | ||
458 | srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1); | ||
459 | break; | ||
460 | default: | ||
461 | return -EINVAL; | ||
462 | } | ||
405 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); | 463 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); |
406 | 464 | ||
407 | rcr = DAVINCI_MCBSP_RCR_RFIG; | 465 | rcr = DAVINCI_MCBSP_RCR_RFIG; |
@@ -426,12 +484,41 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, | |||
426 | element_cnt = 1; | 484 | element_cnt = 1; |
427 | fmt = double_fmt[fmt]; | 485 | fmt = double_fmt[fmt]; |
428 | } | 486 | } |
487 | switch (master) { | ||
488 | case SND_SOC_DAIFMT_CBS_CFS: | ||
489 | case SND_SOC_DAIFMT_CBS_CFM: | ||
490 | rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(0); | ||
491 | xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(0); | ||
492 | rcr |= DAVINCI_MCBSP_RCR_RPHASE; | ||
493 | xcr |= DAVINCI_MCBSP_XCR_XPHASE; | ||
494 | break; | ||
495 | case SND_SOC_DAIFMT_CBM_CFM: | ||
496 | case SND_SOC_DAIFMT_CBM_CFS: | ||
497 | rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(element_cnt - 1); | ||
498 | xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(element_cnt - 1); | ||
499 | break; | ||
500 | default: | ||
501 | return -EINVAL; | ||
502 | } | ||
429 | } | 503 | } |
430 | dma_params->acnt = dma_params->data_type = data_type[fmt]; | 504 | dma_params->acnt = dma_params->data_type = data_type[fmt]; |
431 | dma_params->fifo_level = 0; | 505 | dma_params->fifo_level = 0; |
432 | mcbsp_word_length = asp_word_length[fmt]; | 506 | mcbsp_word_length = asp_word_length[fmt]; |
433 | rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1); | 507 | |
434 | xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1); | 508 | switch (master) { |
509 | case SND_SOC_DAIFMT_CBS_CFS: | ||
510 | case SND_SOC_DAIFMT_CBS_CFM: | ||
511 | rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(0); | ||
512 | xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(0); | ||
513 | break; | ||
514 | case SND_SOC_DAIFMT_CBM_CFM: | ||
515 | case SND_SOC_DAIFMT_CBM_CFS: | ||
516 | rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1); | ||
517 | xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1); | ||
518 | break; | ||
519 | default: | ||
520 | return -EINVAL; | ||
521 | } | ||
435 | 522 | ||
436 | rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | | 523 | rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | |
437 | DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length); | 524 | DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length); |
@@ -442,6 +529,10 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, | |||
442 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr); | 529 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr); |
443 | else | 530 | else |
444 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr); | 531 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr); |
532 | |||
533 | pr_debug("%s - %d srgr=%X\n", __func__, __LINE__, srgr); | ||
534 | pr_debug("%s - %d xcr=%X\n", __func__, __LINE__, xcr); | ||
535 | pr_debug("%s - %d rcr=%X\n", __func__, __LINE__, rcr); | ||
445 | return 0; | 536 | return 0; |
446 | } | 537 | } |
447 | 538 | ||
@@ -500,6 +591,7 @@ static struct snd_soc_dai_ops davinci_i2s_dai_ops = { | |||
500 | .trigger = davinci_i2s_trigger, | 591 | .trigger = davinci_i2s_trigger, |
501 | .hw_params = davinci_i2s_hw_params, | 592 | .hw_params = davinci_i2s_hw_params, |
502 | .set_fmt = davinci_i2s_set_dai_fmt, | 593 | .set_fmt = davinci_i2s_set_dai_fmt, |
594 | .set_clkdiv = davinci_i2s_dai_set_clkdiv, | ||
503 | 595 | ||
504 | }; | 596 | }; |
505 | 597 | ||
diff --git a/sound/soc/davinci/davinci-i2s.h b/sound/soc/davinci/davinci-i2s.h index 241648ce8873..0b1e77b8c279 100644 --- a/sound/soc/davinci/davinci-i2s.h +++ b/sound/soc/davinci/davinci-i2s.h | |||
@@ -12,6 +12,11 @@ | |||
12 | #ifndef _DAVINCI_I2S_H | 12 | #ifndef _DAVINCI_I2S_H |
13 | #define _DAVINCI_I2S_H | 13 | #define _DAVINCI_I2S_H |
14 | 14 | ||
15 | /* McBSP dividers */ | ||
16 | enum davinci_mcbsp_div { | ||
17 | DAVINCI_MCBSP_CLKGDV, /* Sample rate generator divider */ | ||
18 | }; | ||
19 | |||
15 | extern struct snd_soc_dai davinci_i2s_dai; | 20 | extern struct snd_soc_dai davinci_i2s_dai; |
16 | 21 | ||
17 | #endif | 22 | #endif |