1 // SPDX-License-Identifier: GPL-2.0
3 * arch/sh/drivers/dma/dma-api.c
5 * SuperH-specific DMA management API
7 * Copyright (C) 2003, 2004, 2005 Paul Mundt
9 #include <linux/init.h>
10 #include <linux/module.h>
11 #include <linux/spinlock.h>
12 #include <linux/proc_fs.h>
13 #include <linux/seq_file.h>
14 #include <linux/list.h>
15 #include <linux/platform_device.h>
17 #include <linux/sched.h>
18 #include <linux/slab.h>
21 DEFINE_SPINLOCK(dma_spin_lock
);
22 static LIST_HEAD(registered_dmac_list
);
24 struct dma_info
*get_dma_info(unsigned int chan
)
26 struct dma_info
*info
;
29 * Look for each DMAC's range to determine who the owner of
32 list_for_each_entry(info
, ®istered_dmac_list
, list
) {
33 if ((chan
< info
->first_vchannel_nr
) ||
34 (chan
>= info
->first_vchannel_nr
+ info
->nr_channels
))
42 EXPORT_SYMBOL(get_dma_info
);
44 static unsigned int get_nr_channels(void)
46 struct dma_info
*info
;
49 if (unlikely(list_empty(®istered_dmac_list
)))
52 list_for_each_entry(info
, ®istered_dmac_list
, list
)
53 nr
+= info
->nr_channels
;
58 struct dma_channel
*get_dma_channel(unsigned int chan
)
60 struct dma_info
*info
= get_dma_info(chan
);
61 struct dma_channel
*channel
;
65 return ERR_PTR(-EINVAL
);
67 for (i
= 0; i
< info
->nr_channels
; i
++) {
68 channel
= &info
->channels
[i
];
69 if (channel
->vchan
== chan
)
75 EXPORT_SYMBOL(get_dma_channel
);
77 int get_dma_residue(unsigned int chan
)
79 struct dma_info
*info
= get_dma_info(chan
);
80 struct dma_channel
*channel
= get_dma_channel(chan
);
82 if (info
->ops
->get_residue
)
83 return info
->ops
->get_residue(channel
);
87 EXPORT_SYMBOL(get_dma_residue
);
89 int request_dma(unsigned int chan
, const char *dev_id
)
91 struct dma_channel
*channel
= { 0 };
92 struct dma_info
*info
= get_dma_info(chan
);
95 channel
= get_dma_channel(chan
);
96 if (atomic_xchg(&channel
->busy
, 1))
99 strscpy(channel
->dev_id
, dev_id
, sizeof(channel
->dev_id
));
101 if (info
->ops
->request
) {
102 result
= info
->ops
->request(channel
);
104 atomic_set(&channel
->busy
, 0);
111 EXPORT_SYMBOL(request_dma
);
113 void free_dma(unsigned int chan
)
115 struct dma_info
*info
= get_dma_info(chan
);
116 struct dma_channel
*channel
= get_dma_channel(chan
);
119 info
->ops
->free(channel
);
121 atomic_set(&channel
->busy
, 0);
123 EXPORT_SYMBOL(free_dma
);
125 void dma_wait_for_completion(unsigned int chan
)
127 struct dma_info
*info
= get_dma_info(chan
);
128 struct dma_channel
*channel
= get_dma_channel(chan
);
130 if (channel
->flags
& DMA_TEI_CAPABLE
) {
131 wait_event(channel
->wait_queue
,
132 (info
->ops
->get_residue(channel
) == 0));
136 while (info
->ops
->get_residue(channel
))
139 EXPORT_SYMBOL(dma_wait_for_completion
);
141 void dma_configure_channel(unsigned int chan
, unsigned long flags
)
143 struct dma_info
*info
= get_dma_info(chan
);
144 struct dma_channel
*channel
= get_dma_channel(chan
);
146 if (info
->ops
->configure
)
147 info
->ops
->configure(channel
, flags
);
149 EXPORT_SYMBOL(dma_configure_channel
);
151 int dma_xfer(unsigned int chan
, unsigned long from
,
152 unsigned long to
, size_t size
, unsigned int mode
)
154 struct dma_info
*info
= get_dma_info(chan
);
155 struct dma_channel
*channel
= get_dma_channel(chan
);
159 channel
->count
= size
;
160 channel
->mode
= mode
;
162 return info
->ops
->xfer(channel
);
164 EXPORT_SYMBOL(dma_xfer
);
166 static int dma_proc_show(struct seq_file
*m
, void *v
)
168 struct dma_info
*info
= v
;
170 if (list_empty(®istered_dmac_list
))
174 * Iterate over each registered DMAC
176 list_for_each_entry(info
, ®istered_dmac_list
, list
) {
180 * Iterate over each channel
182 for (i
= 0; i
< info
->nr_channels
; i
++) {
183 struct dma_channel
*channel
= info
->channels
+ i
;
185 if (!(channel
->flags
& DMA_CONFIGURED
))
188 seq_printf(m
, "%2d: %14s %s\n", i
,
189 info
->name
, channel
->dev_id
);
196 int register_dmac(struct dma_info
*info
)
198 unsigned int total_channels
, i
;
200 INIT_LIST_HEAD(&info
->list
);
202 printk(KERN_INFO
"DMA: Registering %s handler (%d channel%s).\n",
203 info
->name
, info
->nr_channels
, info
->nr_channels
> 1 ? "s" : "");
205 BUG_ON((info
->flags
& DMAC_CHANNELS_CONFIGURED
) && !info
->channels
);
207 info
->pdev
= platform_device_register_simple(info
->name
, -1,
209 if (IS_ERR(info
->pdev
))
210 return PTR_ERR(info
->pdev
);
213 * Don't touch pre-configured channels
215 if (!(info
->flags
& DMAC_CHANNELS_CONFIGURED
)) {
218 size
= sizeof(struct dma_channel
) * info
->nr_channels
;
220 info
->channels
= kzalloc(size
, GFP_KERNEL
);
225 total_channels
= get_nr_channels();
226 info
->first_vchannel_nr
= total_channels
;
227 for (i
= 0; i
< info
->nr_channels
; i
++) {
228 struct dma_channel
*chan
= &info
->channels
[i
];
230 atomic_set(&chan
->busy
, 0);
232 chan
->chan
= info
->first_channel_nr
+ i
;
233 chan
->vchan
= info
->first_channel_nr
+ i
+ total_channels
;
235 memcpy(chan
->dev_id
, "Unused", 7);
237 if (info
->flags
& DMAC_CHANNELS_TEI_CAPABLE
)
238 chan
->flags
|= DMA_TEI_CAPABLE
;
240 init_waitqueue_head(&chan
->wait_queue
);
241 dma_create_sysfs_files(chan
, info
);
244 list_add(&info
->list
, ®istered_dmac_list
);
248 EXPORT_SYMBOL(register_dmac
);
250 void unregister_dmac(struct dma_info
*info
)
254 for (i
= 0; i
< info
->nr_channels
; i
++)
255 dma_remove_sysfs_files(info
->channels
+ i
, info
);
257 if (!(info
->flags
& DMAC_CHANNELS_CONFIGURED
))
258 kfree(info
->channels
);
260 list_del(&info
->list
);
261 platform_device_unregister(info
->pdev
);
263 EXPORT_SYMBOL(unregister_dmac
);
265 static int __init
dma_api_init(void)
267 printk(KERN_NOTICE
"DMA: Registering DMA API.\n");
268 return proc_create_single("dma", 0, NULL
, dma_proc_show
) ? 0 : -ENOMEM
;
270 subsys_initcall(dma_api_init
);
272 MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
273 MODULE_DESCRIPTION("DMA API for SuperH");
274 MODULE_LICENSE("GPL v2");