Merge remote-tracking branch 'asoc/topic/twl6040' into asoc-next
[cascardo/linux.git] / sound / soc / rockchip / rockchip_i2s.c
index 2f8e204..574c6af 100644 (file)
@@ -34,6 +34,13 @@ struct rk_i2s_dev {
 
        struct regmap *regmap;
 
+/*
+ * Used to indicate the tx/rx status.
+ * I2S controller hopes to start the tx and rx together,
+ * also to stop them when they are both try to stop.
+*/
+       bool tx_start;
+       bool rx_start;
        bool is_master_mode;
 };
 
@@ -75,29 +82,37 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
                                   I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE);
 
                regmap_update_bits(i2s->regmap, I2S_XFER,
-                                  I2S_XFER_TXS_START,
-                                  I2S_XFER_TXS_START);
+                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START,
+                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START);
+
+               i2s->tx_start = true;
        } else {
+               i2s->tx_start = false;
+
                regmap_update_bits(i2s->regmap, I2S_DMACR,
                                   I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
 
-               regmap_update_bits(i2s->regmap, I2S_XFER,
-                                  I2S_XFER_TXS_START,
-                                  I2S_XFER_TXS_STOP);
+               if (!i2s->rx_start) {
+                       regmap_update_bits(i2s->regmap, I2S_XFER,
+                                          I2S_XFER_TXS_START |
+                                          I2S_XFER_RXS_START,
+                                          I2S_XFER_TXS_STOP |
+                                          I2S_XFER_RXS_STOP);
 
-               regmap_update_bits(i2s->regmap, I2S_CLR,
-                                  I2S_CLR_TXC,
-                                  I2S_CLR_TXC);
+                       regmap_update_bits(i2s->regmap, I2S_CLR,
+                                          I2S_CLR_TXC | I2S_CLR_RXC,
+                                          I2S_CLR_TXC | I2S_CLR_RXC);
 
-               regmap_read(i2s->regmap, I2S_CLR, &val);
-
-               /* Should wait for clear operation to finish */
-               while (val & I2S_CLR_TXC) {
                        regmap_read(i2s->regmap, I2S_CLR, &val);
-                       retry--;
-                       if (!retry) {
-                               dev_warn(i2s->dev, "fail to clear\n");
-                               break;
+
+                       /* Should wait for clear operation to finish */
+                       while (val) {
+                               regmap_read(i2s->regmap, I2S_CLR, &val);
+                               retry--;
+                               if (!retry) {
+                                       dev_warn(i2s->dev, "fail to clear\n");
+                                       break;
+                               }
                        }
                }
        }
@@ -113,29 +128,37 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
                                   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE);
 
                regmap_update_bits(i2s->regmap, I2S_XFER,
-                                  I2S_XFER_RXS_START,
-                                  I2S_XFER_RXS_START);
+                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START,
+                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START);
+
+               i2s->rx_start = true;
        } else {
+               i2s->rx_start = false;
+
                regmap_update_bits(i2s->regmap, I2S_DMACR,
                                   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
 
-               regmap_update_bits(i2s->regmap, I2S_XFER,
-                                  I2S_XFER_RXS_START,
-                                  I2S_XFER_RXS_STOP);
+               if (!i2s->tx_start) {
+                       regmap_update_bits(i2s->regmap, I2S_XFER,
+                                          I2S_XFER_TXS_START |
+                                          I2S_XFER_RXS_START,
+                                          I2S_XFER_TXS_STOP |
+                                          I2S_XFER_RXS_STOP);
 
-               regmap_update_bits(i2s->regmap, I2S_CLR,
-                                  I2S_CLR_RXC,
-                                  I2S_CLR_RXC);
+                       regmap_update_bits(i2s->regmap, I2S_CLR,
+                                          I2S_CLR_TXC | I2S_CLR_RXC,
+                                          I2S_CLR_TXC | I2S_CLR_RXC);
 
-               regmap_read(i2s->regmap, I2S_CLR, &val);
-
-               /* Should wait for clear operation to finish */
-               while (val & I2S_CLR_RXC) {
                        regmap_read(i2s->regmap, I2S_CLR, &val);
-                       retry--;
-                       if (!retry) {
-                               dev_warn(i2s->dev, "fail to clear\n");
-                               break;
+
+                       /* Should wait for clear operation to finish */
+                       while (val) {
+                               regmap_read(i2s->regmap, I2S_CLR, &val);
+                               retry--;
+                               if (!retry) {
+                                       dev_warn(i2s->dev, "fail to clear\n");
+                                       break;
+                               }
                        }
                }
        }