drivers/dma/dw/rzn1-dmamux.c

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

File Facts

System
Linux kernel
Corpus path
drivers/dma/dw/rzn1-dmamux.c
Extension
.c
Size
4300 bytes
Lines
170
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 rzn1_dmamux_data {
	struct dma_router dmarouter;
	DECLARE_BITMAP(used_chans, 2 * RZN1_DMAMUX_LINES_PER_CTLR);
};

struct rzn1_dmamux_map {
	unsigned int req_idx;
};

static void rzn1_dmamux_free(struct device *dev, void *route_data)
{
	struct rzn1_dmamux_data *dmamux = dev_get_drvdata(dev);
	struct rzn1_dmamux_map *map = route_data;

	dev_dbg(dev, "Unmapping DMAMUX request %u\n", map->req_idx);

	clear_bit(map->req_idx, dmamux->used_chans);

	kfree(map);
}

static void *rzn1_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 rzn1_dmamux_data *dmamux = platform_get_drvdata(pdev);
	struct rzn1_dmamux_map *map;
	unsigned int dmac_idx, chan, val;
	u32 mask;
	int ret;

	if (dma_spec->args_count != RNZ1_DMAMUX_NCELLS) {
		ret = -EINVAL;
		goto put_device;
	}

	map = kzalloc_obj(*map);
	if (!map) {
		ret = -ENOMEM;
		goto put_device;
	}

	chan = dma_spec->args[0];
	map->req_idx = dma_spec->args[4];
	val = dma_spec->args[5];
	dma_spec->args_count -= 2;

	if (chan >= RZN1_DMAMUX_LINES_PER_CTLR) {
		dev_err(&pdev->dev, "Invalid DMA request line: %u\n", chan);
		ret = -EINVAL;
		goto free_map;
	}

	if (map->req_idx >= RZN1_DMAMUX_MAX_LINES ||
	    (map->req_idx % RZN1_DMAMUX_LINES_PER_CTLR) != chan) {
		dev_err(&pdev->dev, "Invalid MUX request line: %u\n", map->req_idx);
		ret = -EINVAL;
		goto free_map;
	}

	dmac_idx = map->req_idx >= RZN1_DMAMUX_LINES_PER_CTLR ? 1 : 0;
	dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", dmac_idx);
	if (!dma_spec->np) {
		dev_err(&pdev->dev, "Can't get DMA master\n");
		ret = -EINVAL;
		goto free_map;
	}

	dev_dbg(&pdev->dev, "Mapping DMAMUX request %u to DMAC%u request %u\n",
		map->req_idx, dmac_idx, chan);

	if (test_and_set_bit(map->req_idx, dmamux->used_chans)) {
		ret = -EBUSY;
		goto put_dma_spec_np;
	}

	mask = BIT(map->req_idx);
	ret = r9a06g032_sysctrl_set_dmamux(mask, val ? mask : 0);
	if (ret)
		goto clear_bitmap;

	put_device(&pdev->dev);
	return map;

clear_bitmap:
	clear_bit(map->req_idx, dmamux->used_chans);
put_dma_spec_np:
	of_node_put(dma_spec->np);
free_map:
	kfree(map);

Annotation

Implementation Notes