sound/soc/spear/spdif_out.c

Source file repositories/reference/linux-study-clean/sound/soc/spear/spdif_out.c

File Facts

System
Linux kernel
Corpus path
sound/soc/spear/spdif_out.c
Extension
.c
Size
8895 bytes
Lines
365
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_out_params {
	u32 rate;
	u32 core_freq;
	u32 mute;
};

struct spdif_out_dev {
	struct clk *clk;
	struct spear_dma_data dma_params;
	struct spdif_out_params saved_params;
	u32 running;
	void __iomem *io_base;
	struct snd_dmaengine_dai_dma_data dma_params_tx;
	struct snd_dmaengine_pcm_config config;
};

static void spdif_out_configure(struct spdif_out_dev *host)
{
	writel(SPDIF_OUT_RESET, host->io_base + SPDIF_OUT_SOFT_RST);
	mdelay(1);
	writel(readl(host->io_base + SPDIF_OUT_SOFT_RST) & ~SPDIF_OUT_RESET,
			host->io_base + SPDIF_OUT_SOFT_RST);

	writel(SPDIF_OUT_FDMA_TRIG_16 | SPDIF_OUT_MEMFMT_16_16 |
			SPDIF_OUT_VALID_HW | SPDIF_OUT_USER_HW |
			SPDIF_OUT_CHNLSTA_HW | SPDIF_OUT_PARITY_HW,
			host->io_base + SPDIF_OUT_CFG);

	writel(0x7F, host->io_base + SPDIF_OUT_INT_STA_CLR);
	writel(0x7F, host->io_base + SPDIF_OUT_INT_EN_CLR);
}

static int spdif_out_startup(struct snd_pcm_substream *substream,
		struct snd_soc_dai *cpu_dai)
{
	struct spdif_out_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
	int ret;

	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
		return -EINVAL;

	ret = clk_enable(host->clk);
	if (ret)
		return ret;

	host->running = true;
	spdif_out_configure(host);

	return 0;
}

static void spdif_out_shutdown(struct snd_pcm_substream *substream,
		struct snd_soc_dai *dai)
{
	struct spdif_out_dev *host = snd_soc_dai_get_drvdata(dai);

	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
		return;

	clk_disable(host->clk);
	host->running = false;
}

static void spdif_out_clock(struct spdif_out_dev *host, u32 core_freq,
		u32 rate)
{
	u32 divider, ctrl;

	clk_set_rate(host->clk, core_freq);
	divider = DIV_ROUND_CLOSEST(clk_get_rate(host->clk), (rate * 128));

	ctrl = readl(host->io_base + SPDIF_OUT_CTRL);
	ctrl &= ~SPDIF_DIVIDER_MASK;
	ctrl |= (divider << SPDIF_DIVIDER_SHIFT) & SPDIF_DIVIDER_MASK;
	writel(ctrl, host->io_base + SPDIF_OUT_CTRL);
}

static int spdif_out_hw_params(struct snd_pcm_substream *substream,
		struct snd_pcm_hw_params *params,
		struct snd_soc_dai *dai)
{
	struct spdif_out_dev *host = snd_soc_dai_get_drvdata(dai);
	u32 rate, core_freq;

	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
		return -EINVAL;

	rate = params_rate(params);

	switch (rate) {

Annotation

Implementation Notes