1 /**
2  * \file
3  *
4  * \brief Direct Memory Access Controller Driver for SAMB
5  *
6  * Copyright (C) 2015-2016 Atmel Corporation. All rights reserved.
7  *
8  * \asf_license_start
9  *
10  * \page License
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright notice,
16  *    this list of conditions and the following disclaimer.
17  *
18  * 2. Redistributions in binary form must reproduce the above copyright notice,
19  *    this list of conditions and the following disclaimer in the documentation
20  *    and/or other materials provided with the distribution.
21  *
22  * 3. The name of Atmel may not be used to endorse or promote products derived
23  *    from this software without specific prior written permission.
24  *
25  * 4. This software may only be redistributed and used in connection with an
26  *    Atmel microcontroller product.
27  *
28  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  *
40  * \asf_license_stop
41  *
42  */
43 /*
44  * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
45  */
46 #ifndef DMA_H_INCLUDED
47 #define DMA_H_INCLUDED
48 
49 #ifdef __cplusplus
50 extern "C" {
51 #endif
52 
53 /**
54  * \defgroup asfdoc_samb_dma_group SAM Direct Memory Access Controller Driver (DMAC)
55  *
56  * This driver for Atmel&reg; | SMART SAM devices provides an interface for the configuration
57  * and management of the Direct Memory Access Controller(DMAC) module within
58  * the device. The DMAC can transfer data between memories and peripherals, and
59  * thus off-load these tasks from the CPU. The module supports peripheral to
60  * peripheral, peripheral to memory, memory to peripheral, and memory to memory
61  * transfers.
62  *
63  * The following peripherals are used by the DMAC Driver:
64  * - DMAC (Direct Memory Access Controller)
65  *
66  * The following devices can use this module:
67  *  - Atmel | SMART SAM B11
68  *
69  * The outline of this documentation is as follows:
70  * - \ref asfdoc_samb_dma_prerequisites
71  * - \ref asfdoc_samb_dma_module_overview
72  * - \ref asfdoc_samb_dma_special_considerations
73  * - \ref asfdoc_samb_dma_extra_info
74  * - \ref asfdoc_samb_dma_examples
75  * - \ref asfdoc_samb_dma_api_overview
76  *
77  *
78  * \section asfdoc_samb_dma_prerequisites Prerequisites
79  *
80  * There are no prerequisites for this module.
81  *
82  *
83  * \section asfdoc_samb_dma_module_overview Module Overview
84  *
85  * SAM devices with DMAC enables high data transfer rates with minimum
86  * CPU intervention and frees up CPU time. With access to all peripherals,
87  * the DMAC can handle automatic transfer of data to/from modules.
88  * It supports static and incremental addressing for both source and
89  * destination.
90  *
91  * The DMAC when used with peripheral triggers, provides a
92  * considerable advantage by reducing the power consumption and performing
93  * data transfer in the background.
94  * The CPU can remain in sleep during this time to reduce power consumption.
95  *
96  * <table>
97  *    <tr>
98  *      <th>Device</th>
99  *      <th>Dma channel number</th>
100  *    </tr>
101  *    <tr>
102  *      <td>SAMB11</td>
103  *      <td>4</td>
104  *    </tr>
105  * </table>
106  * The DMA channel operation can be suspended at any time by software,
107  * or after selectable descriptor execution. The DMAC driver for SAM
108  * supports four types of transfers such as peripheral to peripheral,
109  * peripheral to memory, memory to peripheral, and memory to memory.
110  *
111  * The basic transfer unit is a beat which is defined as a single bus access.
112  * There can be multiple beats in a single block transfer and multiple block
113  * transfers in a DMA transaction.
114  * DMA transfer is based on descriptors, which holds transfer properties
115  * such as the source and destination addresses, transfer counter, and other
116  * additional transfer control information.
117  * The descriptors can be static or linked. When static, a single block transfer
118  * is performed. When linked, a number of transfer descriptors can be used to
119  * enable multiple block transfers within a single DMA transaction.
120  *
121  * The implementation of the DMA driver is based on the idea that DMA channel
122  * is a finite resource of entities with the same abilities. A DMA channel resource
123  * is able to move a defined set of data from a source address to destination
124  * address triggered by a transfer trigger. On the SAM devices there are 12
125  * DMA resources available for allocation. Each of these DMA resources can trigger
126  * interrupt callback routines.
127  * The other main features are:
128  *
129  * - Selectable transfer trigger source
130  *  - Software
131  *  - Peripheral
132  * - Tree level channel priority
133  *  - Normal level
134  *  - High level
135  *  - Top level
136  * - Optional interrupt generation on transfer complete, channel error
137  * - Supports multi-buffer or circular buffer mode by linking multiple descriptors
138  * - Beat size configurable as 8-bit, 16-bit, or 32-bit
139  *
140  * A simplified block diagram of the DMA Resource can be seen in
141  * \ref asfdoc_samb_dma_module_block_diagram "the figure below".
142  *
143  * \anchor asfdoc_samb_dma_module_block_diagram
144  * \dot
145  * digraph overview {
146  * splines = false;
147  * rankdir=LR;
148  *
149  * mux1 [label="Transfer Trigger", shape=box];
150  *
151  * dma [label="DMA Channel", shape=polygon, sides=6, orientation=60, style=filled, fillcolor=darkolivegreen1, height=1, width=1];
152  * descriptor [label="Transfer Descriptor", shape=box, style=filled, fillcolor=lightblue];
153  *
154  * mux1 -> dma;
155  * descriptor -> dma;
156  *
157  * interrupt [label="Interrupt", shape=box];
158  * events [label="Events", shape=box];
159  *
160  * dma:e -> interrupt:w;
161  * dma:e -> events:w;
162  *
163  * {rank=same; descriptor dma}
164  *
165  * }
166  * \enddot
167  *
168  * \subsection asfdoc_samb_dma_module_overview_dma_channels DMA Channels
169  * The DMAC in each device consists of several DMA channels, which
170  * along with the transfer descriptors defines the data transfer properties.
171  * - The transfer control descriptor defines the source and destination
172  * addresses, source and destination address increment settings, the
173  * block transfer count
174  * - Dedicated channel registers control the peripheral trigger source,
175  * trigger mode settings, and channel priority level settings
176  *
177  * With a successful DMA resource allocation, a dedicated
178  * DMA channel will be assigned. The channel will be occupied until the
179  * DMA resource is freed. A DMA resource handle is used to identify the specific
180  * DMA resource.
181  * When there are multiple channels with active requests, the arbiter prioritizes
182  * the channels requesting access to the bus.
183  *
184  * \subsection asfdoc_samb_dma_module_overview_dma_trigger DMA Triggers
185  * DMA transfer can be started only when a DMA transfer request is acknowledged/granted by the arbiter. A
186  * transfer request can be triggered from software, peripheral. There
187  * are dedicated source trigger selections for each DMA channel usage.
188  *
189  * \subsection asfdoc_samb_dma_module_overview_dma_transfer_descriptor DMA Transfer Descriptor
190  * The transfer descriptor resides in the SRAM and
191  * defines these channel properties.
192  *
193  * <table>
194  *   <tr>
195  *     <th>Field name</th>
196  *     <th>Field width</th>
197  *   </tr>
198  *   <tr>
199  *     <td>Source Address</td>
200  *     <td>32 bits</td>
201  *   </tr>
202  *   <tr>
203  *     <td>Destination Address</td>
204  *     <td>32 bits</td>
205  *   </tr>
206  *   <tr>
207  *     <td>Block Transfer Counter</td>
208  *     <td>32 bits</td>
209  *   </tr>
210  *   <tr>
211  *     <td>Descriptor Next Address</td>
212  *     <td>30 bits</td>
213  *   </tr>
214  *   <tr>
215  *     <td>Block Transfer Interrupt</td>
216  *     <td>1 bit</td>
217  *   </tr>
218  *   <tr>
219  *     <td>Block Transfer Stop Control</td>
220  *     <td>1 bit</td>
221  *   </tr>
222  * </table>
223  *
224  * Before starting a transfer, at least one descriptor should be configured.
225  * After a successful allocation of a DMA channel, the transfer descriptor can
226  * be added with a call to \ref dma_add_descriptor(). If there is a transfer
227  * descriptor already allocated to the DMA resource, the descriptor will
228  * be linked to the next descriptor address.
229  *
230  * \subsection asfdoc_samb_dma_module_overview_dma_output DMA Interrupts
231  * Both an interrupt callback and an peripheral can be triggered by the
232  * DMA transfer. Three types of callbacks are supported by the DMA driver:
233  * transfer complete, channel suspend, and transfer error. Each of these callback
234  * types can be registered and enabled for each channel independently through
235  * the DMA driver API.
236  *
237  *
238  * \section asfdoc_samb_dma_special_considerations Special Considerations
239  *
240  * There are no special considerations for this module.
241  *
242  *
243  * \section asfdoc_samb_dma_extra_info Extra Information
244  *
245  * For extra information, see \ref asfdoc_samb_dma_extra. This includes:
246  * - \ref asfdoc_samb_dma_extra_acronyms
247  * - \ref asfdoc_samb_dma_extra_dependencies
248  * - \ref asfdoc_samb_dma_extra_errata
249  * - \ref asfdoc_samb_dma_extra_history
250  *
251  *
252  * \section asfdoc_samb_dma_examples Examples
253  *
254  * For a list of examples related to this driver, see
255  * \ref asfdoc_samb_dma_exqsg.
256  *
257  *
258  * \section asfdoc_samb_dma_api_overview API Overview
259  * @{
260  */
261 
262 #include <compiler.h>
263 #include <system_sam_b.h>
264 #include "conf_dma.h"
265 
266 /** DMA IRQn number. */
267 #define PROV_DMA_CTRL0_IRQn		15
268 
269 /** DMA invalid channel number. */
270 #define DMA_INVALID_CHANNEL        0xff
271 
272 /** DMA peripheral index */
273 enum dma_peripheral_index {
274 	MEMORY_DMA_PERIPHERAL = 0,
275 	UART0RX_DMA_PERIPHERAL,
276 	UART0TX_DMA_PERIPHERAL,
277 	UART1RX_DMA_PERIPHERAL,
278 	UART1TX_DMA_PERIPHERAL,
279 	SPI0RX_DMA_PERIPHERAL,
280 	SPI0TX_DMA_PERIPHERAL,
281 	SPI1RX_DMA_PERIPHERAL,
282 	SPI1TX_DMA_PERIPHERAL,
283 	I2C0RX_DMA_PERIPHERAL,
284 	I2C0TX_DMA_PERIPHERAL,
285 	I2C1RX_DMA_PERIPHERAL,
286 	I2C1TX_DMA_PERIPHERAL,
287 	DUALTIMER0_DMA_PERIPHERAL = 15,
288 	TIMER0_DMA_PERIPHERAL,
289 };
290 
291 /** DMA channel index */
292 enum dma_ch_index {
293 	/** DMA channel 0 */
294 	DMA_CHANNEL_0 = 0,
295 	/** DMA channel 1 */
296 	DMA_CHANNEL_1,
297 	/** DMA channel 2 */
298 	DMA_CHANNEL_2,
299 	/** DMA channel 3 */
300 	DMA_CHANNEL_3,
301 };
302 
303 enum dma_endian_swap {
304 	/** DMA endian no swap */
305 	DMA_ENDIAN_NO_SWAP,
306 	/** DMA endian 16-bit */
307 	DMA_ENDIAN_SIZE_16,
308 	/** DMA endian 32-bit */
309 	DMA_ENDIAN_SIZE_32,
310 	/** DMA endian 64-bit */
311 	DMA_ENDIAN_SIZE_64,
312 };
313 
314 /**
315  * Callback types for DMA callback driver.
316  */
317 enum dma_callback_type {
318 	/** Callback for transfer complete */
319 	DMA_CALLBACK_TRANSFER_DONE,
320 	/** AHB read slave error */
321 	DMA_CALLBACK_READ_ERR,
322 	/**  AHB write slave error */
323 	DMA_CALLBACK_WRITE_ERR,
324 	/** FIFO has been overflown */
325 	DMA_CALLBACK_FIFO_OVERFLOW,
326 	/** FIFO has been underflows */
327 	DMA_CALLBACK_FIFO_UNDERFLOW,
328 	/** Read timeout on AHB bus (timeout value fixed at 1024 cycles) */
329 	DMA_CALLBACK_READ_TIMEOUT,
330 	/** Write timeout on AHB bus (timeout value fixed at 1024 cycles) */
331 	DMA_CALLBACK_WRITE_TIMEOUT,
332 	/** Channel active but did not start a burst for 2048 cycles */
333 	DMA_CALLBACK_WDT_TRIGGER,
334 	/** Number of available callbacks */
335 	DMA_CALLBACK_N,
336 };
337 
338 /**
339  * DMA transfer descriptor configuration. When the source or destination address
340  * increment is enabled, the addresses stored into the configuration structure
341  * must correspond to the end of the transfer.
342  */
343 struct dma_descriptor {
344 	/** Start address of read buffer */
345 	uint32_t read_start_addr;
346 	/** Start address of write buffer */
347 	uint32_t write_start_addr;
348 	/** Size (in bytes) of buffer to transfer */
349 	uint32_t buffer_size;
350 	union {
351 		struct {
352 			/** Active high interrupt enable once buffer has been transferred */
353 			uint32_t set_interrupt:1;
354 			/** If set, channel stops when buffer done, otherwise load from cmd_next_addr */
355 			uint32_t last:1;
356 			/** Address of next command if cmd_last is not set */
357 			uint32_t next_addr:30;
358 		} cmd;
359 		uint32_t next;
360 	};
361 };
362 /** Structure for DMA source/description */
363 struct dma_config {
364 	/** Maximum number of bytes of an AHB read/write burst */
365 	uint8_t max_burst;
366 	/** Number of AHB read/write commands to issue before channel is released */
367 	uint8_t tokens;
368 	/** If true, the controller will increment the next burst address */
369 	bool enable_inc_addr;
370 	/** Index of peripheral to read/write from (0 if memory or no peripheral flow control) */
371 	enum dma_peripheral_index periph;
372 	/**
373 	 * Number of cycles to wait for read/write request signal to update
374 	 * after issuing the read/write clear signal
375 	 */
376 	uint8_t periph_delay;
377 	/** Top priority enable */
378 	bool enable_proi_top;
379 	/** Top priority channel index */
380 	uint8_t proi_top_index;
381 	/** High priority enable */
382 	bool enable_proi_high;
383 	/** High priority channel index */
384 	uint8_t proi_high_index;
385 };
386 
387 /** Structure for DMA transfer resource */
388 struct dma_resource_config {
389 	struct dma_config src;
390 	struct dma_config des;
391 	/** If true, channel will work in joint mode */
392 	bool enable_joint_mode;
393 	/** Endian Byte Swapping */
394 	enum dma_endian_swap swap;
395 };
396 
397 /** Forward definition of the DMA resource */
398 struct dma_resource;
399 /** Type definition for a DMA resource callback function */
400 typedef void (*dma_callback_t)(struct dma_resource *const resource);
401 
402 /** Structure for DMA transfer resource */
403 struct dma_resource {
404 	/** Allocated DMA channel ID */
405 	uint8_t channel_id;
406 	/** Array of callback functions for DMA transfer job */
407 	dma_callback_t callback[DMA_CALLBACK_N];
408 	/** Bit mask for enabled callbacks */
409 	uint8_t callback_enable;
410 	/** Status of the last job */
411 	volatile enum status_code job_status;
412 	/** Transferred data size */
413 	uint32_t transfered_size;
414 	/** DMA transfer descriptor */
415 	struct dma_descriptor* descriptor;
416 };
417 
418 /**
419  * \brief Get DMA resource status.
420  *
421  * \param[in] resource Pointer to the DMA resource
422  *
423  * \return Status of the DMA resource.
424  */
dma_get_job_status(struct dma_resource * resource)425 static inline enum status_code dma_get_job_status(struct dma_resource *resource)
426 {
427 	return resource->job_status;
428 }
429 
430 /**
431  * \brief Enable a callback function for a dedicated DMA resource.
432  *
433  * \param[in] resource Pointer to the DMA resource
434  * \param[in] type Callback function type
435  *
436  */
dma_enable_callback(struct dma_resource * resource,enum dma_callback_type type)437 static inline void dma_enable_callback(struct dma_resource *resource,
438 		enum dma_callback_type type)
439 {
440 	resource->callback_enable |= 1 << type;
441 }
442 
443 /**
444  * \brief Disable a callback function for a dedicated DMA resource.
445  *
446  * \param[in] resource Pointer to the DMA resource
447  * \param[in] type Callback function type
448  *
449  */
dma_disable_callback(struct dma_resource * resource,enum dma_callback_type type)450 static inline void dma_disable_callback(struct dma_resource *resource,
451 		enum dma_callback_type type)
452 {
453 	resource->callback_enable &= ~(1 << type);
454 }
455 
456 /**
457  * \brief Register a callback function for a dedicated DMA resource.
458  *
459  * There are three types of callback functions, which can be registered:
460  * - Callback for transfer complete
461  * - Callback for transfer error
462  * - Callback for channel suspend
463  *
464  * \param[in] resource Pointer to the DMA resource
465  * \param[in] callback Pointer to the callback function
466  * \param[in] type Callback function type
467  *
468  */
dma_register_callback(struct dma_resource * resource,dma_callback_t callback,enum dma_callback_type type)469 static inline void dma_register_callback(struct dma_resource *resource,
470 		dma_callback_t callback, enum dma_callback_type type)
471 {
472 	resource->callback[type] = callback;
473 }
474 
475 /**
476  * \brief Unregister a callback function for a dedicated DMA resource.
477  *
478  * There are three types of callback functions:
479  * - Callback for transfer complete
480  * - Callback for transfer error
481  * - Callback for channel suspend
482  *
483  * The application can unregister any of the callback functions which
484  * are already registered and are no longer needed.
485  *
486  * \param[in] resource Pointer to the DMA resource
487  * \param[in] type Callback function type
488  *
489  */
dma_unregister_callback(struct dma_resource * resource,enum dma_callback_type type)490 static inline void dma_unregister_callback(struct dma_resource *resource,
491 		enum dma_callback_type type)
492 {
493 	resource->callback[type] = NULL;
494 }
495 
496 /**
497  * \brief Initializes DMA transfer configuration with predefined default values.
498  *
499  * This function will initialize a given DMA descriptor configuration structure to
500  * a set of known default values. This function should be called on
501  * any new instance of the configuration structure before being
502  * modified by the user application.
503  *
504  * The default configuration is as follows:
505  *  \li Set the read start address as 0
506  *  \li Set the write start address as 0
507  *  \li Set buffer size as 1
508  *  \li Set beat size as byte
509  *  \li Enable the interrupt
510  *  \li Enable the channel stops when buffer done
511  *  \li Set next command address to 0
512  * \param[out] config Pointer to the configuration
513  *
514  */
dma_descriptor_get_config_defaults(struct dma_descriptor * config)515 static inline void dma_descriptor_get_config_defaults(struct dma_descriptor *config)
516 {
517 	/* Default read buffer size is set to 0 */
518 	config->read_start_addr = 0;
519 	/* Default write buffer size is set to 0 */
520 	config->write_start_addr = 0;
521 	/* Set beat size to one byte */
522 	config->buffer_size = 1;
523 	/* Enable transferred interrupt */
524 	config->cmd.set_interrupt = 1;
525 	/* Channel stops when buffer done */
526 	config->cmd.last = 1;
527 	/* Set next command to 0 */
528 	config->cmd.next_addr = 0;
529 }
530 
531 /**
532  * \brief Update DMA descriptor.
533  *
534  * This function can update the descriptor of an allocated DMA resource.
535  *
536  */
dma_update_descriptor(struct dma_resource * resource,struct dma_descriptor * descriptor)537 static inline void dma_update_descriptor(struct dma_resource *resource,
538 		struct dma_descriptor* descriptor)
539 {
540 	resource->descriptor = descriptor;
541 }
542 
543 /**
544  * \brief Reset DMA descriptor.
545  *
546  * This function will clear the DESCADDR register of an allocated DMA resource.
547  *
548  */
dma_reset_descriptor(struct dma_resource * resource)549 static inline void dma_reset_descriptor(struct dma_resource *resource)
550 {
551 	resource->descriptor = NULL;
552 }
553 
554 void dma_get_config_defaults(struct dma_resource_config *config);
555 enum status_code dma_allocate(struct dma_resource *resource,
556 		struct dma_resource_config *config);
557 enum status_code dma_add_descriptor(struct dma_resource *resource,
558 		struct dma_descriptor* descriptor);
559 enum status_code dma_start_transfer_job(struct dma_resource *resource);
560 enum status_code dma_free(struct dma_resource *resource);
561 uint8_t dma_get_status(uint8_t channel);
562 uint8_t dma_get_interrupt_status(uint8_t channel);
563 void dma_clear_interrupt_status(uint8_t channel, uint8_t flag);
564 /** @} */
565 
566 /**
567  * \page asfdoc_samb_dma_extra Extra Information for DMAC Driver
568  *
569  * \section asfdoc_samb_dma_extra_acronyms Acronyms
570  * Below is a table listing the acronyms used in this module, along with their
571  * intended meanings.
572  *
573  * <table>
574  *   <tr>
575  *     <th>Acronym</th>
576  *     <th>Description</th>
577  *   </tr>
578  *   <tr>
579  *     <td>DMA</td>
580  *     <td>Direct Memory Access</td>
581  *   </tr>
582  *   <tr>
583  *     <td>DMAC</td>
584  *     <td>Direct Memory Access Controller </td>
585  *   </tr>
586  *   <tr>
587  *     <td>CPU</td>
588  *     <td>Central Processing Unit</td>
589  *   </tr>
590  * </table>
591  *
592  *
593  * \section asfdoc_samb_dma_extra_dependencies Dependencies
594  * There are no dependencies related to this driver.
595  *
596  *
597  * \section asfdoc_samb_dma_extra_errata Errata
598  * There are no errata related to this driver.
599  *
600  *
601  * \section asfdoc_samb_dma_extra_history Module History
602  * An overview of the module history is presented in the table below, with
603  * details on the enhancements and fixes made to the module since its first
604  * release. The current version of this corresponds to the newest version in
605  * the table.
606  *
607  * <table>
608  *   <tr>
609  *     <th>Changelog</th>
610  *   </tr>
611  *   <tr>
612  *     <td>Initial Release</td>
613  *   </tr>
614  * </table>
615  */
616 
617  /**
618  * \page asfdoc_samb_dma_exqsg Examples for DMAC Driver
619  *
620  * This is a list of the available Quick Start Guides (QSGs) and example
621  * applications for \ref asfdoc_samb_dma_group. QSGs are simple examples with
622  * step-by-step instructions to configure and use this driver in a selection of
623  * use cases. Note that QSGs can be compiled as a standalone application or be
624  * added to the user application.
625  *
626  * - \subpage asfdoc_samb_dma_basic_use_case
627  *
628  * \note More DMA usage examples are available in peripheral QSGs.
629  *
630  * \page asfdoc_samb_dma_document_revision_history Document Revision History
631  *
632  * <table>
633  *    <tr>
634  *        <th>Doc. Rev.</td>
635  *        <th>Date</td>
636  *        <th>Comments</td>
637  *    </tr>
638  *    <tr>
639  *        <td>A</td>
640  *        <td>09/2015</td>
641  *        <td>Initial release</td>
642  *    </tr>
643  * </table>
644  */
645 
646 #ifdef __cplusplus
647 }
648 #endif
649 
650 #endif /* DMA_H_INCLUDED */
651