1 /*
2  * \file
3  *
4  * \brief Direct Memory Access Controller Driver for SAMB
5  *
6  * Copyright (C) 2015 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 
47 #include <string.h>
48 #include "dma_sam_b.h"
49 
50 struct _dma_module {
51 	volatile bool _dma_init;
52 	volatile uint32_t allocated_channels;
53 	uint8_t free_channels;
54 };
55 
56 struct _dma_module _dma_inst = {
57 	._dma_init = false,
58 	.allocated_channels = 0,
59 	.free_channels = CONF_MAX_USED_CHANNEL_NUM,
60 };
61 
62 /** Internal DMA resource pool. */
63 static struct dma_resource* _dma_active_resource[CONF_MAX_USED_CHANNEL_NUM];
64 
65 /**
66  * \brief Get the assigned channel DMA value.
67  *
68  * \param[in] channel DMA channel index
69  * \param[in] DMA register address
70  *
71  * \return The value of DMA register.
72  */
get_channel_reg_val(uint8_t channel,uint32_t reg)73 static uint32_t get_channel_reg_val(uint8_t channel, uint32_t reg)
74 {
75 	return *(uint32_t*)(reg + 0x100*channel);
76 }
77 
78 /**
79  * \brief Set the assigned channel DMA value.
80  *
81  * \param[in] channel DMA channel index
82  * \param[in] DMA register address
83  * \param[in] The value to be set
84  *
85  */
set_channel_reg_val(uint8_t channel,uint32_t reg,uint32_t val)86 static void set_channel_reg_val(uint8_t channel, uint32_t reg, uint32_t val)
87 {
88 	*(uint32_t*)(reg + 0x100*channel) = val;
89 }
90 
91 /**
92  * \brief Get the DMA status.
93  *
94  * \param[in]  channel  DMA channel index
95  *
96  * \return The status of DMA
97  */
dma_get_status(uint8_t channel)98 uint8_t dma_get_status(uint8_t channel)
99 {
100 	return (uint8_t)get_channel_reg_val(channel, (uint32_t)&PROV_DMA_CTRL0->CH0_INT_RAWSTAT_REG.reg);
101 }
102 
103 /**
104  * \brief Get the DMA interrupt status.
105  *
106  * \param[in]  channel  DMA channel index
107  *
108  * \return The interrupt of status DMA
109  */
dma_get_interrupt_status(uint8_t channel)110 uint8_t dma_get_interrupt_status(uint8_t channel)
111 {
112 	return get_channel_reg_val(channel, (uint32_t)&PROV_DMA_CTRL0->CH0_INT_STATUS_REG.reg);
113 }
114 
115 /**
116  * \brief Get the DMA interrupt status.
117  *
118  * \param[in]  channel  DMA channel index
119  * \param[in]  flag     The interrupt flag want to clear
120  *
121  */
dma_clear_interrupt_status(uint8_t channel,uint8_t flag)122 void dma_clear_interrupt_status(uint8_t channel, uint8_t flag)
123 {
124 	set_channel_reg_val(channel, (uint32_t)&PROV_DMA_CTRL0->CH0_INT_CLEAR_REG.reg, 1 << flag);
125 }
126 
127 /**
128  * \brief Find a free channel for a DMA resource.
129  *
130  * Find a channel for the requested DMA resource.
131  *
132  * \return Status of channel allocation.
133  * \retval DMA_INVALID_CHANNEL  No channel available
134  * \retval count          Allocated channel for the DMA resource
135  */
_dma_find_first_free_channel_and_allocate(void)136 static uint8_t _dma_find_first_free_channel_and_allocate(void)
137 {
138 	uint8_t count;
139 	uint32_t tmp;
140 	bool allocated = false;
141 
142 	tmp = _dma_inst.allocated_channels;
143 
144 	for (count = 0; count < CONF_MAX_USED_CHANNEL_NUM; ++count) {
145 		if (!(tmp & 0x00000001)) {
146 			/* If free channel found, set as allocated and return
147 			 *number */
148 
149 			_dma_inst.allocated_channels |= 1 << count;
150 			_dma_inst.free_channels--;
151 			allocated = true;
152 
153 			break;
154 		}
155 
156 		tmp = tmp >> 1;
157 	}
158 
159 	if (!allocated) {
160 		return DMA_INVALID_CHANNEL;
161 	} else {
162 		return count;
163 	}
164 }
165 
166 /**
167  * \brief Release an allocated DMA channel.
168  *
169  * \param[in]  channel  Channel id to be released
170  *
171  */
_dma_release_channel(uint8_t channel)172 static void _dma_release_channel(uint8_t channel)
173 {
174 	_dma_inst.allocated_channels &= ~(1 << channel);
175 	_dma_inst.free_channels++;
176 }
177 
178 /**
179  * \brief Initializes config with predefined default values.
180  *
181  * This function will initialize a given DMA configuration structure to
182  * a set of known default values. This function should be called on
183  * any new instance of the configuration structure before being
184  * modified by the user application.
185  *
186  * The default configuration is as follows:
187  *  \li Set source max burst number as 1
188  *  \li Set source tokens as 1
189  *  \li Set source peripheral as memory
190  *  \li Set source peripheral delay as 0
191  *  \li Disable source top priority
192  *  \li Set source top priority channel as 0
193  *  \li Disable source high priority
194  *  \li Set source high priority channel as 0
195  *  \li Set destination max burst number as 1
196  *  \li Set destination tokens as 1
197  *  \li Set destination peripheral as memory
198  *  \li Set destination peripheral delay as 0
199  *  \li Disable destination top priority
200  *  \li Set destination top priority channel as 0
201  *  \li Disable destination high priority
202  *  \li Set destination high priority channel as 0
203  *  \li Disable the joint mode
204  *  \li Disable the endian swap
205  * \param[out] config Pointer to the configuration
206  *
207  */
dma_get_config_defaults(struct dma_resource_config * config)208 void dma_get_config_defaults(struct dma_resource_config *config)
209 {
210 	/* DMA source configuration */
211 	config->src.max_burst = 1;
212 	config->src.tokens = 1;
213 	config->src.enable_inc_addr = true;
214 	config->src.periph = MEMORY_DMA_PERIPHERAL;
215 	config->src.periph_delay = 0;
216 	config->src.enable_proi_top = false;
217 	config->src.proi_top_index = 0;
218 	config->src.enable_proi_high = false;
219 	config->src.proi_high_index = 0;
220 	/* DMA destination configuration */
221 	config->des.max_burst = 1;
222 	config->des.tokens = 1;
223 	config->des.enable_inc_addr = true;
224 	config->des.periph = MEMORY_DMA_PERIPHERAL;
225 	config->des.periph_delay = 0;
226 	config->des.enable_proi_top = false;
227 	config->des.proi_top_index = 0;
228 	config->des.enable_proi_high = false;
229 	config->des.proi_high_index = 0;
230 	/* DMA channel configuration */
231 	config->enable_joint_mode = false;
232 	config->swap = DMA_ENDIAN_NO_SWAP;
233 }
234 
235 /**
236  * \brief Configure the DMA resource.
237  *
238  * \param[in]  dma_resource Pointer to a DMA resource instance
239  * \param[out] config Configurations of the DMA resource
240  *
241  */
_dma_set_config(struct dma_resource * resource,struct dma_resource_config * config)242 static void _dma_set_config(struct dma_resource *resource,
243 		struct dma_resource_config *config)
244 {
245 	uint32_t regval = 0;
246 
247 	/* Static register configuration */
248 	regval = PROV_DMA_CTRL_CH0_STATIC_REG0_RD_BURST_MAX_SIZE(config->src.max_burst)|
249 			PROV_DMA_CTRL_CH0_STATIC_REG0_RD_TOKENS(config->src.tokens) |
250 			(config->src.enable_inc_addr << PROV_DMA_CTRL_CH0_STATIC_REG0_RD_INCR_Pos);
251 	set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_STATIC_REG0.reg, regval);
252 	/* Static register1 configuration */
253 	regval = PROV_DMA_CTRL_CH0_STATIC_REG1_WR_BURST_MAX_SIZE(config->des.max_burst) |
254 			PROV_DMA_CTRL_CH0_STATIC_REG1_WR_TOKENS(config->des.tokens) |
255 			(config->des.enable_inc_addr << PROV_DMA_CTRL_CH0_STATIC_REG0_RD_INCR_Pos);
256 	set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_STATIC_REG1.reg, regval);
257 	/* Static register2 configuration */
258 	regval = (config->enable_joint_mode << PROV_DMA_CTRL_CH0_STATIC_REG2_JOINT_Pos) |
259 			PROV_DMA_CTRL_CH0_STATIC_REG2_END_SWAP(config->swap);
260 	set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_STATIC_REG2.reg, regval);
261 	/* Static register4 configuration */
262 	regval = PROV_DMA_CTRL_CH0_STATIC_REG4_RD_PERIPH_NUM(config->src.periph) |
263 			PROV_DMA_CTRL_CH0_STATIC_REG4_RD_PERIPH_DELAY(config->src.periph_delay) |
264 			PROV_DMA_CTRL_CH0_STATIC_REG4_WR_PERIPH_NUM(config->des.periph) |
265 			PROV_DMA_CTRL_CH0_STATIC_REG4_WR_PERIPH_DELAY(config->des.periph_delay);
266 	set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_STATIC_REG4.reg, regval);
267 	/* Priority channels configuration */
268 	regval = PROV_DMA_CTRL_CORE_PRIORITY_RD_PRIO_TOP_NUM(config->src.proi_top_index) |
269 			(PROV_DMA_CTRL_CORE_PRIORITY_RD_PRIO_TOP << config->src.enable_proi_top) |
270 			PROV_DMA_CTRL_CORE_PRIORITY_RD_PRIO_HIGH_NUM(config->src.proi_high_index) |
271 			(PROV_DMA_CTRL_CORE_PRIORITY_RD_PRIO_HIGH << config->src.enable_proi_high) |
272 			PROV_DMA_CTRL_CORE_PRIORITY_WR_PRIO_TOP_NUM(config->des.proi_top_index) |
273 			(PROV_DMA_CTRL_CORE_PRIORITY_WR_PRIO_TOP << config->des.enable_proi_top) |
274 			PROV_DMA_CTRL_CORE_PRIORITY_WR_PRIO_HIGH_NUM(config->des.proi_high_index) |
275 			(PROV_DMA_CTRL_CORE_PRIORITY_WR_PRIO_HIGH << config->des.enable_proi_high);
276 	set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CORE_PRIORITY.reg, regval);
277 	/* Initial the global variety */
278 	for (int i = 0; i < DMA_CALLBACK_N; i++) {
279 		resource->callback[i] = NULL;
280 	}
281 	resource->callback_enable = 0;
282 }
283 
284 /**
285  * \brief Free an allocated DMA resource.
286  *
287  * This function will free an allocated DMA resource.
288  *
289  * \param[in,out] resource Pointer to the DMA resource
290  *
291  * \return Status of the free procedure.
292  *
293  * \retval STATUS_OK The DMA resource was freed successfully
294  * \retval STATUS_BUSY The DMA resource was busy and can't be freed
295  * \retval STATUS_ERR_NOT_INITIALIZED DMA resource was not initialized
296  */
dma_free(struct dma_resource * resource)297 enum status_code dma_free(struct dma_resource *resource)
298 {
299 	/* Check if channel is busy */
300 	if (dma_get_job_status(resource) == STATUS_BUSY) {
301 		return STATUS_BUSY;
302 	}
303 
304 	/* Check if DMA resource was not allocated */
305 	if (!(_dma_inst.allocated_channels & (1 << resource->channel_id))) {
306 		return STATUS_ERR_NOT_INITIALIZED;
307 	}
308 
309 	/* Release the DMA resource */
310 	_dma_release_channel(resource->channel_id);
311 
312 	/* Reset the item in the DMA resource pool */
313 	_dma_active_resource[resource->channel_id] = NULL;
314 
315 	return STATUS_OK;
316 }
317 
318 /**
319  * \brief Add a DMA transfer descriptor to a DMA resource.
320  *
321  * This function will add a DMA transfer descriptor to a DMA resource.
322  * If there was a transfer descriptor already allocated to the DMA resource,
323  * the descriptor will be linked to the next descriptor address.
324  *
325  * \param[in] resource Pointer to the DMA resource
326  * \param[in] descriptor Pointer to the transfer descriptor
327  *
328  * \retval STATUS_OK The descriptor is added to the DMA resource
329  * \retval STATUS_BUSY The DMA resource was busy and the descriptor is not added
330  */
dma_add_descriptor(struct dma_resource * resource,struct dma_descriptor * descriptor)331 enum status_code dma_add_descriptor(struct dma_resource *resource,
332 		struct dma_descriptor *descriptor)
333 {
334 	struct dma_descriptor *desc = resource->descriptor;
335 
336 	/* Check if channel is busy */
337 	if (dma_get_job_status(resource) == STATUS_BUSY) {
338 		return STATUS_BUSY;
339 	}
340 
341 	/* Look up for an empty space for the descriptor */
342 	if (desc == NULL) {
343 		resource->descriptor = descriptor;
344 		set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_CMD_REG0.reg, descriptor->read_start_addr);
345 		set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_CMD_REG1.reg, descriptor->write_start_addr);
346 		set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_CMD_REG2.reg, descriptor->buffer_size);
347 		set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_CMD_REG3.reg, 3);
348 	} else {
349 		/* Looking for end of descriptor link */
350 		while(((uint32_t)desc->cmd.next_addr) != 0) {
351 			desc = (struct dma_descriptor*)((uint32_t)desc->next);
352 		}
353 		if (resource->descriptor->cmd.next_addr == 0x0) {
354 			set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_CMD_REG3.reg, ((uint32_t)descriptor & (~0x3)));
355 		}
356 		/* Set to the end of descriptor list */
357 		desc->next = (uint32_t)descriptor;
358 		/* The end of list should point to 0 */
359 		if (descriptor->cmd.next_addr != 0) {
360 			/* Enable transferred interrupt, and channel stops when buffer done */
361 			descriptor->next = 0x3;
362 		}
363 	}
364 
365 	return STATUS_OK;
366 }
367 
368 /**
369  * \brief Start a DMA transfer.
370  *
371  * This function will start a DMA transfer through an allocated DMA resource.
372  *
373  * \param[in,out] resource Pointer to the DMA resource
374  *
375  * \return Status of the transfer start procedure.
376  *
377  * \retval STATUS_OK The transfer was started successfully
378  * \retval STATUS_BUSY The DMA resource was busy and the transfer was not started
379  * \retval STATUS_ERR_INVALID_ARG Transfer size is 0 and transfer was not started
380  */
dma_start_transfer_job(struct dma_resource * resource)381 enum status_code dma_start_transfer_job(struct dma_resource *resource)
382 {
383 	volatile uint32_t regval;
384 
385 	/* Check if resource was busy */
386 	if (resource->job_status == STATUS_BUSY) {
387 		return STATUS_BUSY;
388 	}
389 
390 	/* Check if transfer size is valid */
391 	if (resource->descriptor->buffer_size == 0) {
392 		return STATUS_ERR_INVALID_ARG;
393 	}
394 
395 	/* Clear the interrupt flag */
396 	regval = get_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_INT_STATUS_REG.reg);
397 	set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_INT_CLEAR_REG.reg, regval);
398 	/* Set the interrupt flag */
399 	regval = PROV_DMA_CTRL_CH0_INT_ENABLE_REG_MASK & resource->callback_enable;
400 	set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_INT_ENABLE_REG.reg, regval);
401 	/* Set job status */
402 	resource->job_status = STATUS_BUSY;
403 
404 	/* Enable the transfer channel */
405 	set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_CH_ENABLE_REG.reg, 1);
406 	/* Start the transfer channel */
407 	set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_CH_START_REG.reg, 1);
408 
409 	return STATUS_OK;
410 }
411 /**
412  * \brief Get the channel index
413  *
414  * \param[in]  channel  Channel active
415  *
416  */
get_channel_index(uint8_t channel)417 static uint8_t get_channel_index(uint8_t channel)
418 {
419 	uint8_t index = 0;
420 
421 	channel = channel & 0x0f;
422 	do {
423 		channel = channel >> 1;
424 		index++;
425 	} while (channel);
426 
427 	return (index - 1);
428 }
429 
430 /**
431  * \brief DMA interrupt service routine.
432  *
433  */
dma_isr_handler(void)434 static void dma_isr_handler( void )
435 {
436 	uint8_t active_channel;
437 	static uint8_t channel_index; //
438 	struct dma_resource *resource;
439 	uint8_t isr;
440 	uint8_t isr_flag = 0;
441 
442 	/* Get active channel */
443 	active_channel =  PROV_DMA_CTRL0->CORE_INT_STATUS.reg &
444 			PROV_DMA_CTRL_CORE_INT_STATUS_CHANNEL__Msk;
445 
446 	do {
447 		channel_index = get_channel_index(active_channel);
448 		/* Get active DMA resource based on channel */
449 		resource = _dma_active_resource[channel_index];
450 		isr = get_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_INT_STATUS_REG.reg);
451 		/* Calculate block transfer size of the DMA transfer */
452 		resource->transfered_size = get_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_COUNT_REG.reg);
453 
454 		/* DMA channel interrupt handler */
455 		if (isr & (1 << DMA_CALLBACK_TRANSFER_DONE)) {
456 			/* Transfer complete flag */
457 			isr_flag = DMA_CALLBACK_TRANSFER_DONE;
458 			/* Set job status */
459 			resource->job_status = STATUS_OK;
460 		} else if (isr & (1 << DMA_CALLBACK_READ_ERR)) {
461 			/* Read error flag */
462 			isr_flag = DMA_CALLBACK_READ_ERR;
463 			/* Set I/O ERROR status */
464 			resource->job_status = STATUS_ERR_IO;
465 		} else if (isr & (1 << DMA_CALLBACK_WRITE_ERR)) {
466 			/* Write error flag */
467 			isr_flag = DMA_CALLBACK_WRITE_ERR;
468 			/* Set I/O ERROR status */
469 			resource->job_status = STATUS_ERR_IO;
470 		} else if (isr & (1 << DMA_CALLBACK_FIFO_OVERFLOW)) {
471 			/* Overflow flag */
472 			isr_flag = DMA_CALLBACK_FIFO_OVERFLOW;
473 			/* Set I/O ERROR status */
474 			resource->job_status = STATUS_ERR_IO;
475 		} else if (isr & (1 << DMA_CALLBACK_FIFO_UNDERFLOW)) {
476 			/* Underflow flag */
477 			isr_flag = DMA_CALLBACK_FIFO_UNDERFLOW;
478 			/* Set I/O ERROR status */
479 			resource->job_status = STATUS_ERR_IO;
480 		} else if (isr & (1 << DMA_CALLBACK_READ_TIMEOUT)) {
481 			/* Read timeout flag */
482 			isr_flag = DMA_CALLBACK_READ_TIMEOUT;
483 			/* Set I/O ERROR status */
484 			resource->job_status = STATUS_ERR_IO;
485 		} else if (isr & (1 << DMA_CALLBACK_WRITE_TIMEOUT)) {
486 			/* Write timeout flag */
487 			isr_flag = DMA_CALLBACK_WRITE_TIMEOUT;
488 			/* Set I/O ERROR status */
489 			resource->job_status = STATUS_ERR_IO;
490 		} else if (isr & (1 << DMA_CALLBACK_WDT_TRIGGER)) {
491 			/* Watchdog error flag */
492 			isr_flag = DMA_CALLBACK_WDT_TRIGGER;
493 			/* Set I/O ERROR status */
494 			resource->job_status = STATUS_ERR_IO;
495 		}
496 
497 		if (isr) {
498 			/* Clear the watch dog error flag */
499 			set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_INT_CLEAR_REG.reg, 1<<isr_flag);
500 			/* Execute the callback function */
501 			if ((resource->callback_enable & (1<<isr_flag)) &&
502 					(resource->callback[isr_flag])) {
503 				resource->callback[isr_flag](resource);
504 			}
505 		}
506 		isr &= ~(1<<isr_flag);
507 	} while (isr);
508 
509 	NVIC_ClearPendingIRQ(PROV_DMA_CTRL0_IRQn);
510 }
511 
512 /**
513  * \brief Allocate a DMA with configurations.
514  *
515  * This function will allocate a proper channel for a DMA transfer request.
516  *
517  * \param[in,out]  dma_resource Pointer to a DMA resource instance
518  * \param[in] transfer_config Configurations of the DMA transfer
519  *
520  * \return Status of the allocation procedure.
521  *
522  * \retval STATUS_OK The DMA resource was allocated successfully
523  * \retval STATUS_ERR_NOT_FOUND DMA resource allocation failed
524  */
dma_allocate(struct dma_resource * resource,struct dma_resource_config * config)525 enum status_code dma_allocate(struct dma_resource *resource,
526 		struct dma_resource_config *config)
527 {
528 	uint8_t new_channel;
529 
530 	if (!_dma_inst._dma_init) {
531 		/* Perform a reset before enable DMA controller */
532 		system_peripheral_reset(PERIPHERAL_DMA);
533 		/* Select Mux 15 as PROV_DMA_CTRL0 interrupt source */
534 		LPMCU_MISC_REGS0->IRQ_MUX_IO_SEL_3.bit.MUX_15 = LPMCU_MISC_REGS_IRQ_MUX_IO_SEL_3_MUX_15_16_Val;
535 		system_register_isr(31, (uint32_t)dma_isr_handler);
536 
537 		_dma_inst._dma_init = true;
538 	}
539 
540 	new_channel = _dma_find_first_free_channel_and_allocate();
541 	/* If no channel available, return not found */
542 	if (new_channel == DMA_INVALID_CHANNEL) {
543 		return STATUS_ERR_NOT_FOUND;
544 	}
545 
546 	/* Set the channel */
547 	resource->channel_id = new_channel;
548 	/* Configure the DMA control,channel registers and descriptors here */
549 	_dma_set_config(resource, config);
550 
551 	resource->descriptor = NULL;
552 
553 	/* Log the DMA resource into the internal DMA resource pool */
554 	_dma_active_resource[resource->channel_id] = resource;
555 
556 	return STATUS_OK;
557 }