From: Maruthi Srinivas Bayyavarapu <maruthi.bayyavar...@amd.com>

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 at amd.com>
Reviewed-by: Alex Deucher <alexander.deucher at amd.com>
Signed-off-by: Alex Deucher <alexander.deucher at amd.com>
---
 sound/soc/dwc/designware_i2s.c | 70 ++++++++++++++++++++++++++----------------
 1 file changed, 43 insertions(+), 27 deletions(-)

diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c
index 940c881..825a1f4 100644
--- a/sound/soc/dwc/designware_i2s.c
+++ b/sound/soc/dwc/designware_i2s.c
@@ -98,6 +98,8 @@ struct dw_i2s_dev {
        unsigned int i2s_reg_comp1;
        unsigned int i2s_reg_comp2;
        struct device *dev;
+       u32 ccr;
+       u32 xfer_resolution;

        /* data related to DMA transfers b/w i2s and DMAC */
        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;
 }

+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,
                struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
        struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
        struct i2s_clk_config_data *config = &dev->config;
-       u32 ccr, xfer_resolution, ch_reg, irq;
        int ret;

        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
                config->data_width = 16;
-               ccr = 0x00;
-               xfer_resolution = 0x02;
+               dev->ccr = 0x00;
+               dev->xfer_resolution = 0x02;
                break;

        case SNDRV_PCM_FORMAT_S24_LE:
                config->data_width = 24;
-               ccr = 0x08;
-               xfer_resolution = 0x04;
+               dev->ccr = 0x08;
+               dev->xfer_resolution = 0x04;
                break;

        case SNDRV_PCM_FORMAT_S32_LE:
                config->data_width = 32;
-               ccr = 0x10;
-               xfer_resolution = 0x05;
+               dev->ccr = 0x10;
+               dev->xfer_resolution = 0x05;
                break;

        default:
@@ -262,27 +291,9 @@ static int dw_i2s_hw_params(struct snd_pcm_substream 
*substream,
                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++) {
-               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);
+       i2s_write_reg(dev->i2s_base, CCR, dev->ccr);

        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)
                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;
 }

-- 
1.8.3.1

Reply via email to