mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
ASOC: dwc: Fix 16-bit audio handling
IMO the Synopsys datasheet could be clearer in this area, but it seems that the DMA data ports (DMATX and DMARX) expect left and right samples in alternate writes; if a stereo pair is pushed in a single 32-bit write, the upper half is ignored, leading to double speed audio with a confused stereo image. Make sure the necessary changes happen by updating the DMA configuration data in the hw_params method. The set_bclk_ratio change was made at a time when it looked like it could be causing an error, but I think the division of responsibilities is clearer this way (and the kernel log clearer without the info-level message). Signed-off-by: Phil Elwell <phil@raspberrypi.com>
This commit is contained in:
@@ -223,23 +223,34 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
|
|||||||
{
|
{
|
||||||
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
|
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
|
||||||
struct i2s_clk_config_data *config = &dev->config;
|
struct i2s_clk_config_data *config = &dev->config;
|
||||||
|
union dw_i2s_snd_dma_data *dma_data = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||||
|
dma_data = &dev->play_dma_data;
|
||||||
|
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
|
||||||
|
dma_data = &dev->capture_dma_data;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
|
||||||
switch (params_format(params)) {
|
switch (params_format(params)) {
|
||||||
case SNDRV_PCM_FORMAT_S16_LE:
|
case SNDRV_PCM_FORMAT_S16_LE:
|
||||||
config->data_width = 16;
|
config->data_width = 16;
|
||||||
|
dma_data->dt.addr_width = 2;
|
||||||
dev->ccr = 0x00;
|
dev->ccr = 0x00;
|
||||||
dev->xfer_resolution = 0x02;
|
dev->xfer_resolution = 0x02;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SNDRV_PCM_FORMAT_S24_LE:
|
case SNDRV_PCM_FORMAT_S24_LE:
|
||||||
config->data_width = 24;
|
config->data_width = 24;
|
||||||
|
dma_data->dt.addr_width = 4;
|
||||||
dev->ccr = 0x08;
|
dev->ccr = 0x08;
|
||||||
dev->xfer_resolution = 0x04;
|
dev->xfer_resolution = 0x04;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SNDRV_PCM_FORMAT_S32_LE:
|
case SNDRV_PCM_FORMAT_S32_LE:
|
||||||
config->data_width = 32;
|
config->data_width = 32;
|
||||||
|
dma_data->dt.addr_width = 4;
|
||||||
dev->ccr = 0x10;
|
dev->ccr = 0x10;
|
||||||
dev->xfer_resolution = 0x05;
|
dev->xfer_resolution = 0x05;
|
||||||
break;
|
break;
|
||||||
@@ -418,24 +429,21 @@ static int dw_i2s_set_bclk_ratio(struct snd_soc_dai *cpu_dai,
|
|||||||
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
|
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
|
||||||
struct i2s_clk_config_data *config = &dev->config;
|
struct i2s_clk_config_data *config = &dev->config;
|
||||||
|
|
||||||
dev_err(dev->dev, "%s(%d)\n", __func__, ratio);
|
dev_dbg(dev->dev, "%s(%d)\n", __func__, ratio);
|
||||||
|
if (ratio < config->data_width * 2)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
switch (ratio) {
|
switch (ratio) {
|
||||||
case 32:
|
case 32:
|
||||||
config->data_width = 16;
|
|
||||||
dev->ccr = 0x00;
|
dev->ccr = 0x00;
|
||||||
dev->xfer_resolution = 0x02;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 48:
|
case 48:
|
||||||
config->data_width = 24;
|
|
||||||
dev->ccr = 0x08;
|
dev->ccr = 0x08;
|
||||||
dev->xfer_resolution = 0x04;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 64:
|
case 64:
|
||||||
config->data_width = 32;
|
|
||||||
dev->ccr = 0x10;
|
dev->ccr = 0x10;
|
||||||
dev->xfer_resolution = 0x05;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|||||||
Reference in New Issue
Block a user