sound/soc/spacemit/k1_i2s.c

Source file repositories/reference/linux-study-clean/sound/soc/spacemit/k1_i2s.c

File Facts

System
Linux kernel
Corpus path
sound/soc/spacemit/k1_i2s.c
Extension
.c
Size
14049 bytes
Lines
514
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 spacemit_i2s_dev {
	struct device *dev;

	void __iomem *base;

	struct reset_control *reset;

	struct clk *sysclk;
	struct clk *bclk;
	struct clk *sspa_clk;
	struct clk *sysclk_div;
	struct clk *c_sysclk;
	struct clk *c_bclk;

	struct snd_dmaengine_dai_dma_data capture_dma_data;
	struct snd_dmaengine_dai_dma_data playback_dma_data;

	bool has_capture;
	bool has_playback;

	int dai_fmt;

	int started_count;
};

static const struct snd_pcm_hardware spacemit_pcm_hardware = {
	.info		  = SNDRV_PCM_INFO_INTERLEAVED |
			    SNDRV_PCM_INFO_BATCH,
	.formats          = SPACEMIT_PCM_FORMATS,
	.rates		  = SPACEMIT_PCM_RATES,
	.rate_min         = SNDRV_PCM_RATE_8000,
	.rate_max         = SNDRV_PCM_RATE_192000,
	.channels_min     = 1,
	.channels_max     = 2,
	.buffer_bytes_max = SPACEMIT_I2S_PERIOD_SIZE * 4 * 4,
	.period_bytes_min = SPACEMIT_I2S_PERIOD_SIZE * 2,
	.period_bytes_max = SPACEMIT_I2S_PERIOD_SIZE * 4,
	.periods_min	  = 2,
	.periods_max	  = 4,
};

static const struct snd_dmaengine_pcm_config spacemit_dmaengine_pcm_config = {
	.pcm_hardware = &spacemit_pcm_hardware,
	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
	.chan_names = {"tx", "rx"},
	.prealloc_buffer_size = 32 * 1024,
};

static void spacemit_i2s_init(struct spacemit_i2s_dev *i2s)
{
	u32 sscr_val, sspsp_val, ssfcr_val, ssrwt_val;

	sscr_val = SSCR_TRAIL | SSCR_FRF_PSP;
	ssfcr_val = FIELD_PREP(SSFCR_FIELD_TFT, 0xF) |
		    FIELD_PREP(SSFCR_FIELD_RFT, 0xF) |
		    SSFCR_RSRE | SSFCR_TSRE;
	ssrwt_val = SSRWT_RWOT;
	sspsp_val = SSPSP_SFRMP;

	writel(sscr_val, i2s->base + SSCR);
	writel(ssfcr_val, i2s->base + SSFCR);
	writel(sspsp_val, i2s->base + SSPSP);
	writel(ssrwt_val, i2s->base + SSRWT);
	writel(0, i2s->base + SSINTEN);
}

static int spacemit_i2s_startup(struct snd_pcm_substream *substream,
	struct snd_soc_dai *dai)
{
	struct spacemit_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);

	switch (i2s->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_I2S:
		snd_pcm_hw_constraint_minmax(substream->runtime,
					     SNDRV_PCM_HW_PARAM_CHANNELS,
					     2, 2);
		snd_pcm_hw_constraint_mask64(substream->runtime,
					     SNDRV_PCM_HW_PARAM_FORMAT,
					     SNDRV_PCM_FMTBIT_S16_LE);
		break;
	case SND_SOC_DAIFMT_DSP_A:
	case SND_SOC_DAIFMT_DSP_B:
		snd_pcm_hw_constraint_minmax(substream->runtime,
					     SNDRV_PCM_HW_PARAM_CHANNELS,
					     1, 1);
		snd_pcm_hw_constraint_mask64(substream->runtime,
					     SNDRV_PCM_HW_PARAM_FORMAT,
					     SNDRV_PCM_FMTBIT_S32_LE);
		break;
	default:

Annotation

Implementation Notes