|
@@ -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;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|