sound/soc/xtensa/xtfpga-i2s.c

Source file repositories/reference/linux-study-clean/sound/soc/xtensa/xtfpga-i2s.c

File Facts

System
Linux kernel
Corpus path
sound/soc/xtensa/xtfpga-i2s.c
Extension
.c
Size
17521 bytes
Lines
651
Domain
Driver Families
Bucket
sound/soc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

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;

	/* maximal FIFO level */
	unsigned tx_fifo_high;
};

static bool xtfpga_i2s_wr_reg(struct device *dev, unsigned int reg)
{
	return reg >= XTFPGA_I2S_CONFIG;
}

static bool xtfpga_i2s_rd_reg(struct device *dev, unsigned int reg)
{
	return reg < XTFPGA_I2S_CHAN0_DATA;
}

static bool xtfpga_i2s_volatile_reg(struct device *dev, unsigned int reg)
{
	return reg == XTFPGA_I2S_INT_STATUS;
}

static const struct regmap_config xtfpga_i2s_regmap_config = {
	.reg_bits = 32,
	.reg_stride = 4,
	.val_bits = 32,
	.max_register = XTFPGA_I2S_CHAN3_DATA,
	.writeable_reg = xtfpga_i2s_wr_reg,
	.readable_reg = xtfpga_i2s_rd_reg,
	.volatile_reg = xtfpga_i2s_volatile_reg,
	.cache_type = REGCACHE_FLAT,
};

/* 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) \
static unsigned 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; \

Annotation

Implementation Notes