/* * I2S controller operation: * * Enabling TX: output 1 period of zeros (starting with left channel) * and then queued data. * * Level status and interrupt: whenever FIFO level is below FIFO trigger, * level status is 1 and an IRQ is asserted (if enabled). * * Underrun status and interrupt: whenever FIFO is empty, underrun status * is 1 and an IRQ is asserted (if enabled).
*/ struct xtfpga_i2s { struct device *dev; struct clk *clk; struct regmap *regmap; void __iomem *regs;
/* current playback substream. NULL if not playing. * * Access to that field is synchronized between the interrupt handler * and userspace through RCU. * * Interrupt handler (threaded part) does PIO on substream data in RCU * read-side critical section. Trigger callback sets and clears the * pointer when the playback is started and stopped with * rcu_assign_pointer. When userspace is about to free the playback * stream in the pcm_close callback it synchronizes with the interrupt * handler by means of synchronize_rcu call.
*/ struct snd_pcm_substream __rcu *tx_substream; unsigned (*tx_fn)(struct xtfpga_i2s *i2s, struct snd_pcm_runtime *runtime, unsigned tx_ptr); unsigned tx_ptr; /* next frame index in the sample buffer */
/* current fifo level estimate. * Doesn't have to be perfectly accurate, but must be not less than * the actual FIFO level in order to avoid stall on push attempt.
*/ unsigned tx_fifo_level;
/* FIFO level at which level interrupt occurs */ unsigned tx_fifo_low;
/* Generate functions that do PIO from TX DMA area to FIFO for all supported * stream formats. * Functions will be called xtfpga_pcm_tx_<channels>x<sample bits>, e.g. * xtfpga_pcm_tx_2x16 for 16-bit stereo. * * FIFO consists of 32-bit words, one word per channel, always 2 channels. * If I2S interface is configured with smaller sample resolution, only * the LSB of each word is used.
*/ #define xtfpga_pcm_tx_fn(channels, sample_bits) \ staticunsigned xtfpga_pcm_tx_##channels##x##sample_bits( \ struct xtfpga_i2s *i2s, struct snd_pcm_runtime *runtime, \ unsigned tx_ptr) \
{ \ const u##sample_bits (*p)[channels] = \
(void *)runtime->dma_area; \
\ for (; i2s->tx_fifo_level < i2s->tx_fifo_high; \
i2s->tx_fifo_level += 2) { \
iowrite32(p[tx_ptr][0], \
i2s->regs + XTFPGA_I2S_CHAN0_DATA); \
iowrite32(p[tx_ptr][channels - 1], \
i2s->regs + XTFPGA_I2S_CHAN0_DATA); \ if (++tx_ptr >= runtime->buffer_size) \
tx_ptr = 0; \
} \ return tx_ptr; \
}
for (i = 0; i < 2; ++i) { bool tx_active = xtfpga_pcm_push_tx(i2s);
regmap_write(i2s->regmap, XTFPGA_I2S_INT_STATUS,
XTFPGA_I2S_INT_VALID); if (tx_active)
regmap_read(i2s->regmap, XTFPGA_I2S_INT_STATUS,
&int_status);
if (!tx_active ||
!(int_status & XTFPGA_I2S_INT_LEVEL)) break;
/* After the push the level IRQ is still asserted, * means FIFO level is below tx_fifo_low. Estimate * it as tx_fifo_low.
*/
i2s->tx_fifo_level = i2s->tx_fifo_low;
}
/* ratio field of the config register controls MCLK->I2S clock * derivation: I2S clock = MCLK / (2 * (ratio + 2)). * * So with MCLK = 256 * sample rate ratio is 0 for 32 bit stereo * and 2 for 16 bit stereo.
*/
ratio = (freq - (srate * sample_size * 8)) /
(srate * sample_size * 4);
regmap_update_bits(i2s->regmap, XTFPGA_I2S_CONFIG,
XTFPGA_I2S_CONFIG_RATIO_MASK,
ratio << XTFPGA_I2S_CONFIG_RATIO_BASE);
staticint xtfpga_pcm_trigger(struct snd_soc_component *component, struct snd_pcm_substream *substream, int cmd)
{ int ret = 0; struct snd_pcm_runtime *runtime = substream->runtime; struct xtfpga_i2s *i2s = runtime->private_data;
switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
WRITE_ONCE(i2s->tx_ptr, 0);
rcu_assign_pointer(i2s->tx_substream, substream);
xtfpga_pcm_refill_fifo(i2s); break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
rcu_assign_pointer(i2s->tx_substream, NULL); break;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.