sound/soc/xilinx/xlnx_spdif.c

Source file repositories/reference/linux-study-clean/sound/soc/xilinx/xlnx_spdif.c

File Facts

System
Linux kernel
Corpus path
sound/soc/xilinx/xlnx_spdif.c
Extension
.c
Size
7744 bytes
Lines
319
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 spdif_dev_data {
	u32 mode;
	u32 aclk;
	bool rx_chsts_updated;
	void __iomem *base;
	struct clk *axi_clk;
	wait_queue_head_t chsts_q;
};

static irqreturn_t xlnx_spdifrx_irq_handler(int irq, void *arg)
{
	u32 val;
	struct spdif_dev_data *ctx = arg;

	val = readl(ctx->base + XSPDIF_IRQ_STS_REG);
	if (val & XSPDIF_CH_STS_MASK) {
		writel(val & XSPDIF_CH_STS_MASK,
		       ctx->base + XSPDIF_IRQ_STS_REG);
		val = readl(ctx->base +
			    XSPDIF_IRQ_ENABLE_REG);
		writel(val & ~XSPDIF_CH_STS_MASK,
		       ctx->base + XSPDIF_IRQ_ENABLE_REG);

		ctx->rx_chsts_updated = true;
		wake_up_interruptible(&ctx->chsts_q);
		return IRQ_HANDLED;
	}

	return IRQ_NONE;
}

static int xlnx_spdif_startup(struct snd_pcm_substream *substream,
			      struct snd_soc_dai *dai)
{
	u32 val;
	struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev);

	val = readl(ctx->base + XSPDIF_CONTROL_REG);
	val |= XSPDIF_FIFO_FLUSH_MASK;
	writel(val, ctx->base + XSPDIF_CONTROL_REG);

	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
		writel(XSPDIF_CH_STS_MASK,
		       ctx->base + XSPDIF_IRQ_ENABLE_REG);
		writel(XSPDIF_GLOBAL_IRQ_ENABLE,
		       ctx->base + XSPDIF_GLOBAL_IRQ_ENABLE_REG);
	}

	return 0;
}

static void xlnx_spdif_shutdown(struct snd_pcm_substream *substream,
				struct snd_soc_dai *dai)
{
	struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev);

	writel(XSPDIF_SOFT_RESET_VALUE, ctx->base + XSPDIF_SOFT_RESET_REG);
}

static int xlnx_spdif_hw_params(struct snd_pcm_substream *substream,
				struct snd_pcm_hw_params *params,
				struct snd_soc_dai *dai)
{
	u32 val, clk_div, clk_cfg;
	struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev);

	clk_div = DIV_ROUND_CLOSEST(ctx->aclk, MAX_CHANNELS * AES_SAMPLE_WIDTH *
				    params_rate(params));

	switch (clk_div) {
	case 4:
		clk_cfg = 0;
		break;
	case 8:
		clk_cfg = 1;
		break;
	case 16:
		clk_cfg = 2;
		break;
	case 24:
		clk_cfg = 3;
		break;
	case 32:
		clk_cfg = 4;
		break;
	case 48:
		clk_cfg = 5;
		break;
	case 64:
		clk_cfg = 6;

Annotation

Implementation Notes