sound/soc/sunxi/sun4i-spdif.c

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

File Facts

System
Linux kernel
Corpus path
sound/soc/sunxi/sun4i-spdif.c
Extension
.c
Size
21378 bytes
Lines
774
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 sun4i_spdif_quirks {
	unsigned int reg_dac_txdata;
	bool has_reset;
	unsigned int val_fctl_ftx;
	unsigned int mclk_multiplier;
	const char *tx_clk_name;
};

struct sun4i_spdif_dev {
	struct platform_device *pdev;
	struct clk *spdif_clk;
	struct clk *apb_clk;
	struct reset_control *rst;
	struct snd_soc_dai_driver cpu_dai_drv;
	struct regmap *regmap;
	struct snd_dmaengine_dai_dma_data dma_params_tx;
	const struct sun4i_spdif_quirks *quirks;
	spinlock_t lock;
};

static void sun4i_spdif_configure(struct sun4i_spdif_dev *host)
{
	const struct sun4i_spdif_quirks *quirks = host->quirks;

	/* soft reset SPDIF */
	regmap_write(host->regmap, SUN4I_SPDIF_CTL, SUN4I_SPDIF_CTL_RESET);

	/* flush TX FIFO */
	regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL,
			   quirks->val_fctl_ftx, quirks->val_fctl_ftx);

	/* Valid data at the MSB of TXFIFO Register */
	regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL,
			   SUN4I_SPDIF_FCTL_TXIM, 0);

	/* clear TX counter */
	regmap_write(host->regmap, SUN4I_SPDIF_TXCNT, 0);
}

static void sun4i_snd_txctrl_on(struct snd_pcm_substream *substream,
				struct sun4i_spdif_dev *host)
{
	if (substream->runtime->channels == 1)
		regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
				   SUN4I_SPDIF_TXCFG_SINGLEMOD,
				   SUN4I_SPDIF_TXCFG_SINGLEMOD);

	/* SPDIF TX ENABLE */
	regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
			   SUN4I_SPDIF_TXCFG_TXEN, SUN4I_SPDIF_TXCFG_TXEN);

	/* DRQ ENABLE */
	regmap_update_bits(host->regmap, SUN4I_SPDIF_INT,
			   SUN4I_SPDIF_INT_TXDRQEN, SUN4I_SPDIF_INT_TXDRQEN);

	/* Global enable */
	regmap_update_bits(host->regmap, SUN4I_SPDIF_CTL,
			   SUN4I_SPDIF_CTL_GEN, SUN4I_SPDIF_CTL_GEN);
}

static void sun4i_snd_txctrl_off(struct snd_pcm_substream *substream,
				 struct sun4i_spdif_dev *host)
{
	/* SPDIF TX DISABLE */
	regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
			   SUN4I_SPDIF_TXCFG_TXEN, 0);

	/* DRQ DISABLE */
	regmap_update_bits(host->regmap, SUN4I_SPDIF_INT,
			   SUN4I_SPDIF_INT_TXDRQEN, 0);

	/* Global disable */
	regmap_update_bits(host->regmap, SUN4I_SPDIF_CTL,
			   SUN4I_SPDIF_CTL_GEN, 0);
}

static int sun4i_spdif_startup(struct snd_pcm_substream *substream,
			       struct snd_soc_dai *cpu_dai)
{
	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
	struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));

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

	sun4i_spdif_configure(host);

	return 0;
}

Annotation

Implementation Notes