sound: soc: tegra: Add RX and TX channel reset
Nitin Nagaraja [Fri, 26 Apr 2013 11:19:55 +0000 (16:19 +0530)]
When the same APBIF channel is used for repeated recording and
switching between I2S and TDM mode, there is corruption and hang.
Adding soft reset to that channel during allocation of the FIFOs
fixes the issue.

Bug 1224769

Change-Id: I7b7483ffeca347a021892d9bc47a3f9005602500
Signed-off-by: Nitin Nagaraja <nitinn@nvidia.com>
Reviewed-on: http://git-master/r/223344
(cherry picked from commit 532d07c2fbc7fa07e7649cd587332439cc3ac6d8)
Reviewed-on: http://git-master/r/227397
Reviewed-by: Nitin Pai <npai@nvidia.com>
Reviewed-by: Scott Peterson <speterson@nvidia.com>
Reviewed-by: Bob Johnston <bjohnston@nvidia.com>

sound/soc/tegra/tegra30_ahub.c

index ea9afa4..ce0b161 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * tegra30_ahub.c - Tegra30 AHUB driver
  *
- * Copyright (c) 2011,2012, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2011-2013, NVIDIA CORPORATION. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -103,6 +103,28 @@ void tegra30_ahub_clock_set_rate(int rate)
        clk_set_rate(ahub->clk_d_audio, rate);
 }
 
+static int tegra30_ahub_soft_reset_rx_channel(int channel)
+{
+       u32 reg, val;
+
+       reg = TEGRA30_AHUB_CHANNEL_CLEAR +
+             (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE);
+       val = TEGRA30_AHUB_CHANNEL_CLEAR_RX_SOFT_RESET;
+       tegra30_apbif_write(reg, val);
+       return 0;
+}
+
+static int tegra30_ahub_soft_reset_tx_channel(int channel)
+{
+       u32 reg, val;
+
+       reg = TEGRA30_AHUB_CHANNEL_CLEAR +
+             (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE);
+       val = TEGRA30_AHUB_CHANNEL_CLEAR_TX_SOFT_RESET;
+       tegra30_apbif_write(reg, val);
+       return 0;
+}
+
 int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
                                  unsigned long *fiforeg,
                                  unsigned long *reqsel)
@@ -122,6 +144,8 @@ int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
                   (channel * TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE);
        *reqsel = ahub->dma_sel + channel;
 
+       tegra30_ahub_soft_reset_rx_channel(channel);
+
        reg = TEGRA30_AHUB_CHANNEL_CTRL +
              (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
        val = tegra30_apbif_read(reg);
@@ -362,6 +386,8 @@ int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
                   (channel * TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE);
        *reqsel = ahub->dma_sel + channel;
 
+       tegra30_ahub_soft_reset_tx_channel(channel);
+
        reg = TEGRA30_AHUB_CHANNEL_CTRL +
              (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
        val = tegra30_apbif_read(reg);