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 }