drivers/dma/stm32/stm32-dmamux.c

Source file repositories/reference/linux-study-clean/drivers/dma/stm32/stm32-dmamux.c

File Facts

System
Linux kernel
Corpus path
drivers/dma/stm32/stm32-dmamux.c
Extension
.c
Size
10653 bytes
Lines
410
Domain
Driver Families
Bucket
drivers/dma
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_dmamux {
	u32 master;
	u32 request;
	u32 chan_id;
};

struct stm32_dmamux_data {
	struct dma_router dmarouter;
	struct clk *clk;
	void __iomem *iomem;
	u32 dma_requests; /* Number of DMA requests connected to DMAMUX */
	u32 dmamux_requests; /* Number of DMA requests routed toward DMAs */
	spinlock_t lock; /* Protects register access */
	DECLARE_BITMAP(dma_inuse, STM32_DMAMUX_MAX_DMA_REQUESTS); /* Used DMA channel */
	u32 ccr[STM32_DMAMUX_MAX_DMA_REQUESTS]; /* Used to backup CCR register
						 * in suspend
						 */
	u32 dma_reqs[]; /* Number of DMA Request per DMA masters.
			 *  [0] holds number of DMA Masters.
			 *  To be kept at very end of this structure
			 */
};

static inline u32 stm32_dmamux_read(void __iomem *iomem, u32 reg)
{
	return readl_relaxed(iomem + reg);
}

static inline void stm32_dmamux_write(void __iomem *iomem, u32 reg, u32 val)
{
	writel_relaxed(val, iomem + reg);
}

static void stm32_dmamux_free(struct device *dev, void *route_data)
{
	struct stm32_dmamux_data *dmamux = dev_get_drvdata(dev);
	struct stm32_dmamux *mux = route_data;
	unsigned long flags;

	/* Clear dma request */
	spin_lock_irqsave(&dmamux->lock, flags);

	stm32_dmamux_write(dmamux->iomem, STM32_DMAMUX_CCR(mux->chan_id), 0);
	clear_bit(mux->chan_id, dmamux->dma_inuse);

	pm_runtime_put_sync(dev);

	spin_unlock_irqrestore(&dmamux->lock, flags);

	dev_dbg(dev, "Unmapping DMAMUX(%u) to DMA%u(%u)\n",
		mux->request, mux->master, mux->chan_id);

	kfree(mux);
}

static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec,
					 struct of_dma *ofdma)
{
	struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
	struct stm32_dmamux_data *dmamux = platform_get_drvdata(pdev);
	struct stm32_dmamux *mux;
	u32 i, min, max;
	int ret = -EINVAL;
	unsigned long flags;

	if (dma_spec->args_count != 3) {
		dev_err(&pdev->dev, "invalid number of dma mux args\n");
		goto err_put_pdev;
	}

	if (dma_spec->args[0] > dmamux->dmamux_requests) {
		dev_err(&pdev->dev, "invalid mux request number: %d\n",
			dma_spec->args[0]);
		goto err_put_pdev;
	}

	mux = kzalloc_obj(*mux);
	if (!mux) {
		ret = -ENOMEM;
		goto err_put_pdev;
	}

	spin_lock_irqsave(&dmamux->lock, flags);
	mux->chan_id = find_first_zero_bit(dmamux->dma_inuse,
					   dmamux->dma_requests);

	if (mux->chan_id == dmamux->dma_requests) {
		spin_unlock_irqrestore(&dmamux->lock, flags);
		dev_err(&pdev->dev, "Run out of free DMA requests\n");
		ret = -ENOMEM;

Annotation

Implementation Notes