sound/soc/rockchip/rockchip_spdif.c

Source file repositories/reference/linux-study-clean/sound/soc/rockchip/rockchip_spdif.c

File Facts

System
Linux kernel
Corpus path
sound/soc/rockchip/rockchip_spdif.c
Extension
.c
Size
11355 bytes
Lines
451
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 rk_spdif_dev {
	struct device *dev;

	struct clk *mclk;
	struct clk *hclk;

	struct snd_dmaengine_dai_dma_data playback_dma_data;

	struct regmap *regmap;
};

static int rk_spdif_runtime_suspend(struct device *dev)
{
	struct rk_spdif_dev *spdif = dev_get_drvdata(dev);

	regcache_cache_only(spdif->regmap, true);
	clk_disable_unprepare(spdif->mclk);
	clk_disable_unprepare(spdif->hclk);

	return 0;
}

static int rk_spdif_runtime_resume(struct device *dev)
{
	struct rk_spdif_dev *spdif = dev_get_drvdata(dev);
	int ret;

	ret = clk_prepare_enable(spdif->hclk);
	if (ret) {
		dev_err(spdif->dev, "hclk clock enable failed %d\n", ret);
		return ret;
	}

	ret = clk_prepare_enable(spdif->mclk);
	if (ret) {
		clk_disable_unprepare(spdif->hclk);
		dev_err(spdif->dev, "mclk clock enable failed %d\n", ret);
		return ret;
	}

	regcache_cache_only(spdif->regmap, false);
	regcache_mark_dirty(spdif->regmap);

	ret = regcache_sync(spdif->regmap);
	if (ret) {
		regcache_cache_only(spdif->regmap, true);
		clk_disable_unprepare(spdif->mclk);
		clk_disable_unprepare(spdif->hclk);
	}

	return ret;
}

static int rk_spdif_hw_params(struct snd_pcm_substream *substream,
			      struct snd_pcm_hw_params *params,
			      struct snd_soc_dai *dai)
{
	struct rk_spdif_dev *spdif = snd_soc_dai_get_drvdata(dai);
	unsigned int mclk_rate = clk_get_rate(spdif->mclk);
	unsigned int val = SPDIF_CFGR_HALFWORD_ENABLE;
	int bmc, div, ret, i;
	u16 *fc;
	u8 cs[CS_BYTE];

	ret = snd_pcm_create_iec958_consumer_hw_params(params, cs, sizeof(cs));
	if (ret < 0)
		return ret;

	fc = (u16 *)cs;
	for (i = 0; i < CS_BYTE / 2; i++)
		regmap_write(spdif->regmap, SPDIF_CHNSRn(i), CS_FRAME(fc[i]));

	regmap_update_bits(spdif->regmap, SPDIF_CFGR, SPDIF_CFGR_CSE_MASK,
			   SPDIF_CFGR_CSE_EN);

	/* bmc = 128fs */
	bmc = 128 * params_rate(params);
	div = DIV_ROUND_CLOSEST(mclk_rate, bmc);
	val |= SPDIF_CFGR_CLK_DIV(div);

	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S16_LE:
		val |= SPDIF_CFGR_VDW_16;
		val |= SPDIF_CFGR_ADJ_RIGHT_J;
		break;
	case SNDRV_PCM_FORMAT_S20_3LE:
		val |= SPDIF_CFGR_VDW_20;
		val |= SPDIF_CFGR_ADJ_RIGHT_J;
		break;
	case SNDRV_PCM_FORMAT_S24_LE:

Annotation

Implementation Notes