/**
* \brief   EDMA3 De-initialization
*
* This function removes the EDMA3 Driver instance and unregisters the
* interrupt handlers.
*
* \return  EDMA3_DRV_SOK if success, else error code
*/
EDMA3_DRV_Result edma3deinit (void)
{
  unsigned int edmaInstanceId = 0;
  EDMA3_DRV_Result    edma3Result = EDMA3_DRV_SOK;
  
  /* Unregister Interrupt Handlers first */
  unregisterEdma3Interrupts();
  
  /* Delete the semaphore */
  edma3Result = edma3OsSemDelete(semHandle);
  if (EDMA3_DRV_SOK != edma3Result )
  {
#ifdef EDMA3_DRV_DEBUG
    EDMA3_DRV_PRINTF("edma3deinit: edma3OsSemDelete FAILED\r\n");
#endif
  }
  else
  {
    /* Make the semaphore handle as NULL. */
    semHandle = NULL;
    
    /* Now, close the EDMA3 Driver Instance */
    edma3Result = EDMA3_DRV_close (hEdma, NULL);
    if (EDMA3_DRV_SOK != edma3Result )
    {
#ifdef EDMA3_DRV_DEBUG
      EDMA3_DRV_PRINTF("edma3deinit: EDMA3_DRV_close FAILED\r\n");
#endif
    }
    else
    {
      /* Make the Drv handle as NULL. */
      hEdma = NULL;
      
      /* Now, delete the EDMA3 Driver Object */
      edma3Result = EDMA3_DRV_delete (edmaInstanceId, NULL);
      if (EDMA3_DRV_SOK != edma3Result )
      {
#ifdef EDMA3_DRV_DEBUG
        EDMA3_DRV_PRINTF("edma3deinit: EDMA3_DRV_delete FAILED\r\n");
#endif
      }
      else
      {
#ifdef EDMA3_DRV_DEBUG
        EDMA3_DRV_PRINTF("edma3deinit: EDMA3 Deinitialization" \
          " Completed...\r\n");
#endif
      }
    }
  }
  
  return edma3Result;
}
/**
* \brief   EDMA3 Cache Flush
*
*  This function flushes (cleans) the Cache
*
*  \param  mem_start_ptr [IN]      Starting adress of memory. Please note that
*                                  this should be 32 bytes alinged.
*  \param  num_bytes [IN]          length of buffer
* \return  nil return value
*/
void Edma3_CacheFlush(unsigned int mem_start_ptr,
                      unsigned int num_bytes)
{
  /* Verify whether the start address is 128-bytes aligned or not */
  if((mem_start_ptr & (0x7FU))    !=    0)
  {
#ifdef EDMA3_DRV_DEBUG
    EDMA3_DRV_PRINTF("\r\n Cache : Memory is not 128 bytes alinged\r\n");
#endif
  }
  
  BCACHE_wb ((void *)mem_start_ptr,
    num_bytes,
    EDMA3_CACHE_WAIT);
}
/**
 *  \brief   EDMA3 mem-to-mem data copy test case, using two DMA
 *              channels, linked to each other.
 *
 *  \param  acnt        [IN]      Number of bytes in an array
 *  \param  bcnt        [IN]      Number of arrays in a frame
 *  \param  ccnt        [IN]      Number of frames in a block
 *  \param  syncType    [IN]      Synchronization type (A/AB Sync)
 *
 *  \return  EDMA3_DRV_SOK or EDMA3_DRV Error Code
 */
EDMA3_DRV_Result edma3_test_with_link(
						EDMA3_DRV_Handle hEdma,
	                    unsigned int acnt,
	                    unsigned int bcnt,
	                    unsigned int ccnt,
	                    EDMA3_DRV_SyncType syncType)
    {
    EDMA3_DRV_Result result = EDMA3_DRV_SOK;
    EDMA3_DRV_PaRAMRegs paramSet = {0,0,0,0,0,0,0,0,0,0,0,0};
    unsigned int ch1Id = 0;
    unsigned int ch2Id = 0;
    unsigned int tcc1 = 0;
    unsigned int tcc2 = 0;
    int i;
    unsigned int count;
    unsigned int Istestpassed1 = 0u;
    unsigned int Istestpassed2 = 0u;
    unsigned int numenabled = 0;
    unsigned int BRCnt = 0;
    int srcbidx = 0, desbidx = 0;
    int srccidx = 0, descidx = 0;


    srcBuff1 = (signed char*) GLOBAL_ADDR(_srcBuff1);
    dstBuff1 = (signed char*) GLOBAL_ADDR(_dstBuff1);
    srcBuff2 = (signed char*) GLOBAL_ADDR(_srcBuff2);
    dstBuff2 = (signed char*) GLOBAL_ADDR(_dstBuff2);


    /* Initalize source and destination buffers */
    for (count = 0u; count < (acnt*bcnt*ccnt); count++)
        {
        srcBuff1[count] = (int)count+1;
        srcBuff2[count] = (int)count+1;
        /**
         * No need to initialize the destination buffer as it is being invalidated.
        dstBuff1[count] = initval;
        dstBuff2[count] = initval;
        */
        }


#ifdef EDMA3_ENABLE_DCACHE
    /*
    * Note: These functions are required if the buffer is in DDR.
    * For other cases, where buffer is NOT in DDR, user
    * may or may not require the below functions.
    */
    /* Flush the Source Buffers */
    if (result == EDMA3_DRV_SOK)
        {
        result = Edma3_CacheFlush((unsigned int)srcBuff1, (acnt*bcnt*ccnt));
        }
    if (result == EDMA3_DRV_SOK)
        {
        result = Edma3_CacheFlush((unsigned int)srcBuff2, (acnt*bcnt*ccnt));
        }

    /* Invalidate the Destination Buffers */
    if (result == EDMA3_DRV_SOK)
        {
        result = Edma3_CacheInvalidate((unsigned int)dstBuff1, (acnt*bcnt*ccnt));
        }
    if (result == EDMA3_DRV_SOK)
        {
        result = Edma3_CacheInvalidate((unsigned int)dstBuff2, (acnt*bcnt*ccnt));
        }
#endif  /* EDMA3_ENABLE_DCACHE */


    irqRaised1 = 0;
    irqRaised2 = 0;

    /* Set B count reload as B count. */
    BRCnt = bcnt;

    /* Setting up the SRC/DES Index */
    srcbidx = (int)acnt;
    desbidx = (int)acnt;
    if (syncType == EDMA3_DRV_SYNC_A)
        {
        /* A Sync Transfer Mode */
        srccidx = (int)acnt;
        descidx = (int)acnt;
        }
    else
        {
        /* AB Sync Transfer Mode */
        srccidx = ((int)acnt * (int)bcnt);
        descidx = ((int)acnt * (int)bcnt);
        }


    /* Setup for Channel 1*/
    tcc1 = EDMA3_DRV_TCC_ANY;
    ch1Id = EDMA3_DRV_DMA_CHANNEL_ANY;

    /* Request any DMA channel and any TCC */
    if (result == EDMA3_DRV_SOK)
        {
        result = EDMA3_DRV_requestChannel (hEdma, &ch1Id, &tcc1,
                                            (EDMA3_RM_EventQueue)0,
                                            &callback1, NULL);
        }

    if (result == EDMA3_DRV_SOK)
        {
        /* Fill the PaRAM Set with transfer specific information */
        paramSet.srcAddr    = (unsigned int)(srcBuff1);
        paramSet.destAddr   = (unsigned int)(dstBuff1);

        /**
         * Be Careful !!!
         * Valid values for SRCBIDX/DSTBIDX are between –32768 and 32767
         * Valid values for SRCCIDX/DSTCIDX are between –32768 and 32767
         */
        paramSet.srcBIdx    = srcbidx;
        paramSet.destBIdx   = desbidx;
        paramSet.srcCIdx    = srccidx;
        paramSet.destCIdx   = descidx;

        /**
         * Be Careful !!!
         * Valid values for ACNT/BCNT/CCNT are between 0 and 65535.
         * ACNT/BCNT/CCNT must be greater than or equal to 1.
         * Maximum number of bytes in an array (ACNT) is 65535 bytes
         * Maximum number of arrays in a frame (BCNT) is 65535
         * Maximum number of frames in a block (CCNT) is 65535
         */
        paramSet.aCnt       = acnt;
        paramSet.bCnt       = bcnt;
        paramSet.cCnt       = ccnt;

        /* For AB-synchronized transfers, BCNTRLD is not used. */
        paramSet.bCntReload = BRCnt;

        paramSet.linkAddr   = 0xFFFFu;

        /* Src & Dest are in INCR modes */
        paramSet.opt &= 0xFFFFFFFCu;
        /* Program the TCC */
        paramSet.opt |= ((tcc1 << OPT_TCC_SHIFT) & OPT_TCC_MASK);

        /* Enable Intermediate & Final transfer completion interrupt */
        paramSet.opt |= (1 << OPT_ITCINTEN_SHIFT);
        paramSet.opt |= (1 << OPT_TCINTEN_SHIFT);

        if (syncType == EDMA3_DRV_SYNC_A)
            {
            paramSet.opt &= 0xFFFFFFFBu;
            }
        else
            {
            /* AB Sync Transfer Mode */
            paramSet.opt |= (1 << OPT_SYNCDIM_SHIFT);
            }

        /* Now, write the PaRAM Set. */
        result = EDMA3_DRV_setPaRAM (hEdma, ch1Id, &paramSet);
        }


    /*
     * There is another way to program the PaRAM Set using specific APIs
     * for different PaRAM set entries. It gives user more control and easier
     * to use interface. User can use any of the methods.
     * Below is the alternative way to program the PaRAM Set.
     */

    /*

    if (result == EDMA3_DRV_SOK)
        {
        result = EDMA3_DRV_setSrcParams (hEdma, ch1Id, (unsigned int)(srcBuff1),
                                        EDMA3_DRV_ADDR_MODE_INCR,
                                        EDMA3_DRV_W8BIT);
        }

    if (result == EDMA3_DRV_SOK)
        {
        result = EDMA3_DRV_setDestParams (hEdma, ch1Id,
                                            (unsigned int)(dstBuff1),
                                            EDMA3_DRV_ADDR_MODE_INCR,
                                            EDMA3_DRV_W8BIT);
        }

    if (result == EDMA3_DRV_SOK)
        {
        result = EDMA3_DRV_setSrcIndex (hEdma, ch1Id, srcbidx, srccidx);
        }

    if (result == EDMA3_DRV_SOK)
        {
        result =  EDMA3_DRV_setDestIndex (hEdma, ch1Id, desbidx, descidx);
        }

    if (result == EDMA3_DRV_SOK)
        {
        if (syncType == EDMA3_DRV_SYNC_A)
            {
            result = EDMA3_DRV_setTransferParams (hEdma, ch1Id, acnt, bcnt,
                                                ccnt, BRCnt,
                                                EDMA3_DRV_SYNC_A);
            }
        else
            {
            result = EDMA3_DRV_setTransferParams (hEdma, ch1Id, acnt, bcnt,
                                                ccnt, BRCnt,
                                                EDMA3_DRV_SYNC_AB);
            }
        }

    if (result == EDMA3_DRV_SOK)
        {
        result = EDMA3_DRV_setOptField (hEdma, ch1Id,
                                        EDMA3_DRV_OPT_FIELD_TCINTEN, 1u);
        }

    if (result == EDMA3_DRV_SOK)
        {
        result = EDMA3_DRV_setOptField (hEdma, ch1Id,
                                        EDMA3_DRV_OPT_FIELD_ITCINTEN, 1u);
        }

    */


    /* Request any LINK channel and any TCC */
    if (result == EDMA3_DRV_SOK)
        {
        /* Setup for Channel 2 */
        ch2Id   = EDMA3_DRV_LINK_CHANNEL;
        tcc2    = EDMA3_DRV_TCC_ANY;

        result = EDMA3_DRV_requestChannel (hEdma, &ch2Id, &tcc2,
                                            (EDMA3_RM_EventQueue)0,
                                            &callback1, NULL);
        }

    if (result == EDMA3_DRV_SOK)
        {
        /*
         * Fill the PaRAM Set for the LINK channel
         * with transfer specific information.
         */
        paramSet.srcAddr    = (unsigned int)(srcBuff2);
        paramSet.destAddr   = (unsigned int)(dstBuff2);

        /**
         * Be Careful !!!
         * Valid values for SRCBIDX/DSTBIDX are between –32768 and 32767
         * Valid values for SRCCIDX/DSTCIDX are between –32768 and 32767
         */
        paramSet.srcBIdx    = srcbidx;
        paramSet.destBIdx   = desbidx;
        paramSet.srcCIdx    = srccidx;
        paramSet.destCIdx   = descidx;

        /**
         * Be Careful !!!
         * Valid values for ACNT/BCNT/CCNT are between 0 and 65535.
         * ACNT/BCNT/CCNT must be greater than or equal to 1.
         * Maximum number of bytes in an array (ACNT) is 65535 bytes
         * Maximum number of arrays in a frame (BCNT) is 65535
         * Maximum number of frames in a block (CCNT) is 65535
         */
        paramSet.aCnt       = acnt;
        paramSet.bCnt       = bcnt;
        paramSet.cCnt       = ccnt;

        /* For AB-synchronized transfers, BCNTRLD is not used. */
        paramSet.bCntReload = BRCnt;

        paramSet.linkAddr   = 0xFFFFu;

        /* Reset opt field first */
        paramSet.opt = 0x0u;
        /* Src & Dest are in INCR modes */
        paramSet.opt &= 0xFFFFFFFCu;

        /* Enable Intermediate & Final transfer completion interrupt */
        paramSet.opt |= (1 << OPT_ITCINTEN_SHIFT);
        paramSet.opt |= (1 << OPT_TCINTEN_SHIFT);

        if (syncType == EDMA3_DRV_SYNC_A)
            {
            paramSet.opt &= 0xFFFFFFFBu;
            }
        else
            {
            /* AB Sync Transfer Mode */
            paramSet.opt |= (1 << OPT_SYNCDIM_SHIFT);
            }

        /* Now, write the PaRAM Set. */
        result = EDMA3_DRV_setPaRAM(hEdma, ch2Id, &paramSet);
        }


    /*
     * There is another way to program the PaRAM Set using specific APIs
     * for different PaRAM set entries. It gives user more control and easier
     * to use interface. User can use any of the methods.
     * Below is the alternative way to program the PaRAM Set.
     */

    /*

    if (result == EDMA3_DRV_SOK)
        {
        result = EDMA3_DRV_setSrcParams (hEdma, ch2Id, (unsigned int)(srcBuff2),
                                        EDMA3_DRV_ADDR_MODE_INCR,
                                        EDMA3_DRV_W8BIT);
        }

    if (result == EDMA3_DRV_SOK)
        {
        result = EDMA3_DRV_setDestParams (hEdma, ch2Id,
                                        (unsigned int)(dstBuff2),
                                        EDMA3_DRV_ADDR_MODE_INCR,
                                        EDMA3_DRV_W8BIT);
        }

    if (result == EDMA3_DRV_SOK)
        {
        result = EDMA3_DRV_setSrcIndex (hEdma, ch2Id, srcbidx, srccidx);
        }

    if (result == EDMA3_DRV_SOK)
        {
        result =  EDMA3_DRV_setDestIndex (hEdma, ch2Id, desbidx, descidx);
        }

    if (result == EDMA3_DRV_SOK)
        {
        if (syncType == EDMA3_DRV_SYNC_A)
            {
            result = EDMA3_DRV_setTransferParams (hEdma, ch2Id, acnt, bcnt,
                                                    ccnt,
                                                    BRCnt,EDMA3_DRV_SYNC_A);
            }
        else
            {
            result = EDMA3_DRV_setTransferParams (hEdma, ch2Id, acnt, bcnt,
                                                    ccnt,
                                                    BRCnt,EDMA3_DRV_SYNC_AB);
            }
        }

    if (result == EDMA3_DRV_SOK)
        {
        result = EDMA3_DRV_setOptField (hEdma, ch2Id,
                                        EDMA3_DRV_OPT_FIELD_TCINTEN, 1u);
        }

    if (result == EDMA3_DRV_SOK)
        {
        result = EDMA3_DRV_setOptField (hEdma, ch2Id,
                                        EDMA3_DRV_OPT_FIELD_ITCINTEN, 1u);
        }

    */


    /* Link both the channels. */
    if (result == EDMA3_DRV_SOK)
        {
        result = EDMA3_DRV_linkChannel (hEdma, ch1Id, ch2Id);
        }


    /*
     * Since the transfer is going to happen in Manual mode of EDMA3
     * operation, we have to 'Enable the Transfer' multiple times.
     * Number of times depends upon the Mode (A/AB Sync)
     * and the different counts.
     */
    if (result == EDMA3_DRV_SOK)
        {
        /*Need to activate next param*/
        if (syncType == EDMA3_DRV_SYNC_A)
            {
            numenabled = bcnt * ccnt;
            }
        else
            {
            /* AB Sync Transfer Mode */
            numenabled = ccnt;
            }

        for (i = 0; i < numenabled; i++)
            {
            irqRaised1 = 0;

            /*
             * Now enable the transfer for Master channel as many times
             * as calculated above.
             */
            result = EDMA3_DRV_enableTransfer (hEdma, ch1Id,
                                                EDMA3_DRV_TRIG_MODE_MANUAL);
            if (result != EDMA3_DRV_SOK)
                {
#ifdef EDMA3_DRV_DEBUG
                EDMA3_DRV_PRINTF ("error from edma3_test_with_link\n\r\n");
#endif  /* EDMA3_DRV_DEBUG */
                break;
                }

            while (irqRaised1 == 0)
                {
                /* Wait for the Completion ISR on Master Channel. */
                printf ("waiting for interrupt...\n");	
                }

            /* Check the status of the completed transfer */
            if (irqRaised1 < 0)
                {
                /* Some error occured, break from the FOR loop. */
#ifdef EDMA3_DRV_DEBUG
                EDMA3_DRV_PRINTF ("\r\nedma3_test_with_link: Event Miss Occured!!!\r\n");
#endif  /* EDMA3_DRV_DEBUG */

                /* Clear the error bits first */
                result = EDMA3_DRV_clearErrorBits (hEdma, ch1Id);

                break;
                }
            }
        }


    /**
     * Now the transfer on Master channel is finished.
     * Trigger next (LINK) param.
     */
    if (EDMA3_DRV_SOK == result)
        {
        for (i = 0; i < numenabled; i++)
            {
            irqRaised1 = 0;

            /*
             * Enable the transfer for LINK channel as many times
             * as calculated above.
             */
            result = EDMA3_DRV_enableTransfer (hEdma, ch1Id,
                                                EDMA3_DRV_TRIG_MODE_MANUAL);
            if (result != EDMA3_DRV_SOK)
                {
#ifdef EDMA3_DRV_DEBUG
                EDMA3_DRV_PRINTF ("error from edma3_test_with_link\n\r\n");
#endif  /* EDMA3_DRV_DEBUG */
                break;
                }

            while (irqRaised1 == 0)
                {
                /* Wait for the Completion ISR on the Link Channel. */
                printf ("waiting for interrupt...\n");	
                }

            /* Check the status of the completed transfer */
            if (irqRaised1 < 0)
                {
                /* Some error occured, break from the FOR loop. */
#ifdef EDMA3_DRV_DEBUG
                EDMA3_DRV_PRINTF ("\r\nedma3_test_with_link: Event Miss Occured!!!\r\n");
#endif  /* EDMA3_DRV_DEBUG */

                /* Clear the error bits first */
                result = EDMA3_DRV_clearErrorBits (hEdma, ch2Id);

                break;
                }
            }
        }



    /* Match the Source and Destination Buffers. */
    if (EDMA3_DRV_SOK == result)
        {
        for (i = 0; i < (acnt*bcnt*ccnt); i++)
            {
            if (srcBuff1[i] != dstBuff1[i])
                {
                Istestpassed1 = 0u;
#ifdef EDMA3_DRV_DEBUG
                EDMA3_DRV_PRINTF("edma3_test_with_link: Data write-read " \
                                "matching FAILED at i = %d " \
                                "(srcBuff1 -> dstBuff1)\r\n", i);
#endif  /* EDMA3_DRV_DEBUG */
                break;
                }
            }
        if (i == (acnt*bcnt*ccnt))
            {
            Istestpassed1 = 1u;
            }


        for (i = 0; i < (acnt*bcnt*ccnt); i++)
            {
            if (srcBuff2[i] != dstBuff2[i])
                {
                Istestpassed2 = 0;
#ifdef EDMA3_DRV_DEBUG
                EDMA3_DRV_PRINTF("edma3_test_with_link: Data write-read " \
                            "matching FAILED at i = %d " \
                            "(srcBuff2 -> dstBuff2)\r\n", i);
#endif  /* EDMA3_DRV_DEBUG */
                break;
                }
            }
        if (i == (acnt*bcnt*ccnt))
            {
            Istestpassed2 = 1u;
            }


        /* Free the previously allocated channels. */
        result = EDMA3_DRV_freeChannel (hEdma, ch1Id);
        if (result != EDMA3_DRV_SOK)
            {
#ifdef EDMA3_DRV_DEBUG
            EDMA3_DRV_PRINTF("edma3_test_with_link: EDMA3_DRV_freeChannel() " \
                                "for ch1 FAILED, error code: %d\r\n", result);
#endif  /* EDMA3_DRV_DEBUG */
            }
        else
            {
            result = EDMA3_DRV_freeChannel (hEdma, ch2Id);
            if (result != EDMA3_DRV_SOK)
                {
#ifdef EDMA3_DRV_DEBUG
                EDMA3_DRV_PRINTF("edma3_test_with_link: " \
                                "EDMA3_DRV_freeChannel() for ch 2 FAILED, " \
                                "error code: %d\r\n", result);
#endif  /* EDMA3_DRV_DEBUG */
                }
            }
        }


    if((Istestpassed1 == 1u) && (Istestpassed2 == 1u))
        {
#ifdef EDMA3_DRV_DEBUG
        EDMA3_DRV_PRINTF("edma3_test_with_link PASSED\r\n");
#endif  /* EDMA3_DRV_DEBUG */
        }
    else
        {
#ifdef EDMA3_DRV_DEBUG
        EDMA3_DRV_PRINTF("edma3_test_with_link FAILED\r\n");
#endif  /* EDMA3_DRV_DEBUG */
        result = ((EDMA3_DRV_SOK == result) ?
                                EDMA3_DATA_MISMATCH_ERROR : result);
        }


    return result;
}
/**
* \brief   EDMA3 Initialization
*
* This function initializes the EDMA3 Driver and registers the
* interrupt handlers.
*
* \return  EDMA3_DRV_SOK if success, else error code
*/
EDMA3_DRV_Result edma3init (void)
{
  unsigned int edma3InstanceId = 0;
  EDMA3_DRV_InitConfig initCfg;
  EDMA3_DRV_Result    edma3Result = EDMA3_DRV_SOK;
  EDMA3_OS_SemAttrs semAttrs = {EDMA3_OS_SEMTYPE_FIFO, NULL};
  EDMA3_DRV_GblConfigParams *globalConfig = &sampleEdma3GblCfgParams;
  EDMA3_DRV_InstanceInitConfig *instanceConfig = &sampleInstInitConfig;
  EDMA3_RM_MiscParam miscParam;
  
  if (NULL == hEdma)
  {
    miscParam.isSlave = FALSE;
    
    /* Create EDMA3 Driver Object first. */
    edma3Result = EDMA3_DRV_create (edma3InstanceId,
      globalConfig , (void *)&miscParam);
    
    if (edma3Result != EDMA3_DRV_SOK)
    {
#ifdef EDMA3_DRV_DEBUG
      EDMA3_DRV_PRINTF("edma3init: EDMA3_DRV_create FAILED\r\n");
#endif
    }
    else
    {
      /* configuration structure for the Driver */
      initCfg.isMaster = TRUE;
      initCfg.regionId = (EDMA3_RM_RegionId)1u;
      initCfg.drvSemHandle = NULL;
      /* Driver instance specific config NULL */
      initCfg.drvInstInitConfig = instanceConfig;
      initCfg.gblerrCb = NULL;
      initCfg.gblerrData = NULL;
      
      /**
      * Driver Object created successfully.
      * Create a semaphore now for driver instance.
      */
      edma3Result = edma3OsSemCreate(1, &semAttrs, &initCfg.drvSemHandle);
      if (edma3Result != EDMA3_DRV_SOK)
      {
#ifdef EDMA3_DRV_DEBUG
        EDMA3_DRV_PRINTF("edma3init: edma3OsSemCreate FAILED\r\n");
#endif
      }
      else
      {
        /* Save the semaphore handle for future use */
        semHandle = initCfg.drvSemHandle;
        
        /* Open the Driver Instance */
        hEdma = EDMA3_DRV_open (edma3InstanceId, (void *) &initCfg,
          &edma3Result);
        if(NULL == hEdma)
        {
#ifdef EDMA3_DRV_DEBUG
          EDMA3_DRV_PRINTF("edma3init: EDMA3_DRV_open FAILED\r\n");
#endif
        }
        else
        {
        /**
        * Register Interrupt Handlers for various interrupts
        * like transfer completion interrupt, CC error
        * interrupt, TC error interrupts etc, if required.
          */
          registerEdma3Interrupts();
        }
      }
    }
  }
  else
  {
    /* EDMA3 Driver already initialized, no need to do that again. */
#ifdef EDMA3_DRV_DEBUG
    EDMA3_DRV_PRINTF("edma3init: EDMA3 Driver Already Initialized...Init failed\r\n");
#endif
    edma3Result = EDMA3_DRV_E_INVALID_STATE;
  }
  
  return edma3Result;
}
/**
 *  \brief   EDMA3 misc test cases.
 *              This test case will read/write to some CC registers.
 *
 *  \return  EDMA3_DRV_SOK or EDMA3_DRV Error Code
 */
EDMA3_DRV_Result edma3_misc_test(EDMA3_DRV_Handle hEdma)
    {
    EDMA3_DRV_Result drvResult = EDMA3_DRV_SOK;
    unsigned int ccRegOffset = 0u;
    unsigned int ccRegVal = 0u;
    unsigned int newRegVal = 0u;
    unsigned int origRegVal = 0u;


    /**
     *1. Try fetching some CC registers value.
     * It should PASS.
     */
    /* PID Register */
    ccRegOffset = 0x0u;
    ccRegVal = 0;
    drvResult = EDMA3_DRV_getCCRegister(hEdma, ccRegOffset, &ccRegVal);

    if (drvResult != EDMA3_DRV_SOK)
        {
#ifdef EDMA3_DRV_DEBUG
        EDMA3_DRV_PRINTF ("Fetching CC Register (offset 0X%x) Failed, test FAILED\r\n", ccRegOffset);
#endif
        }
    else
        {
#ifdef EDMA3_DRV_DEBUG
        EDMA3_DRV_PRINTF ("Fetching CC Register (offset 0X%x) Passed, test PASSED\r\n", ccRegOffset);
#endif

#ifdef EDMA3_DEBUG_PRINT
        EDMA3_DEBUG_PRINTF ("Fetched CC Register at Offset 0X%x, Value = 0X%x\r\n", ccRegOffset, ccRegVal);
#endif  /* EDMA3_DEBUG_PRINT */
        }


    if (drvResult == EDMA3_DRV_SOK)
        {
        /* Fetch DRAE1 Register */
        ccRegOffset = 0x0348u;
        ccRegVal = 0;
        drvResult = EDMA3_DRV_getCCRegister(hEdma, ccRegOffset, &ccRegVal);

        if (drvResult != EDMA3_DRV_SOK)
            {
#ifdef EDMA3_DRV_DEBUG
            EDMA3_DRV_PRINTF ("Fetching CC Register (offset 0X%x) Failed, test FAILED\r\n", ccRegOffset);
#endif
            }
        else
            {
#ifdef EDMA3_DRV_DEBUG
            EDMA3_DRV_PRINTF ("Fetching CC Register (offset 0X%x) Passed, test PASSED\r\n", ccRegOffset);
#endif

#ifdef EDMA3_DEBUG_PRINT
            EDMA3_DEBUG_PRINTF ("Fetched CC Register at Offset 0X%x, Value = 0X%x\r\n", ccRegOffset, ccRegVal);
#endif  /* EDMA3_DEBUG_PRINT */
            }
        }


    if (drvResult == EDMA3_DRV_SOK)
        {
        /* Fetch QWMTHRA Register */
        ccRegOffset = 0x0620u;
        ccRegVal = 0;
        drvResult = EDMA3_DRV_getCCRegister(hEdma, ccRegOffset, &ccRegVal);

        if (drvResult != EDMA3_DRV_SOK)
            {
#ifdef EDMA3_DRV_DEBUG
            EDMA3_DRV_PRINTF ("Fetching CC Register (offset 0X%x) Failed, test FAILED\r\n", ccRegOffset);
#endif
            return drvResult;
            }
        else
            {
#ifdef EDMA3_DRV_DEBUG
            EDMA3_DRV_PRINTF ("Fetching CC Register (offset 0X%x) Passed, test PASSED\r\n", ccRegOffset);
#endif

#ifdef EDMA3_DEBUG_PRINT
            EDMA3_DEBUG_PRINTF ("Fetched CC Register at Offset 0X%x, Value = 0X%x\r\n", ccRegOffset, ccRegVal);
#endif  /* EDMA3_DEBUG_PRINT */
            }
        }



    /**
     * 2. Try fetching some CC registers value, whose offset is not 4-bytes
     * aligned. It should FAIL.
     */
    if (drvResult == EDMA3_DRV_SOK)
        {
        ccRegOffset = 0x1002u;
        ccRegVal = 0x0u;
        drvResult = EDMA3_DRV_getCCRegister(hEdma, ccRegOffset, &ccRegVal);

        if (drvResult == EDMA3_DRV_E_INVALID_PARAM)
            {
#ifdef EDMA3_DEBUG_PRINT
            EDMA3_DEBUG_PRINTF ("Fetching Invalid CC Register (offset 0X%x) Failed, test PASSED\r\n", ccRegOffset);
#endif  /* EDMA3_DEBUG_PRINT */
            drvResult = EDMA3_DRV_SOK;
            }
        else
            {
#ifdef EDMA3_DEBUG_PRINT
            EDMA3_DEBUG_PRINTF ("Fetching Invalid CC Register (offset 0X%x) Passed, test FAILED\r\n", ccRegOffset);
#endif  /* EDMA3_DEBUG_PRINT */
            }
        }



    /**
     * 3. Read CC Register QWMTHRA. Store the current value. Write a different
     * value on it. Read it back. Write the original value again. Read it back to
     * cross-check. It should PASS.
     */
    if (drvResult == EDMA3_DRV_SOK)
        {
        ccRegOffset = 0x0620u;
        origRegVal = 0x0u;
        drvResult = EDMA3_DRV_getCCRegister(hEdma, ccRegOffset, &origRegVal);

        if (drvResult != EDMA3_DRV_SOK)
            {
#ifdef EDMA3_DRV_DEBUG
            EDMA3_DRV_PRINTF ("Fetching CC Register (offset 0X%x) Failed, test FAILED\r\n", ccRegOffset);
#endif
            }
        else
            {
#ifdef EDMA3_DRV_DEBUG
            EDMA3_DRV_PRINTF ("Fetching CC Register (offset 0X%x) Passed, test PASSED\r\n", ccRegOffset);
#endif

#ifdef EDMA3_DEBUG_PRINT
            EDMA3_DEBUG_PRINTF ("Fetched CC Register at Offset 0X%x, Value = 0X%x\r\n", ccRegOffset, origRegVal);
#endif  /* EDMA3_DEBUG_PRINT */

            /* Find the new value to be written, it depends on the no of event queues */
            switch (origRegVal)
                {
                /* Write a new value on the same register */
                case 0x10:
                    /* 1 TC */
                    newRegVal = 0x0Fu;
                    break;

                case 0x1010:
                    /* 2 TC */
                    newRegVal = 0x0F0Fu;
                    break;

                case 0x101010:
                    /* 3 TC */
                    newRegVal = 0x0F0F0Fu;
                    break;

                case 0x10101010:
                    /* 4 TC */
                    newRegVal = 0x0F0F0F0Fu;
                    break;

                default:
                    newRegVal = origRegVal;
                    break;
                }

            drvResult = EDMA3_DRV_setCCRegister (hEdma, ccRegOffset, newRegVal);
            if (drvResult == EDMA3_DRV_SOK)
                {
                /* If write is successful, read it back to check */
                ccRegVal = 0x0u;

                drvResult = EDMA3_DRV_getCCRegister (hEdma, ccRegOffset, &ccRegVal);
                if (drvResult == EDMA3_DRV_SOK)
                    {
                    /* Check with the value which we have written */
                    if (newRegVal == ccRegVal)
                        {
#ifdef EDMA3_DEBUG_PRINT
                        EDMA3_DEBUG_PRINTF ("Value written successfully \r\n");
#endif  /* EDMA3_DEBUG_PRINT */
                        }
                    else
                        {
#ifdef EDMA3_DRV_DEBUG
                        EDMA3_DRV_PRINTF ("QWMTHRA write FAILED \r\n");
#endif
                        drvResult = EDMA3_DRV_E_INVALID_PARAM;
                        }
                    }

                /* Restore the original value */
                if (drvResult == EDMA3_DRV_SOK)
                    {
                    drvResult = EDMA3_DRV_setCCRegister (hEdma, ccRegOffset, origRegVal);
                    if (drvResult != EDMA3_DRV_SOK)
                        {
#ifdef EDMA3_DEBUG_PRINT
                        EDMA3_DEBUG_PRINTF ("QWMTHRA Restore FAILED\r\n");
#endif  /* EDMA3_DEBUG_PRINT */
                        }
                    else
                        {
#ifdef EDMA3_DEBUG_PRINT
                        EDMA3_DEBUG_PRINTF ("QWMTHRA Restore Successful\r\n");
#endif  /* EDMA3_DEBUG_PRINT */
                        }
                    }
                }
            }
        }


    return drvResult;
    }