drivers/dma/lpc18xx-dmamux.c

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

File Facts

System
Linux kernel
Corpus path
drivers/dma/lpc18xx-dmamux.c
Extension
.c
Size
4984 bytes
Lines
191
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 lpc18xx_dmamux {
	u32 value;
	bool busy;
};

struct lpc18xx_dmamux_data {
	struct dma_router dmarouter;
	struct lpc18xx_dmamux *muxes;
	u32 dma_master_requests;
	u32 dma_mux_requests;
	struct regmap *reg;
	spinlock_t lock;
};

static void lpc18xx_dmamux_free(struct device *dev, void *route_data)
{
	struct lpc18xx_dmamux_data *dmamux = dev_get_drvdata(dev);
	struct lpc18xx_dmamux *mux = route_data;
	unsigned long flags;

	spin_lock_irqsave(&dmamux->lock, flags);
	mux->busy = false;
	spin_unlock_irqrestore(&dmamux->lock, flags);
}

static void *lpc18xx_dmamux_reserve(struct of_phandle_args *dma_spec,
				    struct of_dma *ofdma)
{
	struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
	struct lpc18xx_dmamux_data *dmamux = platform_get_drvdata(pdev);
	unsigned long flags;
	unsigned mux;
	int ret = -EINVAL;

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

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

	if (dma_spec->args[1] > LPC18XX_DMAMUX_MAX_VAL) {
		dev_err(&pdev->dev, "invalid dma mux value: %d\n",
			dma_spec->args[1]);
		goto err_put_pdev;
	}

	/* The of_node_put() will be done in the core for the node */
	dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
	if (!dma_spec->np) {
		dev_err(&pdev->dev, "can't get dma master\n");
		goto err_put_pdev;
	}

	spin_lock_irqsave(&dmamux->lock, flags);
	if (dmamux->muxes[mux].busy) {
		spin_unlock_irqrestore(&dmamux->lock, flags);
		dev_err(&pdev->dev, "dma request %u busy with %u.%u\n",
			mux, mux, dmamux->muxes[mux].value);
		of_node_put(dma_spec->np);
		ret = -EBUSY;
		goto err_put_pdev;
	}

	dmamux->muxes[mux].busy = true;
	dmamux->muxes[mux].value = dma_spec->args[1];

	regmap_update_bits(dmamux->reg, LPC18XX_CREG_DMAMUX,
			   LPC18XX_DMAMUX_MASK(mux),
			   LPC18XX_DMAMUX_VAL(dmamux->muxes[mux].value, mux));
	spin_unlock_irqrestore(&dmamux->lock, flags);

	dma_spec->args[1] = dma_spec->args[2];
	dma_spec->args_count = 2;

	dev_dbg(&pdev->dev, "mapping dmamux %u.%u to dma request %u\n", mux,
		dmamux->muxes[mux].value, mux);

	put_device(&pdev->dev);

	return &dmamux->muxes[mux];

err_put_pdev:
	put_device(&pdev->dev);

Annotation

Implementation Notes