sound/soc/samsung/spdif.c

Source file repositories/reference/linux-study-clean/sound/soc/samsung/spdif.c

File Facts

System
Linux kernel
Corpus path
sound/soc/samsung/spdif.c
Extension
.c
Size
11393 bytes
Lines
463
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 samsung_spdif_info {
	spinlock_t	lock;
	struct device	*dev;
	void __iomem	*regs;
	unsigned long	clk_rate;
	struct clk	*pclk;
	struct clk	*sclk;
	u32		saved_clkcon;
	u32		saved_con;
	u32		saved_cstas;
	struct snd_dmaengine_dai_dma_data *dma_playback;
};

static struct snd_dmaengine_dai_dma_data spdif_stereo_out;
static struct samsung_spdif_info spdif_info;

static inline struct samsung_spdif_info
*component_to_info(struct snd_soc_component *component)
{
	return snd_soc_component_get_drvdata(component);
}

static inline struct samsung_spdif_info *to_info(struct snd_soc_dai *cpu_dai)
{
	return snd_soc_dai_get_drvdata(cpu_dai);
}

static void spdif_snd_txctrl(struct samsung_spdif_info *spdif, int on)
{
	void __iomem *regs = spdif->regs;
	u32 clkcon;

	dev_dbg(spdif->dev, "Entered %s\n", __func__);

	clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
	if (on)
		writel(clkcon | CLKCTL_PWR_ON, regs + CLKCON);
	else
		writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
}

static int spdif_set_sysclk(struct snd_soc_dai *cpu_dai,
				int clk_id, unsigned int freq, int dir)
{
	struct samsung_spdif_info *spdif = to_info(cpu_dai);
	u32 clkcon;

	dev_dbg(spdif->dev, "Entered %s\n", __func__);

	clkcon = readl(spdif->regs + CLKCON);

	if (clk_id == SND_SOC_SPDIF_INT_MCLK)
		clkcon &= ~CLKCTL_MCLK_EXT;
	else
		clkcon |= CLKCTL_MCLK_EXT;

	writel(clkcon, spdif->regs + CLKCON);

	spdif->clk_rate = freq;

	return 0;
}

static int spdif_trigger(struct snd_pcm_substream *substream, int cmd,
				struct snd_soc_dai *dai)
{
	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
	struct samsung_spdif_info *spdif = to_info(snd_soc_rtd_to_cpu(rtd, 0));

	dev_dbg(spdif->dev, "Entered %s\n", __func__);

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_RESUME:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
		scoped_guard(spinlock_irqsave, &spdif->lock)
			spdif_snd_txctrl(spdif, 1);
		break;
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_SUSPEND:
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
		scoped_guard(spinlock_irqsave, &spdif->lock)
			spdif_snd_txctrl(spdif, 0);
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

Annotation

Implementation Notes