aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-davinci/include/mach/asp.h6
-rw-r--r--sound/soc/davinci/davinci-i2s.c74
2 files changed, 61 insertions, 19 deletions
diff --git a/arch/arm/mach-davinci/include/mach/asp.h b/arch/arm/mach-davinci/include/mach/asp.h
index 18e4ce34ece6..019c64733417 100644
--- a/arch/arm/mach-davinci/include/mach/asp.h
+++ b/arch/arm/mach-davinci/include/mach/asp.h
@@ -51,6 +51,12 @@ struct snd_platform_data {
51 u32 rx_dma_offset; 51 u32 rx_dma_offset;
52 enum dma_event_q eventq_no; /* event queue number */ 52 enum dma_event_q eventq_no; /* event queue number */
53 unsigned int codec_fmt; 53 unsigned int codec_fmt;
54 /*
55 * Allowing this is more efficient and eliminates left and right swaps
56 * caused by underruns, but will swap the left and right channels
57 * when compared to previous behavior.
58 */
59 unsigned enable_channel_combine:1;
54 60
55 /* McASP specific fields */ 61 /* McASP specific fields */
56 int tdm_slots; 62 int tdm_slots;
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index d336786683b4..b2a5372ef72c 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -97,6 +97,23 @@ enum {
97 DAVINCI_MCBSP_WORD_32, 97 DAVINCI_MCBSP_WORD_32,
98}; 98};
99 99
100static const unsigned char data_type[SNDRV_PCM_FORMAT_S32_LE + 1] = {
101 [SNDRV_PCM_FORMAT_S8] = 1,
102 [SNDRV_PCM_FORMAT_S16_LE] = 2,
103 [SNDRV_PCM_FORMAT_S32_LE] = 4,
104};
105
106static const unsigned char asp_word_length[SNDRV_PCM_FORMAT_S32_LE + 1] = {
107 [SNDRV_PCM_FORMAT_S8] = DAVINCI_MCBSP_WORD_8,
108 [SNDRV_PCM_FORMAT_S16_LE] = DAVINCI_MCBSP_WORD_16,
109 [SNDRV_PCM_FORMAT_S32_LE] = DAVINCI_MCBSP_WORD_32,
110};
111
112static const unsigned char double_fmt[SNDRV_PCM_FORMAT_S32_LE + 1] = {
113 [SNDRV_PCM_FORMAT_S8] = SNDRV_PCM_FORMAT_S16_LE,
114 [SNDRV_PCM_FORMAT_S16_LE] = SNDRV_PCM_FORMAT_S32_LE,
115};
116
100struct davinci_mcbsp_dev { 117struct davinci_mcbsp_dev {
101 struct davinci_pcm_dma_params dma_params[2]; 118 struct davinci_pcm_dma_params dma_params[2];
102 void __iomem *base; 119 void __iomem *base;
@@ -105,6 +122,27 @@ struct davinci_mcbsp_dev {
105 int mode; 122 int mode;
106 u32 pcr; 123 u32 pcr;
107 struct clk *clk; 124 struct clk *clk;
125 /*
126 * Combining both channels into 1 element will at least double the
127 * amount of time between servicing the dma channel, increase
128 * effiency, and reduce the chance of overrun/underrun. But,
129 * it will result in the left & right channels being swapped.
130 *
131 * If relabeling the left and right channels is not possible,
132 * you may want to let the codec know to swap them back.
133 *
134 * It may allow x10 the amount of time to service dma requests,
135 * if the codec is master and is using an unnecessarily fast bit clock
136 * (ie. tlvaic23b), independent of the sample rate. So, having an
137 * entire frame at once means it can be serviced at the sample rate
138 * instead of the bit clock rate.
139 *
140 * In the now unlikely case that an underrun still
141 * occurs, both the left and right samples will be repeated
142 * so that no pops are heard, and the left and right channels
143 * won't end up being swapped because of the underrun.
144 */
145 unsigned enable_channel_combine:1;
108}; 146};
109 147
110static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev, 148static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev,
@@ -344,6 +382,8 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
344 int mcbsp_word_length; 382 int mcbsp_word_length;
345 unsigned int rcr, xcr, srgr; 383 unsigned int rcr, xcr, srgr;
346 u32 spcr; 384 u32 spcr;
385 snd_pcm_format_t fmt;
386 unsigned element_cnt = 1;
347 387
348 /* general line settings */ 388 /* general line settings */
349 spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); 389 spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
@@ -373,29 +413,24 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
373 xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1); 413 xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1);
374 } 414 }
375 /* Determine xfer data type */ 415 /* Determine xfer data type */
376 switch (params_format(params)) { 416 fmt = params_format(params);
377 case SNDRV_PCM_FORMAT_S8: 417 if ((fmt > SNDRV_PCM_FORMAT_S32_LE) || !data_type[fmt]) {
378 dma_params->data_type = 1;
379 mcbsp_word_length = DAVINCI_MCBSP_WORD_8;
380 break;
381 case SNDRV_PCM_FORMAT_S16_LE:
382 dma_params->data_type = 2;
383 mcbsp_word_length = DAVINCI_MCBSP_WORD_16;
384 break;
385 case SNDRV_PCM_FORMAT_S32_LE:
386 dma_params->data_type = 4;
387 mcbsp_word_length = DAVINCI_MCBSP_WORD_32;
388 break;
389 default:
390 printk(KERN_WARNING "davinci-i2s: unsupported PCM format\n"); 418 printk(KERN_WARNING "davinci-i2s: unsupported PCM format\n");
391 return -EINVAL; 419 return -EINVAL;
392 } 420 }
393 421
394 dma_params->acnt = dma_params->data_type; 422 if (params_channels(params) == 2) {
423 element_cnt = 2;
424 if (double_fmt[fmt] && dev->enable_channel_combine) {
425 element_cnt = 1;
426 fmt = double_fmt[fmt];
427 }
428 }
429 dma_params->acnt = dma_params->data_type = data_type[fmt];
395 dma_params->fifo_level = 0; 430 dma_params->fifo_level = 0;
396 431 mcbsp_word_length = asp_word_length[fmt];
397 rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(1); 432 rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1);
398 xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(1); 433 xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1);
399 434
400 rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | 435 rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) |
401 DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length); 436 DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length);
@@ -510,7 +545,8 @@ static int davinci_i2s_probe(struct platform_device *pdev)
510 ret = -ENOMEM; 545 ret = -ENOMEM;
511 goto err_release_region; 546 goto err_release_region;
512 } 547 }
513 548 if (pdata)
549 dev->enable_channel_combine = pdata->enable_channel_combine;
514 dev->clk = clk_get(&pdev->dev, NULL); 550 dev->clk = clk_get(&pdev->dev, NULL);
515 if (IS_ERR(dev->clk)) { 551 if (IS_ERR(dev->clk)) {
516 ret = -ENODEV; 552 ret = -ENODEV;