diff options
| -rw-r--r-- | arch/arm/mach-davinci/include/mach/asp.h | 6 | ||||
| -rw-r--r-- | sound/soc/davinci/davinci-i2s.c | 74 |
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 18e4ce34ece..019c6473341 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 d336786683b..b2a5372ef72 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 | ||
| 100 | static 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 | |||
| 106 | static 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 | |||
| 112 | static 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 | |||
| 100 | struct davinci_mcbsp_dev { | 117 | struct 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 | ||
| 110 | static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev, | 148 | static 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; |
