1 // SPDX-License-Identifier: GPL-2.0-only
3 * DMA Router driver for LPC18xx/43xx DMA MUX
5 * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
7 * Based on TI DMA Crossbar driver by:
8 * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
9 * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
12 #include <linux/err.h>
13 #include <linux/init.h>
14 #include <linux/mfd/syscon.h>
15 #include <linux/of_device.h>
16 #include <linux/of_dma.h>
17 #include <linux/regmap.h>
18 #include <linux/spinlock.h>
20 /* CREG register offset and macros for mux manipulation */
21 #define LPC18XX_CREG_DMAMUX 0x11c
22 #define LPC18XX_DMAMUX_VAL(v, n) ((v) << (n * 2))
23 #define LPC18XX_DMAMUX_MASK(n) (0x3 << (n * 2))
24 #define LPC18XX_DMAMUX_MAX_VAL 0x3
26 struct lpc18xx_dmamux
{
31 struct lpc18xx_dmamux_data
{
32 struct dma_router dmarouter
;
33 struct lpc18xx_dmamux
*muxes
;
34 u32 dma_master_requests
;
40 static void lpc18xx_dmamux_free(struct device
*dev
, void *route_data
)
42 struct lpc18xx_dmamux_data
*dmamux
= dev_get_drvdata(dev
);
43 struct lpc18xx_dmamux
*mux
= route_data
;
46 spin_lock_irqsave(&dmamux
->lock
, flags
);
48 spin_unlock_irqrestore(&dmamux
->lock
, flags
);
51 static void *lpc18xx_dmamux_reserve(struct of_phandle_args
*dma_spec
,
54 struct platform_device
*pdev
= of_find_device_by_node(ofdma
->of_node
);
55 struct lpc18xx_dmamux_data
*dmamux
= platform_get_drvdata(pdev
);
59 if (dma_spec
->args_count
!= 3) {
60 dev_err(&pdev
->dev
, "invalid number of dma mux args\n");
61 return ERR_PTR(-EINVAL
);
64 mux
= dma_spec
->args
[0];
65 if (mux
>= dmamux
->dma_master_requests
) {
66 dev_err(&pdev
->dev
, "invalid mux number: %d\n",
68 return ERR_PTR(-EINVAL
);
71 if (dma_spec
->args
[1] > LPC18XX_DMAMUX_MAX_VAL
) {
72 dev_err(&pdev
->dev
, "invalid dma mux value: %d\n",
74 return ERR_PTR(-EINVAL
);
77 /* The of_node_put() will be done in the core for the node */
78 dma_spec
->np
= of_parse_phandle(ofdma
->of_node
, "dma-masters", 0);
80 dev_err(&pdev
->dev
, "can't get dma master\n");
81 return ERR_PTR(-EINVAL
);
84 spin_lock_irqsave(&dmamux
->lock
, flags
);
85 if (dmamux
->muxes
[mux
].busy
) {
86 spin_unlock_irqrestore(&dmamux
->lock
, flags
);
87 dev_err(&pdev
->dev
, "dma request %u busy with %u.%u\n",
88 mux
, mux
, dmamux
->muxes
[mux
].value
);
89 of_node_put(dma_spec
->np
);
90 return ERR_PTR(-EBUSY
);
93 dmamux
->muxes
[mux
].busy
= true;
94 dmamux
->muxes
[mux
].value
= dma_spec
->args
[1];
96 regmap_update_bits(dmamux
->reg
, LPC18XX_CREG_DMAMUX
,
97 LPC18XX_DMAMUX_MASK(mux
),
98 LPC18XX_DMAMUX_VAL(dmamux
->muxes
[mux
].value
, mux
));
99 spin_unlock_irqrestore(&dmamux
->lock
, flags
);
101 dma_spec
->args
[1] = dma_spec
->args
[2];
102 dma_spec
->args_count
= 2;
104 dev_dbg(&pdev
->dev
, "mapping dmamux %u.%u to dma request %u\n", mux
,
105 dmamux
->muxes
[mux
].value
, mux
);
107 return &dmamux
->muxes
[mux
];
110 static int lpc18xx_dmamux_probe(struct platform_device
*pdev
)
112 struct device_node
*dma_np
, *np
= pdev
->dev
.of_node
;
113 struct lpc18xx_dmamux_data
*dmamux
;
116 dmamux
= devm_kzalloc(&pdev
->dev
, sizeof(*dmamux
), GFP_KERNEL
);
120 dmamux
->reg
= syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg");
121 if (IS_ERR(dmamux
->reg
)) {
122 dev_err(&pdev
->dev
, "syscon lookup failed\n");
123 return PTR_ERR(dmamux
->reg
);
126 ret
= of_property_read_u32(np
, "dma-requests",
127 &dmamux
->dma_mux_requests
);
129 dev_err(&pdev
->dev
, "missing dma-requests property\n");
133 dma_np
= of_parse_phandle(np
, "dma-masters", 0);
135 dev_err(&pdev
->dev
, "can't get dma master\n");
139 ret
= of_property_read_u32(dma_np
, "dma-requests",
140 &dmamux
->dma_master_requests
);
143 dev_err(&pdev
->dev
, "missing master dma-requests property\n");
147 dmamux
->muxes
= devm_kcalloc(&pdev
->dev
, dmamux
->dma_master_requests
,
148 sizeof(struct lpc18xx_dmamux
),
153 spin_lock_init(&dmamux
->lock
);
154 platform_set_drvdata(pdev
, dmamux
);
155 dmamux
->dmarouter
.dev
= &pdev
->dev
;
156 dmamux
->dmarouter
.route_free
= lpc18xx_dmamux_free
;
158 return of_dma_router_register(np
, lpc18xx_dmamux_reserve
,
162 static const struct of_device_id lpc18xx_dmamux_match
[] = {
163 { .compatible
= "nxp,lpc1850-dmamux" },
167 static struct platform_driver lpc18xx_dmamux_driver
= {
168 .probe
= lpc18xx_dmamux_probe
,
170 .name
= "lpc18xx-dmamux",
171 .of_match_table
= lpc18xx_dmamux_match
,
175 static int __init
lpc18xx_dmamux_init(void)
177 return platform_driver_register(&lpc18xx_dmamux_driver
);
179 arch_initcall(lpc18xx_dmamux_init
);