sound/soc/stm/stm32_spdifrx.c

Source file repositories/reference/linux-study-clean/sound/soc/stm/stm32_spdifrx.c

File Facts

System
Linux kernel
Corpus path
sound/soc/stm/stm32_spdifrx.c
Extension
.c
Size
29498 bytes
Lines
1070
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 stm32_spdifrx_data {
	struct platform_device *pdev;
	void __iomem *base;
	struct regmap *regmap;
	const struct regmap_config *regmap_conf;
	struct completion cs_completion;
	struct clk *kclk;
	struct snd_dmaengine_dai_dma_data dma_params;
	struct snd_pcm_substream *substream;
	struct snd_dma_buffer *dmab;
	struct dma_chan *ctrl_chan;
	struct dma_async_tx_descriptor *desc;
	struct dma_slave_config slave_config;
	dma_addr_t phys_addr;
	spinlock_t lock;  /* Sync enabling lock */
	spinlock_t irq_lock; /* Prevent race condition on stream state */
	unsigned char cs[SPDIFRX_CS_BYTES_NB];
	unsigned char ub[SPDIFRX_UB_BYTES_NB];
	int irq;
	int refcount;
};

static void stm32_spdifrx_dma_complete(void *data)
{
	struct stm32_spdifrx_data *spdifrx = (struct stm32_spdifrx_data *)data;
	struct platform_device *pdev = spdifrx->pdev;
	u32 *p_start = (u32 *)spdifrx->dmab->area;
	u32 *p_end = p_start + (2 * SPDIFRX_CS_BYTES_NB) - 1;
	u32 *ptr = p_start;
	u16 *ub_ptr = (short *)spdifrx->ub;
	int i = 0;

	regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR,
			   SPDIFRX_CR_CBDMAEN,
			   (unsigned int)~SPDIFRX_CR_CBDMAEN);

	if (!spdifrx->dmab->area)
		return;

	while (ptr <= p_end) {
		if (*ptr & SPDIFRX_CSR_SOB)
			break;
		ptr++;
	}

	if (ptr > p_end) {
		dev_err(&pdev->dev, "Start of S/PDIF block not found\n");
		return;
	}

	while (i < SPDIFRX_CS_BYTES_NB) {
		spdifrx->cs[i] = (unsigned char)SPDIFRX_CSR_CSGET(*ptr);
		*ub_ptr++ = SPDIFRX_CSR_USRGET(*ptr++);
		if (ptr > p_end) {
			dev_err(&pdev->dev, "Failed to get channel status\n");
			return;
		}
		i++;
	}

	complete(&spdifrx->cs_completion);
}

static int stm32_spdifrx_dma_ctrl_start(struct stm32_spdifrx_data *spdifrx)
{
	dma_cookie_t cookie;
	int err;

	spdifrx->desc = dmaengine_prep_slave_single(spdifrx->ctrl_chan,
						    spdifrx->dmab->addr,
						    SPDIFRX_CSR_BUF_LENGTH,
						    DMA_DEV_TO_MEM,
						    DMA_CTRL_ACK);
	if (!spdifrx->desc)
		return -EINVAL;

	spdifrx->desc->callback = stm32_spdifrx_dma_complete;
	spdifrx->desc->callback_param = spdifrx;
	cookie = dmaengine_submit(spdifrx->desc);
	err = dma_submit_error(cookie);
	if (err)
		return -EINVAL;

	dma_async_issue_pending(spdifrx->ctrl_chan);

	return 0;
}

static void stm32_spdifrx_dma_ctrl_stop(struct stm32_spdifrx_data *spdifrx)
{

Annotation

Implementation Notes