sound/soc/rockchip/rockchip_sai.c

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

File Facts

System
Linux kernel
Corpus path
sound/soc/rockchip/rockchip_sai.c
Extension
.c
Size
42734 bytes
Lines
1531
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_sai_dev {
	struct device *dev;
	struct clk *hclk;
	struct clk *mclk;
	struct regmap *regmap;
	struct reset_control *rst_h;
	struct reset_control *rst_m;
	struct snd_dmaengine_dai_dma_data capture_dma_data;
	struct snd_dmaengine_dai_dma_data playback_dma_data;
	struct snd_pcm_substream *substreams[SNDRV_PCM_STREAM_LAST + 1];
	unsigned int mclk_rate;
	unsigned int wait_time[SNDRV_PCM_STREAM_LAST + 1];
	unsigned int tx_lanes;
	unsigned int rx_lanes;
	unsigned int sdi[MAX_LANES];
	unsigned int sdo[MAX_LANES];
	unsigned int version;
	enum fpw_mode fpw;
	int  fw_ratio;
	bool has_capture;
	bool has_playback;
	bool is_master_mode;
	bool is_tdm;
	bool initialized;
	/* protects register writes that depend on the state of XFER[1:0] */
	spinlock_t xfer_lock;
};

static bool rockchip_sai_stream_valid(struct snd_pcm_substream *substream,
				      struct snd_soc_dai *dai)
{
	struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);

	if (!substream)
		return false;

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
	    sai->has_playback)
		return true;

	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
	    sai->has_capture)
		return true;

	return false;
}

static int rockchip_sai_fsync_lost_detect(struct rk_sai_dev *sai, bool en)
{
	unsigned int fw, cnt;

	if (sai->is_master_mode || sai->version < SAI_VER_2311)
		return 0;

	regmap_read(sai->regmap, SAI_FSCR, &fw);
	cnt = SAI_FSCR_FW_V(fw) << 1; /* two fsync lost */

	regmap_update_bits(sai->regmap, SAI_INTCR,
			   SAI_INTCR_FSLOSTC, SAI_INTCR_FSLOSTC);
	regmap_update_bits(sai->regmap, SAI_INTCR,
			   SAI_INTCR_FSLOST_MASK,
			   SAI_INTCR_FSLOST(en));
	/*
	 * The `cnt` is the number of SCLK cycles of the CRU's SCLK signal that
	 * should be used as timeout. Consequently, in slave mode, this value
	 * is only correct if the CRU SCLK is equal to the external SCLK.
	 */
	regmap_update_bits(sai->regmap, SAI_FS_TIMEOUT,
			   SAI_FS_TIMEOUT_VAL_MASK | SAI_FS_TIMEOUT_EN_MASK,
			   SAI_FS_TIMEOUT_VAL(cnt) | SAI_FS_TIMEOUT_EN(en));

	return 0;
}

static int rockchip_sai_fsync_err_detect(struct rk_sai_dev *sai,
					 bool en)
{
	if (sai->is_master_mode || sai->version < SAI_VER_2311)
		return 0;

	regmap_update_bits(sai->regmap, SAI_INTCR,
			   SAI_INTCR_FSERRC, SAI_INTCR_FSERRC);
	regmap_update_bits(sai->regmap, SAI_INTCR,
			   SAI_INTCR_FSERR_MASK,
			   SAI_INTCR_FSERR(en));

	return 0;
}

static int rockchip_sai_poll_clk_idle(struct rk_sai_dev *sai)

Annotation

Implementation Notes