]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blobdiff - sound/soc/tegra/tegra30_i2s.c
ASoC: tegra: disable rx_fifo after disable stream
[mirror_ubuntu-hirsute-kernel.git] / sound / soc / tegra / tegra30_i2s.c
index e6d548fa980b68e834d000e422fcd9beb5853417..dbed3c5408e76963cdc4770dbde1b96c8107b65c 100644 (file)
@@ -127,7 +127,7 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
        struct device *dev = dai->dev;
        struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        unsigned int mask, val, reg;
-       int ret, sample_size, srate, i2sclock, bitcnt;
+       int ret, sample_size, srate, i2sclock, bitcnt, audio_bits;
        struct tegra30_ahub_cif_conf cif_conf;
 
        if (params_channels(params) != 2)
@@ -137,8 +137,19 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
                val = TEGRA30_I2S_CTRL_BIT_SIZE_16;
+               audio_bits = TEGRA30_AUDIOCIF_BITS_16;
                sample_size = 16;
                break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               val = TEGRA30_I2S_CTRL_BIT_SIZE_24;
+               audio_bits = TEGRA30_AUDIOCIF_BITS_24;
+               sample_size = 24;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               val = TEGRA30_I2S_CTRL_BIT_SIZE_32;
+               audio_bits = TEGRA30_AUDIOCIF_BITS_32;
+               sample_size = 32;
+               break;
        default:
                return -EINVAL;
        }
@@ -170,8 +181,8 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
        cif_conf.threshold = 0;
        cif_conf.audio_channels = 2;
        cif_conf.client_channels = 2;
-       cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16;
-       cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16;
+       cif_conf.audio_bits = audio_bits;
+       cif_conf.client_bits = audio_bits;
        cif_conf.expand = 0;
        cif_conf.stereo_conv = 0;
        cif_conf.replicate = 0;
@@ -220,9 +231,9 @@ static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s)
 
 static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s)
 {
-       tegra30_ahub_disable_rx_fifo(i2s->capture_fifo_cif);
        regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL,
                           TEGRA30_I2S_CTRL_XFER_EN_RX, 0);
+       tegra30_ahub_disable_rx_fifo(i2s->capture_fifo_cif);
 }
 
 static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -254,6 +265,34 @@ static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
        return 0;
 }
 
+static int tegra30_i2s_set_tdm(struct snd_soc_dai *dai,
+                              unsigned int tx_mask, unsigned int rx_mask,
+                              int slots, int slot_width)
+{
+       struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+       unsigned int mask, val;
+
+       dev_dbg(dai->dev, "%s: txmask=0x%08x rxmask=0x%08x slots=%d width=%d\n",
+                __func__, tx_mask, rx_mask, slots, slot_width);
+
+       mask = TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK |
+              TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_MASK |
+              TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_MASK;
+
+       val = (tx_mask << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT) |
+             (rx_mask << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT) |
+             ((slots - 1) << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT);
+
+       pm_runtime_get_sync(dai->dev);
+       regmap_update_bits(i2s->regmap, TEGRA30_I2S_SLOT_CTRL, mask, val);
+       /* set the fsync width to minimum of 1 clock width */
+       regmap_update_bits(i2s->regmap, TEGRA30_I2S_CH_CTRL,
+                          TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK, 0x0);
+       pm_runtime_put(dai->dev);
+
+       return 0;
+}
+
 static int tegra30_i2s_probe(struct snd_soc_dai *dai)
 {
        struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
@@ -268,6 +307,7 @@ static const struct snd_soc_dai_ops tegra30_i2s_dai_ops = {
        .set_fmt        = tegra30_i2s_set_fmt,
        .hw_params      = tegra30_i2s_hw_params,
        .trigger        = tegra30_i2s_trigger,
+       .set_tdm_slot   = tegra30_i2s_set_tdm,
 };
 
 static const struct snd_soc_dai_driver tegra30_i2s_dai_template = {
@@ -277,14 +317,18 @@ static const struct snd_soc_dai_driver tegra30_i2s_dai_template = {
                .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000_96000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               .formats = SNDRV_PCM_FMTBIT_S32_LE |
+                          SNDRV_PCM_FMTBIT_S24_LE |
+                          SNDRV_PCM_FMTBIT_S16_LE,
        },
        .capture = {
                .stream_name = "Capture",
                .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000_96000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               .formats = SNDRV_PCM_FMTBIT_S32_LE |
+                          SNDRV_PCM_FMTBIT_S24_LE |
+                          SNDRV_PCM_FMTBIT_S16_LE,
        },
        .ops = &tegra30_i2s_dai_ops,
        .symmetric_rates = 1,