ASoC: dwc: reconfigure dwc in 'resume' from 'suspend'

DWC IP can be powered off during system suspend in some platforms.
After system is resumed, dwc needs to be programmed again to continue
audio use case.

Signed-off-by: Maruthi Bayyavarapu <maruthi.bayyavarapu@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Maruthi Srinivas Bayyavarapu 2015-12-04 18:40:33 -05:00 коммит произвёл Mark Brown
Родитель e164835a02
Коммит 0032e9dbc5
1 изменённых файлов: 43 добавлений и 27 удалений

Просмотреть файл

@ -98,6 +98,8 @@ struct dw_i2s_dev {
unsigned int i2s_reg_comp1; unsigned int i2s_reg_comp1;
unsigned int i2s_reg_comp2; unsigned int i2s_reg_comp2;
struct device *dev; struct device *dev;
u32 ccr;
u32 xfer_resolution;
/* data related to DMA transfers b/w i2s and DMAC */ /* data related to DMA transfers b/w i2s and DMAC */
union dw_i2s_snd_dma_data play_dma_data; union dw_i2s_snd_dma_data play_dma_data;
@ -217,31 +219,58 @@ static int dw_i2s_startup(struct snd_pcm_substream *substream,
return 0; return 0;
} }
static void dw_i2s_config(struct dw_i2s_dev *dev, int stream)
{
u32 ch_reg, irq;
struct i2s_clk_config_data *config = &dev->config;
i2s_disable_channels(dev, stream);
for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) {
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
i2s_write_reg(dev->i2s_base, TCR(ch_reg),
dev->xfer_resolution);
i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02);
irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30);
i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
} else {
i2s_write_reg(dev->i2s_base, RCR(ch_reg),
dev->xfer_resolution);
i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07);
irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03);
i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
}
}
}
static int dw_i2s_hw_params(struct snd_pcm_substream *substream, static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{ {
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;
u32 ccr, xfer_resolution, ch_reg, irq;
int ret; int ret;
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;
ccr = 0x00; dev->ccr = 0x00;
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;
ccr = 0x08; dev->ccr = 0x08;
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;
ccr = 0x10; dev->ccr = 0x10;
xfer_resolution = 0x05; dev->xfer_resolution = 0x05;
break; break;
default: default:
@ -262,27 +291,9 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
return -EINVAL; return -EINVAL;
} }
i2s_disable_channels(dev, substream->stream); dw_i2s_config(dev, substream->stream);
for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) { i2s_write_reg(dev->i2s_base, CCR, dev->ccr);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
i2s_write_reg(dev->i2s_base, TCR(ch_reg),
xfer_resolution);
i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02);
irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30);
i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
} else {
i2s_write_reg(dev->i2s_base, RCR(ch_reg),
xfer_resolution);
i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07);
irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03);
i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
}
}
i2s_write_reg(dev->i2s_base, CCR, ccr);
config->sample_rate = params_rate(params); config->sample_rate = params_rate(params);
@ -431,6 +442,11 @@ static int dw_i2s_resume(struct snd_soc_dai *dai)
if (dev->capability & DW_I2S_MASTER) if (dev->capability & DW_I2S_MASTER)
clk_enable(dev->clk); clk_enable(dev->clk);
if (dai->playback_active)
dw_i2s_config(dev, SNDRV_PCM_STREAM_PLAYBACK);
if (dai->capture_active)
dw_i2s_config(dev, SNDRV_PCM_STREAM_CAPTURE);
return 0; return 0;
} }