aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/davinci/davinci-i2s.c
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
commitada47b5fe13d89735805b566185f4885f5a3f750 (patch)
tree644b88f8a71896307d71438e9b3af49126ffb22b /sound/soc/davinci/davinci-i2s.c
parent43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff)
parent3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff)
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'sound/soc/davinci/davinci-i2s.c')
-rw-r--r--sound/soc/davinci/davinci-i2s.c87
1 files changed, 64 insertions, 23 deletions
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index 4ae707048021..adadcd3aa1b1 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -12,6 +12,7 @@
12#include <linux/init.h> 12#include <linux/init.h>
13#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/device.h> 14#include <linux/device.h>
15#include <linux/slab.h>
15#include <linux/delay.h> 16#include <linux/delay.h>
16#include <linux/io.h> 17#include <linux/io.h>
17#include <linux/clk.h> 18#include <linux/clk.h>
@@ -97,12 +98,24 @@ enum {
97 DAVINCI_MCBSP_WORD_32, 98 DAVINCI_MCBSP_WORD_32,
98}; 99};
99 100
101static const unsigned char data_type[SNDRV_PCM_FORMAT_S32_LE + 1] = {
102 [SNDRV_PCM_FORMAT_S8] = 1,
103 [SNDRV_PCM_FORMAT_S16_LE] = 2,
104 [SNDRV_PCM_FORMAT_S32_LE] = 4,
105};
106
107static const unsigned char asp_word_length[SNDRV_PCM_FORMAT_S32_LE + 1] = {
108 [SNDRV_PCM_FORMAT_S8] = DAVINCI_MCBSP_WORD_8,
109 [SNDRV_PCM_FORMAT_S16_LE] = DAVINCI_MCBSP_WORD_16,
110 [SNDRV_PCM_FORMAT_S32_LE] = DAVINCI_MCBSP_WORD_32,
111};
112
113static const unsigned char double_fmt[SNDRV_PCM_FORMAT_S32_LE + 1] = {
114 [SNDRV_PCM_FORMAT_S8] = SNDRV_PCM_FORMAT_S16_LE,
115 [SNDRV_PCM_FORMAT_S16_LE] = SNDRV_PCM_FORMAT_S32_LE,
116};
117
100struct davinci_mcbsp_dev { 118struct davinci_mcbsp_dev {
101 /*
102 * dma_params must be first because rtd->dai->cpu_dai->private_data
103 * is cast to a pointer of an array of struct davinci_pcm_dma_params in
104 * davinci_pcm_open.
105 */
106 struct davinci_pcm_dma_params dma_params[2]; 119 struct davinci_pcm_dma_params dma_params[2];
107 void __iomem *base; 120 void __iomem *base;
108#define MOD_DSP_A 0 121#define MOD_DSP_A 0
@@ -110,6 +123,27 @@ struct davinci_mcbsp_dev {
110 int mode; 123 int mode;
111 u32 pcr; 124 u32 pcr;
112 struct clk *clk; 125 struct clk *clk;
126 /*
127 * Combining both channels into 1 element will at least double the
128 * amount of time between servicing the dma channel, increase
129 * effiency, and reduce the chance of overrun/underrun. But,
130 * it will result in the left & right channels being swapped.
131 *
132 * If relabeling the left and right channels is not possible,
133 * you may want to let the codec know to swap them back.
134 *
135 * It may allow x10 the amount of time to service dma requests,
136 * if the codec is master and is using an unnecessarily fast bit clock
137 * (ie. tlvaic23b), independent of the sample rate. So, having an
138 * entire frame at once means it can be serviced at the sample rate
139 * instead of the bit clock rate.
140 *
141 * In the now unlikely case that an underrun still
142 * occurs, both the left and right samples will be repeated
143 * so that no pops are heard, and the left and right channels
144 * won't end up being swapped because of the underrun.
145 */
146 unsigned enable_channel_combine:1;
113}; 147};
114 148
115static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev, 149static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev,
@@ -349,6 +383,8 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
349 int mcbsp_word_length; 383 int mcbsp_word_length;
350 unsigned int rcr, xcr, srgr; 384 unsigned int rcr, xcr, srgr;
351 u32 spcr; 385 u32 spcr;
386 snd_pcm_format_t fmt;
387 unsigned element_cnt = 1;
352 388
353 /* general line settings */ 389 /* general line settings */
354 spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); 390 spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
@@ -378,27 +414,24 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
378 xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1); 414 xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1);
379 } 415 }
380 /* Determine xfer data type */ 416 /* Determine xfer data type */
381 switch (params_format(params)) { 417 fmt = params_format(params);
382 case SNDRV_PCM_FORMAT_S8: 418 if ((fmt > SNDRV_PCM_FORMAT_S32_LE) || !data_type[fmt]) {
383 dma_params->data_type = 1;
384 mcbsp_word_length = DAVINCI_MCBSP_WORD_8;
385 break;
386 case SNDRV_PCM_FORMAT_S16_LE:
387 dma_params->data_type = 2;
388 mcbsp_word_length = DAVINCI_MCBSP_WORD_16;
389 break;
390 case SNDRV_PCM_FORMAT_S32_LE:
391 dma_params->data_type = 4;
392 mcbsp_word_length = DAVINCI_MCBSP_WORD_32;
393 break;
394 default:
395 printk(KERN_WARNING "davinci-i2s: unsupported PCM format\n"); 419 printk(KERN_WARNING "davinci-i2s: unsupported PCM format\n");
396 return -EINVAL; 420 return -EINVAL;
397 } 421 }
398 422
399 dma_params->acnt = dma_params->data_type; 423 if (params_channels(params) == 2) {
400 rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(1); 424 element_cnt = 2;
401 xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(1); 425 if (double_fmt[fmt] && dev->enable_channel_combine) {
426 element_cnt = 1;
427 fmt = double_fmt[fmt];
428 }
429 }
430 dma_params->acnt = dma_params->data_type = data_type[fmt];
431 dma_params->fifo_level = 0;
432 mcbsp_word_length = asp_word_length[fmt];
433 rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1);
434 xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1);
402 435
403 rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | 436 rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) |
404 DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length); 437 DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length);
@@ -513,7 +546,13 @@ static int davinci_i2s_probe(struct platform_device *pdev)
513 ret = -ENOMEM; 546 ret = -ENOMEM;
514 goto err_release_region; 547 goto err_release_region;
515 } 548 }
516 549 if (pdata) {
550 dev->enable_channel_combine = pdata->enable_channel_combine;
551 dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].sram_size =
552 pdata->sram_size_playback;
553 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].sram_size =
554 pdata->sram_size_capture;
555 }
517 dev->clk = clk_get(&pdev->dev, NULL); 556 dev->clk = clk_get(&pdev->dev, NULL);
518 if (IS_ERR(dev->clk)) { 557 if (IS_ERR(dev->clk)) {
519 ret = -ENODEV; 558 ret = -ENODEV;
@@ -547,6 +586,8 @@ static int davinci_i2s_probe(struct platform_device *pdev)
547 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start; 586 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start;
548 587
549 davinci_i2s_dai.private_data = dev; 588 davinci_i2s_dai.private_data = dev;
589 davinci_i2s_dai.capture.dma_data = dev->dma_params;
590 davinci_i2s_dai.playback.dma_data = dev->dma_params;
550 ret = snd_soc_register_dai(&davinci_i2s_dai); 591 ret = snd_soc_register_dai(&davinci_i2s_dai);
551 if (ret != 0) 592 if (ret != 0)
552 goto err_free_mem; 593 goto err_free_mem;