.. | .. |
---|
59 | 59 | #define JZ_AIC_CTRL_MONO_TO_STEREO BIT(11) |
---|
60 | 60 | #define JZ_AIC_CTRL_SWITCH_ENDIANNESS BIT(10) |
---|
61 | 61 | #define JZ_AIC_CTRL_SIGNED_TO_UNSIGNED BIT(9) |
---|
62 | | -#define JZ_AIC_CTRL_FLUSH BIT(8) |
---|
| 62 | +#define JZ_AIC_CTRL_TFLUSH BIT(8) |
---|
| 63 | +#define JZ_AIC_CTRL_RFLUSH BIT(7) |
---|
63 | 64 | #define JZ_AIC_CTRL_ENABLE_ROR_INT BIT(6) |
---|
64 | 65 | #define JZ_AIC_CTRL_ENABLE_TUR_INT BIT(5) |
---|
65 | 66 | #define JZ_AIC_CTRL_ENABLE_RFS_INT BIT(4) |
---|
.. | .. |
---|
94 | 95 | struct i2s_soc_info { |
---|
95 | 96 | enum jz47xx_i2s_version version; |
---|
96 | 97 | struct snd_soc_dai_driver *dai; |
---|
| 98 | + |
---|
| 99 | + bool shared_fifo_flush; |
---|
97 | 100 | }; |
---|
98 | 101 | |
---|
99 | 102 | struct jz4740_i2s { |
---|
.. | .. |
---|
122 | 125 | writel(value, i2s->base + reg); |
---|
123 | 126 | } |
---|
124 | 127 | |
---|
| 128 | +static inline void jz4740_i2s_set_bits(const struct jz4740_i2s *i2s, |
---|
| 129 | + unsigned int reg, uint32_t bits) |
---|
| 130 | +{ |
---|
| 131 | + uint32_t value = jz4740_i2s_read(i2s, reg); |
---|
| 132 | + value |= bits; |
---|
| 133 | + jz4740_i2s_write(i2s, reg, value); |
---|
| 134 | +} |
---|
| 135 | + |
---|
125 | 136 | static int jz4740_i2s_startup(struct snd_pcm_substream *substream, |
---|
126 | 137 | struct snd_soc_dai *dai) |
---|
127 | 138 | { |
---|
128 | 139 | struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
---|
129 | | - uint32_t conf, ctrl; |
---|
| 140 | + uint32_t conf; |
---|
130 | 141 | int ret; |
---|
| 142 | + |
---|
| 143 | + /* |
---|
| 144 | + * When we can flush FIFOs independently, only flush the FIFO |
---|
| 145 | + * that is starting up. We can do this when the DAI is active |
---|
| 146 | + * because it does not disturb other active substreams. |
---|
| 147 | + */ |
---|
| 148 | + if (!i2s->soc_info->shared_fifo_flush) { |
---|
| 149 | + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
| 150 | + jz4740_i2s_set_bits(i2s, JZ_REG_AIC_CTRL, JZ_AIC_CTRL_TFLUSH); |
---|
| 151 | + else |
---|
| 152 | + jz4740_i2s_set_bits(i2s, JZ_REG_AIC_CTRL, JZ_AIC_CTRL_RFLUSH); |
---|
| 153 | + } |
---|
131 | 154 | |
---|
132 | 155 | if (snd_soc_dai_active(dai)) |
---|
133 | 156 | return 0; |
---|
134 | 157 | |
---|
135 | | - ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL); |
---|
136 | | - ctrl |= JZ_AIC_CTRL_FLUSH; |
---|
137 | | - jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl); |
---|
| 158 | + /* |
---|
| 159 | + * When there is a shared flush bit for both FIFOs, the TFLUSH |
---|
| 160 | + * bit flushes both FIFOs. Flushing while the DAI is active would |
---|
| 161 | + * cause FIFO underruns in other active substreams so we have to |
---|
| 162 | + * guard this behind the snd_soc_dai_active() check. |
---|
| 163 | + */ |
---|
| 164 | + if (i2s->soc_info->shared_fifo_flush) |
---|
| 165 | + jz4740_i2s_set_bits(i2s, JZ_REG_AIC_CTRL, JZ_AIC_CTRL_TFLUSH); |
---|
138 | 166 | |
---|
139 | 167 | ret = clk_prepare_enable(i2s->clk_i2s); |
---|
140 | 168 | if (ret) |
---|
.. | .. |
---|
467 | 495 | static const struct i2s_soc_info jz4740_i2s_soc_info = { |
---|
468 | 496 | .version = JZ_I2S_JZ4740, |
---|
469 | 497 | .dai = &jz4740_i2s_dai, |
---|
| 498 | + .shared_fifo_flush = true, |
---|
470 | 499 | }; |
---|
471 | 500 | |
---|
472 | 501 | static const struct i2s_soc_info jz4760_i2s_soc_info = { |
---|