2 * DMA Router driver for LPC18xx/43xx DMA MUX
4 * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
6 * Based on TI DMA Crossbar driver by:
7 * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
8 * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
16 #include <linux/err.h>
17 #include <linux/init.h>
18 #include <linux/mfd/syscon.h>
19 #include <linux/of_device.h>
20 #include <linux/of_dma.h>
21 #include <linux/regmap.h>
22 #include <linux/spinlock.h>
24 /* CREG register offset and macros for mux manipulation */
25 #define LPC18XX_CREG_DMAMUX 0x11c
26 #define LPC18XX_DMAMUX_VAL(v, n) ((v) << (n * 2))
27 #define LPC18XX_DMAMUX_MASK(n) (0x3 << (n * 2))
28 #define LPC18XX_DMAMUX_MAX_VAL 0x3
30 struct lpc18xx_dmamux
{
35 struct lpc18xx_dmamux_data
{
36 struct dma_router dmarouter
;
37 struct lpc18xx_dmamux
*muxes
;
38 u32 dma_master_requests
;
44 static void lpc18xx_dmamux_free(struct device
*dev
, void *route_data
)
46 struct lpc18xx_dmamux_data
*dmamux
= dev_get_drvdata(dev
);
47 struct lpc18xx_dmamux
*mux
= route_data
;
50 spin_lock_irqsave(&dmamux
->lock
, flags
);
52 spin_unlock_irqrestore(&dmamux
->lock
, flags
);
55 static void *lpc18xx_dmamux_reserve(struct of_phandle_args
*dma_spec
,
58 struct platform_device
*pdev
= of_find_device_by_node(ofdma
->of_node
);
59 struct lpc18xx_dmamux_data
*dmamux
= platform_get_drvdata(pdev
);
63 if (dma_spec
->args_count
!= 3) {
64 dev_err(&pdev
->dev
, "invalid number of dma mux args\n");
65 return ERR_PTR(-EINVAL
);
68 mux
= dma_spec
->args
[0];
69 if (mux
>= dmamux
->dma_master_requests
) {
70 dev_err(&pdev
->dev
, "invalid mux number: %d\n",
72 return ERR_PTR(-EINVAL
);
75 if (dma_spec
->args
[1] > LPC18XX_DMAMUX_MAX_VAL
) {
76 dev_err(&pdev
->dev
, "invalid dma mux value: %d\n",
78 return ERR_PTR(-EINVAL
);
81 /* The of_node_put() will be done in the core for the node */
82 dma_spec
->np
= of_parse_phandle(ofdma
->of_node
, "dma-masters", 0);
84 dev_err(&pdev
->dev
, "can't get dma master\n");
85 return ERR_PTR(-EINVAL
);
88 spin_lock_irqsave(&dmamux
->lock
, flags
);
89 if (dmamux
->muxes
[mux
].busy
) {
90 spin_unlock_irqrestore(&dmamux
->lock
, flags
);
91 dev_err(&pdev
->dev
, "dma request %u busy with %u.%u\n",
92 mux
, mux
, dmamux
->muxes
[mux
].value
);
93 of_node_put(dma_spec
->np
);
94 return ERR_PTR(-EBUSY
);
97 dmamux
->muxes
[mux
].busy
= true;
98 dmamux
->muxes
[mux
].value
= dma_spec
->args
[1];
100 regmap_update_bits(dmamux
->reg
, LPC18XX_CREG_DMAMUX
,
101 LPC18XX_DMAMUX_MASK(mux
),
102 LPC18XX_DMAMUX_VAL(dmamux
->muxes
[mux
].value
, mux
));
103 spin_unlock_irqrestore(&dmamux
->lock
, flags
);
105 dma_spec
->args
[1] = dma_spec
->args
[2];
106 dma_spec
->args_count
= 2;
108 dev_dbg(&pdev
->dev
, "mapping dmamux %u.%u to dma request %u\n", mux
,
109 dmamux
->muxes
[mux
].value
, mux
);
111 return &dmamux
->muxes
[mux
];
114 static int lpc18xx_dmamux_probe(struct platform_device
*pdev
)
116 struct device_node
*dma_np
, *np
= pdev
->dev
.of_node
;
117 struct lpc18xx_dmamux_data
*dmamux
;
120 dmamux
= devm_kzalloc(&pdev
->dev
, sizeof(*dmamux
), GFP_KERNEL
);
124 dmamux
->reg
= syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg");
125 if (IS_ERR(dmamux
->reg
)) {
126 dev_err(&pdev
->dev
, "syscon lookup failed\n");
127 return PTR_ERR(dmamux
->reg
);
130 ret
= of_property_read_u32(np
, "dma-requests",
131 &dmamux
->dma_mux_requests
);
133 dev_err(&pdev
->dev
, "missing dma-requests property\n");
137 dma_np
= of_parse_phandle(np
, "dma-masters", 0);
139 dev_err(&pdev
->dev
, "can't get dma master\n");
143 ret
= of_property_read_u32(dma_np
, "dma-requests",
144 &dmamux
->dma_master_requests
);
147 dev_err(&pdev
->dev
, "missing master dma-requests property\n");
151 dmamux
->muxes
= devm_kcalloc(&pdev
->dev
, dmamux
->dma_master_requests
,
152 sizeof(struct lpc18xx_dmamux
),
157 spin_lock_init(&dmamux
->lock
);
158 platform_set_drvdata(pdev
, dmamux
);
159 dmamux
->dmarouter
.dev
= &pdev
->dev
;
160 dmamux
->dmarouter
.route_free
= lpc18xx_dmamux_free
;
162 return of_dma_router_register(np
, lpc18xx_dmamux_reserve
,
166 static const struct of_device_id lpc18xx_dmamux_match
[] = {
167 { .compatible
= "nxp,lpc1850-dmamux" },
171 static struct platform_driver lpc18xx_dmamux_driver
= {
172 .probe
= lpc18xx_dmamux_probe
,
174 .name
= "lpc18xx-dmamux",
175 .of_match_table
= lpc18xx_dmamux_match
,
179 static int __init
lpc18xx_dmamux_init(void)
181 return platform_driver_register(&lpc18xx_dmamux_driver
);
183 arch_initcall(lpc18xx_dmamux_init
);