/**********************************************************************

Copyright(c) Analog Devices, Inc. All Rights Reserved. 

This software is proprietary and confidential.  By using this software 
you agree to the terms of the associated Analog Devices License Agreement.  

$RCSfile: adi_bf52xc1.c,v $
$Revision: 1.1 $
$Date: 2008/06/27 03:15:03 $

Description:
    This is source code for BF52xC1 driver (BF52x Audio codec)

***********************************************************************/

/*********************************************************************

Include files

*********************************************************************/

#include <services/services.h>          			/* system service includes  */
#include <drivers/adi_dev.h>            			/* device manager includes  */
#include <drivers/sport/adi_sport.h>    			/* SPORT driver includes    */
#include <drivers/deviceaccess/adi_device_access.h> /* Device Access includes	*/
#include <drivers/codec/adi_bf52xc1.h>   			/* BF52xC1 driver includes  */

/*********************************************************************

Enumerations and defines

*********************************************************************/
/* number of BF52xC1 devices in the system  */
#define ADI_BF52xC1_NUM_DEVICES  	(sizeof(BF52xC1Device)/sizeof(ADI_BF52xC1_DEF)) 

/****************************************************
Macros to manipulate BF52xC1 hardware register access
****************************************************/
/* Number of BF52xC1 registers to cache */
#define ADI_BF52xC1_NUM_REGS_TO_CACHE   10
/* Address of the last register in BF52xC1 */
#define ADI_BF52xC1_FINAL_REG_ADDRESS   0x1FFF
/* BF52xC1 Register Address mask */
#define ADI_BF52xC1_REG_ADDR_MASK       0x1E00
/* BF52xC1 Register Data mask */
#define ADI_BF52xC1_REG_DATA_MASK       0x01FF
/* Shift Count to reach BF52xC1 Register Address */
#define ADI_BF52xC1_REG_ADDR_SHIFT      9
/* Shift count to reach BF52xC1 Sampling control register - Sampling Rate field */
#define ADI_BF52xC1_SHIFT_SR            2
/* Shift count to reach BF52xC1 Sampling control register - CLKDIV2 field       */
#define ADI_BF52xC1_SHIFT_CLKDIV2       6

/****************************************************
Macros to manipulate SPORT Register fields
****************************************************/
#define ADI_SPORT_ITCLK                 0x0002  /* SPORT Internal Transmit clock select     */
#define ADI_SPORT_ITFS                  0x0200  /* SPORT Internal Transmit FS select        */
#define ADI_SPORT_TFSR                  0x0400  /* SPORT Transmit FS required               */
#define ADI_SPORT_LTFS                  0x1000  /* SPORT Active Low Transmit FS select      */
#define ADI_SPORT_LATFS                 0x2000  /* SPORT Late Transmit FS select            */
#define ADI_SPORT_TCKFE                 0x4000  /* SPORT Transmit Clock Falling edge Select */
#define ADI_SPORT_TSFSE                 0x0200  /* SPORT Transmit Stereo FS enable          */

#define ADI_SPORT_IRCLK                 0x0002  /* SPORT Internal Receive clock select      */
#define ADI_SPORT_IRFS                  0x0200  /* SPORT Internal Receive FS select         */
#define ADI_SPORT_RFSR                  0x0400  /* SPORT Receive FS required                */
#define ADI_SPORT_LRFS                  0x1000  /* SPORT Active Low Receive FS select       */
#define ADI_SPORT_LARFS                 0x2000  /* SPORT Late Receive FS select             */
#define ADI_SPORT_RCKFE                 0x4000  /* SPORT Receive Clock Falling edge Select  */
#define ADI_SPORT_RSFSE                 0x0200  /* SPORT Receive Stereo FS enable           */

/****************************************************
SPORT word length (actual wordlength - 1)
****************************************************/
#define ADI_SPORT_SLEN_16               (15)    /* 16 bits */
#define ADI_SPORT_SLEN_20               (19)    /* 20 bits */
#define ADI_SPORT_SLEN_24               (23)    /* 24 bits */
#define ADI_SPORT_SLEN_32               (31)    /* 32 bits */

/****************************************************
Stereo modes supported by BF52xC1 hardware
****************************************************/
/* BF52xC1 driver Auto-SPORT configuration does not support DSP and Right-Justified modes */
enum
{
    BF52xC1_STEREO_MODE_RJ = 0,
    BF52xC1_STEREO_MODE_LJ,
    BF52xC1_STEREO_MODE_I2S,
    BF52xC1_STEREO_MODE_DSP
};

/****************************************************
Data bit lengths supported by BF52xC1
****************************************************/
enum
{
    BF52xC1_WORD_LENGTH_16BITS = 0x00,
    BF52xC1_WORD_LENGTH_20BITS = 0x04,
    BF52xC1_WORD_LENGTH_24BITS = 0x08,
    BF52xC1_WORD_LENGTH_32BITS = 0x0C
};

/****************************************************
BF52xC1 driver status
****************************************************/
enum
{
    ADI_BF52xC1_DRIVER_NOT_IN_USE = 0,   /* BF52xC1 driver instance is not in use                     */
    ADI_BF52xC1_DRIVER_USE_SPI,          /* BF52xC1 driver is set to use SPI to access its registers  */
    ADI_BF52xC1_DRIVER_USE_TWI           /* BF52xC1 driver is set to use TWI to access its registers  */
};

/*********************************************************************

Data Structures

*********************************************************************/

/* Structure to cache SPORT registers to support Auto-SPORT configuration */
typedef struct {
    u16     TCR1;       /* Transmit Control reg 1       */
    u16     TCR2;       /* Transmit Control reg 2       */
    u16     RCR1;       /* Receive Control reg 1        */
    u16     RCR2;       /* Receive Control reg 2        */
}   ADI_BF52xC1_SPORT_REGS;

/* BF52xC1 Driver instance structure */
typedef struct {
    u8                      DriverStatus;                               /* Driver Status                                    */
    u8                      AutoSportEnable;                            /* Enable/Disable Auto-SPORT Configuration          */
    u8                      SportDevNumber;                             /* SPORT Device Number to use                       */
    u8                      SpiTwiDevNumber;                            /* SPI/TWI Device Number to use                     */
    u8                      SpiCS_TwiAddr;                              /* SPI Chip-select (or) TWI Device Address          */
    u16                     BF52xC1Reg[ADI_BF52xC1_NUM_REGS_TO_CACHE];  /* BF52xC1 hardware registers cache                 */
    ADI_BF52xC1_SPORT_REGS  SportReg;                                   /* SPORT register cache to support Auto-SPORT config*/
    ADI_DEV_MANAGER_HANDLE  ManagerHandle;                              /* Device Manager handle                            */
    ADI_DEV_DEVICE_HANDLE   DeviceHandle;                               /* Device instance Handle provided by Device Manager*/
    ADI_DMA_MANAGER_HANDLE  DMAHandle;                                  /* Handle to the DMA manager                        */
    ADI_DCB_HANDLE          DCBHandle;                                  /* Deffered Callback handle                         */
    ADI_DCB_CALLBACK_FN     DMCallback;                                 /* Callback function supplied by the Device Manager */   
    ADI_DEV_PDD_HANDLE      SportHandle;                                /* Handle to the underlying SPORT device driver     */
    ADI_DEV_DIRECTION       Direction;                                  /* data direction                                   */
    void                    *pEnterCriticalArg;                         /* critical region argument                         */
    ADI_DEV_CMD_VALUE_PAIR  *SpiTwiConfigTable;                         /* SPI/TWI Configuration Table passed by the client */
} ADI_BF52xC1_DEF;

/* Create a BF52xC1 device (driver) instance */
ADI_BF52xC1_DEF   BF52xC1Device[] = {
    {
        ADI_BF52xC1_DRIVER_NOT_IN_USE,  /* Driver instance not in use       */
        TRUE,                           /* Auto-SPORT Configuration enabled */
        0,                              /* SPORT Device Number to use       */
        0,                              /* SPI/TWI Device Number to use     */
        0,                              /* SPI Chipselect                   */
        {                               /* clear BF52xC1 register cache     */
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
        },
        {                               /* clear SPORT register cache       */
            0,
            0,
            0,
            0,
        },
        NULL,                           /* Device Manager Handle            */
        NULL,                           /* Device Instance Handle           */
        NULL,                           /* DMA Manager Handle               */
        NULL,                           /* DCB Manager Handle               */
        NULL,                           /* Device Manager Callback Function */
        NULL,                           /* SPORT Driver Handle              */
        ADI_DEV_DIRECTION_UNDEFINED,    /* Direction Undefined              */
        NULL,                           /* Critical region argument         */
        NULL,                           /* No SPI/TWI config table to use   */
    }
};

/*********************************************************************

Static functions

*********************************************************************/

static u32 adi_pdd_Open(                        /* Opens BF52xC1 device                     */
    ADI_DEV_MANAGER_HANDLE  ManagerHandle,      /* Device Manager handle                    */
    u32                     DeviceNumber,       /* BF52xC1 Device number to open            */
    ADI_DEV_DEVICE_HANDLE   DeviceHandle,       /* Device handle                            */
    ADI_DEV_PDD_HANDLE      *pPDDHandle,        /* pointer to PDD handle location           */
    ADI_DEV_DIRECTION       Direction,          /* data direction                           */
    void                    *pEnterCriticalArg, /* critical region storage location         */
    ADI_DMA_MANAGER_HANDLE  DMAHandle,          /* handle to the DMA manager                */
    ADI_DCB_HANDLE          DCBHandle,          /* callback handle                          */
    ADI_DCB_CALLBACK_FN     DMCallback          /* device manager callback function         */
);

static u32 adi_pdd_Close(                       /* Closes a BF52xC1 device                  */
    ADI_DEV_PDD_HANDLE      PDDHandle           /* PDD handle of the BF52xC1 device to close*/
);

static u32 adi_pdd_Read(                        /* Queues Inbound buffers to BF52xC1 SPORT  */ 
    ADI_DEV_PDD_HANDLE      PDDHandle,          /* PDD handle of BF52xC1 device             */
    ADI_DEV_BUFFER_TYPE     BufferType,         /* Buffer type                              */
    ADI_DEV_BUFFER          *pBuffer            /* pointer to buffer                        */
);
    
static u32 adi_pdd_Write(                       /* Queues Outbound buffers to BF52xC1 SPORT */
    ADI_DEV_PDD_HANDLE      PDDHandle,          /* PDD handle of a BF52xC1 device           */
    ADI_DEV_BUFFER_TYPE     BufferType,         /* Buffer type                              */
    ADI_DEV_BUFFER          *pBuffer            /* pointer to buffer                        */
);

static u32 adi_pdd_SequentialIO(                /* Sequentially read/writes data to a device*/ 
    ADI_DEV_PDD_HANDLE      PDDHandle,          /* PDD handle of BF52xC1 device             */
    ADI_DEV_BUFFER_TYPE     BufferType,         /* Buffer type                              */
    ADI_DEV_BUFFER          *pBuffer            /* pointer to buffer                        */
);

static u32 adi_pdd_Control(                     /* Sets or senses device specific parameter */
    ADI_DEV_PDD_HANDLE      PDDHandle,          /* PDD handle of BF52xC1 device             */
    u32                     Command,            /* Command ID                               */
    void                    *Value              /* Command specific value                   */
);

static u32 adi_bf52xc1_RegAccess(               /* Function to Access BF52xC1 registers     */
    ADI_BF52xC1_DEF         *pDevice,           /* pointer to the driver instance           */
    u32                     Command,            /* Command ID passed by the application     */
    void                    *Value              /* Command specific value                   */
);

static u32 adi_bf52xc1_DeviceAccess(          	/* Writes to a BF52xC1 hardware register using Device Access Service*/
    ADI_BF52xC1_DEF         *pDevice,           /* pointer to the driver instance                                   */
    ADI_DEV_ACCESS_REGISTER *AccessBF52xC1      /* BF52xC1 register access info                                     */
);

static u32 adi_bf52xc1_UpdateDriverCache(       /* Function to update BF52xC1 register cache*/
    ADI_BF52xC1_DEF         *pDevice,           /* pointer to the driver instance           */
    ADI_DEV_ACCESS_REGISTER *AccessBF52xC1      /* BF52xC1 register access info             */
);

static u32 adi_bf52xc1_UpdateSampleRate(        /* Updates BF52xC1 Sample Control register to match ADC/DAC sampling rate   */
    ADI_BF52xC1_DEF         *pDevice,           /* pointer to the driver instance                                           */
    ADI_BF52xC1_SAMPLE_RATE *pSampleRate        /* pointer to structure holding ADC/DAC Sample rates                        */
);

static u32 adi_bf52xc1_SportOpen(               /* Function to open a SPORT device          */
    ADI_BF52xC1_DEF         *pDevice            /* pointer to the driver instance           */
);

static u32 adi_bf52xc1_ConfigSport(             /* Function to Configure SPORT registers    */
    ADI_BF52xC1_DEF         *pDevice            /* pointer to the driver instance           */
);

static void adi_bf52xc1_SportCallback(          /* Callback function passed to SPORT driver */
    void*                   DeviceHandle,       /* Callback Handle passed by BF52xC1        */
    u32                     Event,              /* Callback Event                           */
    void*                   pArg                /* Callback Argument                        */
);

/*********************************************************************

Debug Mode functions (debug build only)

*********************************************************************/
/* Debug Build only */
#if defined(ADI_DEV_DEBUG)

static u32 adi_bf52xc1_ValidateRegAccess(       /* Function to validate register access table   */
    ADI_BF52xC1_DEF         *pDevice,           /* pointer to the driver instance               */
    u32                     Command,            /* Command ID passed by the application         */
    void                    *Value              /* Command specific value                       */
);

static u32 ValidatePDDHandle(                   /* Validates Physical Device Driver Handle  */
    ADI_DEV_PDD_HANDLE      PDDHandle           /* PDD handle of a BF52xC1 device            */
);

#endif

/*********************************************************************

Entry point for device manager

*********************************************************************/

ADI_DEV_PDD_ENTRY_POINT ADIBF52xC1EntryPoint = {
    adi_pdd_Open,
    adi_pdd_Close,
    adi_pdd_Read,
    adi_pdd_Write,    
    adi_pdd_Control,
    adi_pdd_SequentialIO
};

/*********************************************************************

    Function:       adi_pdd_Open

    Description:    Opens a BF52xC1 device for use

*********************************************************************/

static u32 adi_pdd_Open(                        /* Open BF52xC1 device              */
    ADI_DEV_MANAGER_HANDLE  ManagerHandle,      /* Device Manager handle            */
    u32                     DeviceNumber,       /* BF52xC1 Device number to open    */
    ADI_DEV_DEVICE_HANDLE   DeviceHandle,       /* Device handle                    */
    ADI_DEV_PDD_HANDLE      *pPDDHandle,        /* pointer to PDD handle location   */
    ADI_DEV_DIRECTION       Direction,          /* data direction                   */
    void                    *pEnterCriticalArg, /* critical region storage location */
    ADI_DMA_MANAGER_HANDLE  DMAHandle,          /* handle to the DMA manager        */
    ADI_DCB_HANDLE          DCBHandle,          /* callback handle                  */
    ADI_DCB_CALLBACK_FN     DMCallback          /* device manager callback function */
) 
{   
    /* Return value - assume we're going to be successful   */
    u32 Result = ADI_DEV_RESULT_SUCCESS;
    /* pointer to the device we're working on               */
    ADI_BF52xC1_DEF  *pDevice;
    /* exit critical region parameter                       */
    void    *pExitCriticalArg;
	/* structure to access one BF52xC1 register */
    ADI_DEV_ACCESS_REGISTER AccessBF52xC1;
    
/* for Debug build only - check for errors if required  */
#if defined(ADI_DEV_DEBUG)

    if (DeviceNumber >= ADI_BF52xC1_NUM_DEVICES)     /* check the device number */
    {
        Result = ADI_DEV_RESULT_BAD_DEVICE_NUMBER;  /* Invalid Device number */
    }
    
    /*  Continue only if the device number is valid */
    if (Result == ADI_DEV_RESULT_SUCCESS)
    {
#endif
        /* insure the device the client wants is available  */
        Result  = ADI_DEV_RESULT_DEVICE_IN_USE;
        /* BF52xC1 device we're working on */
        pDevice = &BF52xC1Device[DeviceNumber];
    
        /* Protect this section of code - entering a critical region    */
        pExitCriticalArg = adi_int_EnterCriticalRegion(pEnterCriticalArg);
        /* Check the device usage status*/
        if (pDevice->DriverStatus == ADI_BF52xC1_DRIVER_NOT_IN_USE) 
        {
            /* Device is not in use. Reserve the device for this client */
            /* Set driver to use SPI 0 by default */
            pDevice->DriverStatus = ADI_BF52xC1_DRIVER_USE_SPI;
            Result = ADI_DEV_RESULT_SUCCESS;
        }
        /* Exit the critical region */
        adi_int_ExitCriticalRegion(pExitCriticalArg);
        
        /* Continue only when the BF52xC1 device is available for use  */
        if (Result == ADI_DEV_RESULT_SUCCESS) 
        {
            /* initialise the device settings */
            /* Save the Device Manager handle */
            pDevice->ManagerHandle      = ManagerHandle;
            /* Save the Device handle */
            pDevice->DeviceHandle       = DeviceHandle;
            /* Save the DMA handle */
            pDevice->DMAHandle          = DMAHandle;
            /* Save the DCB handle */
            pDevice->DCBHandle          = DCBHandle;
            /* Save the Device Manager callback function handle */
            pDevice->DMCallback         = DMCallback;
            /* Save the Device direction */
            pDevice->Direction          = Direction;
            /* Pointer to critical region                   */
            pDevice->pEnterCriticalArg  = pEnterCriticalArg;
            /* Clear the SPORT handle */
            pDevice->SportHandle        = NULL;
            
            /* Initialise BF52xC1 register cache & SPORT register cache to default values */
            /* issue a dummy BF52xC1 soft-reset within the driver */
			/* Shift the register address (Bit 15 to Bit 9 in BF52xC1 write packet holds the register address to configure) */
    		AccessBF52xC1.Address = ((BF52xC1_REG_RESET << ADI_BF52xC1_REG_ADDR_SHIFT) & ADI_BF52xC1_REG_ADDR_MASK);
    		/* Bit 8 to Bit 0 in BF52xC1 write packet holds the register data (zero to reset BF52xC1) */
            /* call update driver cache to reset BF52xC1 register cache & SPORT register cache */
            Result = adi_bf52xc1_UpdateDriverCache(pDevice,&AccessBF52xC1);
            
            /* Auto-SPORT Configuration is enabled by default */
            pDevice->AutoSportEnable= TRUE;
            /* By default, use SPORT 0 for audio dataflow */
            pDevice->SportDevNumber = 0;
            /* By default, use SPI 0 to access BF52xC1 registers */
            pDevice->SpiTwiDevNumber= 0;
            /* By default, no valid SPI chipselect is available to select BF52xC1 */
            pDevice->SpiCS_TwiAddr  = 0;
            /* No SPI or TWI configuration is available */
            pDevice->SpiTwiConfigTable = NULL;
            /* Save physical device handle in the client supplied location */
            *pPDDHandle = (ADI_DEV_PDD_HANDLE *)pDevice;
        }

/* for Debug build only */
#if defined(ADI_DEV_DEBUG)
    }
#endif

    /* return */
    return(Result);
}

/*********************************************************************

    Function:       adi_pdd_Close

    Description:    Closes down a BF52xC1 device

*********************************************************************/

static u32 adi_pdd_Close(                       /* Closes a BF52xC1 device                   */
    ADI_DEV_PDD_HANDLE      PDDHandle           /* PDD handle of the BF52xC1 device to close */
)
{  
    /* Return value - assume we're going to be successful   */
    u32 Result = ADI_DEV_RESULT_SUCCESS;
    /* pointer to the device we're working on               */
    ADI_BF52xC1_DEF  *pDevice = (ADI_BF52xC1_DEF *)PDDHandle;
    /* structure to access one BF52xC1 register */
    ADI_DEV_ACCESS_REGISTER AccessBF52xC1;
    
/* for Debug build only - check for errors if required  */
#if defined(ADI_DEV_DEBUG)
    /* Validate the given PDDHandle */
    Result = ValidatePDDHandle(PDDHandle);
    
    /* Continue only if the given PDDHandle is valid */
    if (Result == ADI_DEV_RESULT_SUCCESS)
    {    
#endif
        /* Check if any SPORT device is open */
        if (pDevice->SportHandle)
        {
            /* Close the SPORT device */
            Result = adi_dev_Close(pDevice->SportHandle);
        }

        /* Check if the SPORT device is properly closed or not */
        if (Result == ADI_DEV_RESULT_SUCCESS)
        {
            /* Soft-Reset BF52xC1 before closing this driver instance */
            if ((pDevice->DriverStatus == ADI_BF52xC1_DRIVER_USE_TWI) ||
                ((pDevice->DriverStatus == ADI_BF52xC1_DRIVER_USE_SPI) &&
                (pDevice->SpiCS_TwiAddr != 0)))
            {
            	/*** Packet the Reset register address and data as per BF52xC1 register configuration requirements ***/
    			/* Shift the register address (Bit 15 to Bit 9 in BF52xC1 write packet holds the register address to configure) */
    			AccessBF52xC1.Address = ((BF52xC1_REG_RESET << ADI_BF52xC1_REG_ADDR_SHIFT) & ADI_BF52xC1_REG_ADDR_MASK);
    			/* Bit 8 to Bit 0 in BF52xC1 write packet holds the register data (zero to reset BF52xC1) */
                /* soft-reset BF52xC1 */
                Result = adi_bf52xc1_DeviceAccess(pDevice,&AccessBF52xC1);
            }
            
            /* Mark this BF52xC1 device as closed */
            pDevice->DriverStatus = ADI_BF52xC1_DRIVER_NOT_IN_USE;
        }

/* for Debug build only */
#if defined(ADI_DEV_DEBUG)
    }
#endif

    /* return */
    return(Result);
}

/*********************************************************************

    Function:       adi_pdd_Read

    Description:    Queues BF52xC1 ADC Interleaved buffer(s)

*********************************************************************/
static u32 adi_pdd_Read(                /* Queues BF52xC1 ADC Interleaved buffer(s)  */ 
    ADI_DEV_PDD_HANDLE      PDDHandle,  /* PDD handle of a BF52xC1 device            */
    ADI_DEV_BUFFER_TYPE     BufferType, /* Buffer type                              */
    ADI_DEV_BUFFER          *pBuffer    /* pointer to buffer                        */
){
    
    /* Return value - assume we're going to be successful   */
    u32 Result = ADI_DEV_RESULT_SUCCESS;
    /* pointer to the device we're working on               */
    ADI_BF52xC1_DEF  *pDevice = (ADI_BF52xC1_DEF *)PDDHandle;
    
/* for Debug build only - check for errors if required  */
#if defined(ADI_DEV_DEBUG)
    /* Validate the given PDDHandle */
    Result = ValidatePDDHandle(PDDHandle);
    /* Continue only if the given PDDHandle is valid */
    if (Result == ADI_DEV_RESULT_SUCCESS)
    {    
#endif
        
        /* pass the read operation to SPORT driver */
        Result = adi_dev_Read(pDevice->SportHandle, BufferType, pBuffer);

/* for Debug build only */
#if defined(ADI_DEV_DEBUG)
    }
#endif

    /* return */
    return(Result);
}

/*********************************************************************

    Function:       adi_pdd_Write

    Description:    Queues BF52xC1 DAC Interleaved buffer(s)

*********************************************************************/
static u32 adi_pdd_Write(               /* Queues BF52xC1 DAC Interleaved buffer(s)  */ 
    ADI_DEV_PDD_HANDLE      PDDHandle,  /* PDD handle of a BF52xC1 device            */
    ADI_DEV_BUFFER_TYPE     BufferType, /* Buffer type                              */
    ADI_DEV_BUFFER          *pBuffer    /* pointer to buffer                        */
){
    
    /* Return value - assume we're going to be successful   */
    u32 Result = ADI_DEV_RESULT_SUCCESS;
    /* pointer to the device we're working on               */
    ADI_BF52xC1_DEF  *pDevice = (ADI_BF52xC1_DEF *)PDDHandle;
    
/* for Debug build only - check for errors if required  */
#if defined(ADI_DEV_DEBUG)
    /* Validate the given PDDHandle */
    Result = ValidatePDDHandle(PDDHandle);
    /* Continue only if the given PDDHandle is valid */
    if (Result == ADI_DEV_RESULT_SUCCESS)
    {    
#endif
        
        /* pass the write operation to SPORT driver */
        Result = adi_dev_Write(pDevice->SportHandle, BufferType, pBuffer);

/* for Debug build only */
#if defined(ADI_DEV_DEBUG)
    }
#endif

    /* return */
    return(Result);
}

/*********************************************************************

    Function:       adi_pdd_SequentialIO

    Description:    Sequentially read/writes data to a device
                    BF52xC1 driver does not support this function

*********************************************************************/
static u32 adi_pdd_SequentialIO(        /* BF52xC1 does not support this function    */ 
    ADI_DEV_PDD_HANDLE      PDDHandle,  /* PDD handle of a BF52xC1 device            */
    ADI_DEV_BUFFER_TYPE     BufferType, /* Buffer type                              */
    ADI_DEV_BUFFER          *pBuffer    /* pointer to buffer                        */
){
    
    /* this function is not supported by BF52xC1 driver */
    return(ADI_DEV_RESULT_NOT_SUPPORTED);
}

/*********************************************************************

    Function:       adi_pdd_Control

    Description:    Senses or Configures BF52xC1 device registers

*********************************************************************/
static u32 adi_pdd_Control(             /* Sets or senses device specific parameter */
    ADI_DEV_PDD_HANDLE  PDDHandle,      /* PDD handle of a BF52xC1 device            */
    u32                 Command,        /* Command ID                               */
    void                *Value          /* Command specific value                   */
){
    /* Return value - assume we're going to be successful   */
    u32 Result = ADI_DEV_RESULT_SUCCESS;
    /* pointer to the device we're working on               */
    ADI_BF52xC1_DEF  *pDevice;
    u32 u32Value;       /* u32 type to avoid casts/warnings etc.    */ 
    u8  u8Value;        /* u8 type to avoid casts/warnings etc.    */ 
    
    /* avoid casts */
    pDevice = (ADI_BF52xC1_DEF *)PDDHandle;
    /* assign 8 & 32 bit values for the Value argument */
    u32Value = (u32)Value;
    u8Value = (u8)u32Value;
    /* structure to access one BF52xC1 register */
    ADI_DEV_ACCESS_REGISTER AccessBF52xC1;
    
/* for Debug build only - check for errors if required  */
#if defined(ADI_DEV_DEBUG)
    /* Validate the given PDDHandle */
    Result = ValidatePDDHandle(PDDHandle);
    
    /* Continue only if the given PDDHandle is valid */
    if (Result == ADI_DEV_RESULT_SUCCESS)
    {    
#endif
        /* CASEOF (Command ID)  */
        switch (Command)
        {
            /* CASE: Control dataflow */
            case (ADI_DEV_CMD_SET_DATAFLOW):
                /* Register access to update BF52xC1 Active Control register */
                AccessBF52xC1.Address = (BF52xC1_REG_ACTIVE_CTRL << ADI_BF52xC1_REG_ADDR_SHIFT);
                /* IF (SPORT device allocated to BF52xC1 is open) */
                if (pDevice->SportHandle != NULL)
                {
                    /* IF (enable Dataflow) */
                    if (u8Value == TRUE)
                    {
                        /* Activate BF52xC1 Digital Audio Interface */
    	                AccessBF52xC1.Address |= 1;
                    }
                    /* update BF52xC1 Active Control register */
                    Result = adi_bf52xc1_DeviceAccess(pDevice,&AccessBF52xC1);
                    if (Result == ADI_DEV_RESULT_SUCCESS)
                    {
                        /* Enable/Disable SPORT dataflow */
                        Result = adi_dev_Control(pDevice->SportHandle, Command, Value);
                    }
                }
                /* ELSE IF (client is trying to enable dataflow with SPORT device closed) */
                else if (u8Value == TRUE)
                {
                    /* can not pass this command to SPORT, as no valid SPORT handle is available */
                    /* which means that dataflow method is not defined yet */
                    Result = ADI_DEV_RESULT_DATAFLOW_UNDEFINED;
                    break;
                }
                break;
            
            /* CASE: Query for processor DMA support */
            case (ADI_DEV_CMD_GET_PERIPHERAL_DMA_SUPPORT):
        
                /* BF52xC1 doesn't support DMA, but supports indirectly via SPORT */
                *((u32 *)Value) = FALSE;
                break;

            /* CASE: Set Dataflow method */
            case (ADI_DEV_CMD_SET_DATAFLOW_METHOD):

                /* IF (SPORT device allocated to BF52xC1 is not open) */
                if (pDevice->SportHandle == NULL)
                {
                    /* Try to open the SPORT device 'pDevice->SportDevNumber' */
                    Result = adi_bf52xc1_SportOpen(pDevice);
                }
/* for Debug build only - exit on error */
#if defined(ADI_DEV_DEBUG)
                if (Result != ADI_DEV_RESULT_SUCCESS)
                {
                    break;
                }
#endif  /* ADI_DEV_DEBUG */

                /* Pass the dataflow method to the SPORT device */
                Result = adi_dev_Control(pDevice->SportHandle, Command, Value);
                break;

            /************************
            SPI related commands
            ************************/

            /* CASE: Set BF52xC1 driver to use SPI to access BF52xC1 hardware registers */
            case (ADI_BF52xC1_CMD_SET_SPI_DEVICE_NUMBER):
                /* store SPI device number */
                pDevice->SpiTwiDevNumber = u8Value;
                /* update driver status */
                pDevice->DriverStatus = ADI_BF52xC1_DRIVER_USE_SPI;
                break;

            /* CASE: Set SPI Chipselect for BF52xC1 */
            case (ADI_BF52xC1_CMD_SET_SPI_CS):
                /* store the chipselect value */
                pDevice->SpiCS_TwiAddr = u8Value;
                break;
            
            /************************
            TWI related commands
            ************************/

            /* CASE: Set BF52xC1 driver to use TWI to access BF52xC1 hardware registers */
            case (ADI_BF52xC1_CMD_SET_TWI_DEVICE_NUMBER):
                /* store TWI device number */
                pDevice->SpiTwiDevNumber = u8Value;
                /* update driver status */
                pDevice->DriverStatus = ADI_BF52xC1_DRIVER_USE_TWI;
                /* Set default TWI Global Address for BF52xC1 */
                /* IF (TWI Global address is valid) */
                if ((pDevice->SpiCS_TwiAddr == 0x1A) ||
                    (pDevice->SpiCS_TwiAddr == 0x1B))
                {
                    break;  /* do nothing */
                }
                /* TWI Global address is not valid */
                else
                {
                    /* set BF52xC1 TWI Global address to default */
                    pDevice->SpiCS_TwiAddr = 0x1A;
                }
                break;
            
            /* CASE: Set TWI Global Address for BF52xC1 */
            case (ADI_BF52xC1_CMD_SET_TWI_GLOBAL_ADDR):
/* for Debug build only - validate TWI Global Address */
#if defined(ADI_DEV_DEBUG)
                if ((u8Value != 0x1A) && (u8Value != 0x1B))
                {
                    Result = ADI_BF52xC1_RESULT_TWI_GLOBAL_ADDRESS_INVALID;
                    break;
                }
#endif  /* ADI_DEV_DEBUG */
                /* store the TWI Global address for BF52xC1 */
                pDevice->SpiCS_TwiAddr = u8Value;
                break;

            /************************
            SPORT related commands
            ************************/
            
            /* CASE: Set  TWI or SPI configuration table to be used to access BF52xC1 device registers */
            case (ADI_BF52xC1_CMD_SET_TWI_SPI_CONFIG_TABLE):
                /* store the configuration table address */
                pDevice->SpiTwiConfigTable = (ADI_DEV_CMD_VALUE_PAIR*) Value;;
                break;
                
            /************************
            SPORT related commands
            ************************/

            /* CASE: Set SPORT device number connected to BF52xC1 Digital Audio Interface port */
            case (ADI_BF52xC1_CMD_SET_SPORT_DEVICE_NUMBER):
                /* IF (any SPORT device already in use) */
                if (pDevice->SportHandle != NULL)
                {
                    /* Close the SPORT device */
                    Result = adi_dev_Close(pDevice->SportHandle);
                    
/* for Debug build only - exit on error */
#if defined(ADI_DEV_DEBUG)
                    if (Result != ADI_DEV_RESULT_SUCCESS)
                    {
                        break;
                    }
#endif  /* ADI_DEV_DEBUG */
                    /* Clear SPORT device handle */
                    pDevice->SportHandle = NULL;
                }
                /* store SPORT device number */
                pDevice->SportDevNumber = u8Value;
                /* Application should set dataflow method for this SPORT device, load data buffer(s) & Enable dataflow */
                break;
            
            /* CASE: Open/Close SPORT device connected to BF52xC1 */
            case (ADI_BF52xC1_CMD_OPEN_SPORT_DEVICE):
                /* IF (Open SPORT device) */
                if (u8Value == TRUE)
                {
                    /* IF (SPORT device allocated to BF52xC1 is not in use) */
                    if (pDevice->SportHandle == NULL)
                    {
                        /* Open the SPORT device and reserve it for BF52xC1 use */
                        Result = adi_bf52xc1_SportOpen(pDevice);
                    }
                }
                /* ELSE (Close SPORT device) */
                else
                {
                    /* IF (any SPORT device already in use) */
                    if (pDevice->SportHandle != NULL)
                    {
                        /* Close the SPORT device */
                        Result = adi_dev_Close(pDevice->SportHandle);
                        
/* for Debug build only - exit on error */
#if defined(ADI_DEV_DEBUG)
                        if (Result != ADI_DEV_RESULT_SUCCESS)
                        {
                            break;
                        }
#endif  /* ADI_DEV_DEBUG */
                        /* Clear SPORT device handle */
                        pDevice->SportHandle = NULL;
                    }
                }
                break;

            /* CASE: Enable/Disable Auto-SPORT configuration mode */
            case (ADI_BF52xC1_CMD_ENABLE_AUTO_SPORT_CONFIG):
                pDevice->AutoSportEnable = u8Value;
                /* Update SPORT configuration */
                Result = adi_bf52xc1_ConfigSport(pDevice);
                break;

            /* CASE: Set BF52xC1 Sampling Control register to given ADC and DAC sample rate */
            case (ADI_BF52xC1_CMD_SET_SAMPLE_RATE):
                if ((((ADI_BF52xC1_SAMPLE_RATE*)Value)->AdcSampleRate) &&
                    (((ADI_BF52xC1_SAMPLE_RATE*)Value)->DacSampleRate))
                {
                    /* Update BF52xC1 sampling control register */
                    Result = adi_bf52xc1_UpdateSampleRate(pDevice,(ADI_BF52xC1_SAMPLE_RATE*)Value);
                }
                break;

            /* other commands */
            default:
                /* pass this command to BF52xC1 Register Access Function */
                Result = adi_bf52xc1_RegAccess(pDevice,Command,Value);
                break;

        /* ENDCASE */
        }
        
/* for Debug build only */
#if defined(ADI_DEV_DEBUG)
    }
#endif

    /* return */
    return(Result);
}

/*********************************************************************

    Function:       adi_bf52xc1_RegAccess

    Description:    Configures BF52xC1 hardware registers,
                    Reads BF52xC1 register values from driver cache

*********************************************************************/
static u32 adi_bf52xc1_RegAccess(                /* Function to Access BF52xC1 registers      */
    ADI_BF52xC1_DEF          *pDevice,           /* pointer to the driver instance           */
    u32                     Command,            /* Command ID passed by the application     */
    void                    *Value              /* Command specific value                   */
){
    /* default return code */
    u32 Result = ADI_DEV_RESULT_SUCCESS;

    /* pointer to selective register access table */
    ADI_DEV_ACCESS_REGISTER         *pSelectiveAccess;
    /* pointer to block register access table */
    ADI_DEV_ACCESS_REGISTER_BLOCK   *pBlockAccess;
    /* pointer to register field access table */
    ADI_DEV_ACCESS_REGISTER_FIELD   *pFieldAccess;
    
    /* register access table to be passed to the Device Access Service */
    ADI_DEV_ACCESS_REGISTER         AccessBF52xC1;

    u16 RegAddr,RegData,FieldData,i,CacheIndex;
    
/* for Debug build only - Check for errors */
#if defined(ADI_DEV_DEBUG)
    /* Validate the given register access table */
    Result = adi_bf52xc1_ValidateRegAccess(pDevice,Command,Value);

    /* Continue only if the given register access table is valid */
    if (Result == ADI_DEV_RESULT_SUCCESS)
    {
#endif  /* ADI_DEV_DEBUG */
   
        /* CASEOF (Device Access Command) */
        switch (Command)
        {
            /* CASE (Read a specific BF52xC1 Register) */
            case (ADI_DEV_CMD_REGISTER_READ):
            /* CASE (Read a table of BF52xC1 registers) */
            case(ADI_DEV_CMD_REGISTER_TABLE_READ):
        
                /* get the address of selective register access table submitted by the app */
                pSelectiveAccess = (ADI_DEV_ACCESS_REGISTER *) Value;

                /* access all registers in application provided access table until we reach the delimiter */
                while (pSelectiveAccess->Address != ADI_DEV_REGEND)  
                {
                    /* copy the register value from driver register cache */
                    pSelectiveAccess->Data = pDevice->BF52xC1Reg[pSelectiveAccess->Address];
                    /* IF (the command is to access a single register) */
                    if (Command == ADI_DEV_CMD_REGISTER_READ)
                    {
                        break;  /* done with register access. exit this loop */
                    }
                    pSelectiveAccess++; /* move to next selective register access info */
                }
                break;

            /* CASE (Configure a BF52xC1 Resigter) */
            case(ADI_DEV_CMD_REGISTER_WRITE):
            /* CASE (Configure a table BF52xC1 registers) */
            case(ADI_DEV_CMD_REGISTER_TABLE_WRITE): 
        
                /* get the address of selective register access table submitted by the app */
                pSelectiveAccess = (ADI_DEV_ACCESS_REGISTER *) Value;

                /* access all registers in application provided access table until we reach the delimiter */
                while (pSelectiveAccess->Address != ADI_DEV_REGEND)  
                {
                    /*** Packet this register address and data as per BF52xC1 register configuration requirements ***/
                    /* Shift the register address (Bit 15 to Bit 9 in BF52xC1 write packet holds the register address to configure) */
                    AccessBF52xC1.Address = ((pSelectiveAccess->Address << ADI_BF52xC1_REG_ADDR_SHIFT) & ADI_BF52xC1_REG_ADDR_MASK);
                    /* Bit 8 to Bit 0 in BF52xC1 write packet holds the register data */
                    AccessBF52xC1.Address |= (pSelectiveAccess->Data & ADI_BF52xC1_REG_DATA_MASK);
                    
                    /* Pass the new register data to device access service which inturn configures BF52xC1 */
                    Result = adi_bf52xc1_DeviceAccess(pDevice,&AccessBF52xC1);

/* for Debug build only - exit on error */
#if defined(ADI_DEV_DEBUG)
                    if (Result != ADI_DEV_RESULT_SUCCESS)
                    {
                        break;
                    }
#endif  /* ADI_DEV_DEBUG */

                    /* IF (the command is to access a single register) */
                    if (Command == ADI_DEV_CMD_REGISTER_WRITE)
                    {
                        break;  /* done with register access. exit this loop */
                    }
                    pSelectiveAccess++; /* move to next selective register access info */
                }
                break;

            /* CASE (Read a specific BF52xC1 register field) */
            case(ADI_DEV_CMD_REGISTER_FIELD_READ):
            /* CASE (Read a table BF52xC1 register(s) field(s)) */
            case(ADI_DEV_CMD_REGISTER_FIELD_TABLE_READ):

                /* get the address of Field access table submitted by the app */
                pFieldAccess = (ADI_DEV_ACCESS_REGISTER_FIELD *) Value;

                /* access all registers in application provided access table until we reach the delimiter */
                while (pFieldAccess->Address != ADI_DEV_REGEND)  
                {
                    /* read register value from driver register cache & extract the field data we're interested in */
                    FieldData = (pDevice->BF52xC1Reg[pFieldAccess->Address] & pFieldAccess->Field);
                   
                    /* use the register field mask to determine the 
                       shift count required to reach first bit of this register field */
                    for (i = pFieldAccess->Field; i; i >>= 1)
                    {
                        /* check if we've reached the first bit location of this field */
                        if (i & 1)
                        {
                            break;  /* reached first bit of this field. exit this loop */
                        }
                        /* shift 'FieldData' to report the exact field value back to application */
                        FieldData >>= 1;
                    }
                    
                    /* pass this register field value to the application */
                    pFieldAccess->Data = FieldData;
                    /* IF (the command is to access a single register) */
                    if (Command == ADI_DEV_CMD_REGISTER_FIELD_READ)
                    {
                        break;  /* done with register access. exit this loop */
                    }
                    pFieldAccess++; /* move to next register field access info */
                }
                
                break;
                
            /* CASE (Configure a specific BF52xC1 register field) */
            case(ADI_DEV_CMD_REGISTER_FIELD_WRITE):
            /* CASE (Configure a table BF52xC1 register(s) field(s)) */
            case(ADI_DEV_CMD_REGISTER_FIELD_TABLE_WRITE):
                
                /* get the address of Field access table submitted by the app */
                pFieldAccess = (ADI_DEV_ACCESS_REGISTER_FIELD *) Value;

                /* access all registers in application provided access table until we reach the delimiter */
                while (pFieldAccess->Address != ADI_DEV_REGEND)  
                {
                    /* get the present register data from driver register cache */
                    RegData = pDevice->BF52xC1Reg[pFieldAccess->Address];
                    /* Get the register field data passed by teh application */
                    FieldData = pFieldAccess->Data;
                   
                    /* use the register field mask to determine the 
                       shift count required to reach first bit of this register field */
                    for (i = pFieldAccess->Field; i; i >>= 1)
                    {
                        /* check if we've reached the first bit location of this field */
                        if (i & 1)
                        {
                            break;  /* reached first bit of this field. exit this loop */
                        }
                        /* shift the 'FieldData' until we reach its corresponding field location */
                        FieldData <<= 1;
                    }
                    /* clear the register field that we're about to update */
                    RegData &= ~pFieldAccess->Field;
                    /* update the register field with new value */
                    RegData |= (FieldData & pFieldAccess->Field);
                    
                    /*** Packet this register address and data as per BF52xC1 register configuration requirements ***/
                    /* Shift the register address (Bit 15 to Bit 9 in BF52xC1 write packet holds the register address to configure) */
                    AccessBF52xC1.Address = ((pFieldAccess->Address << ADI_BF52xC1_REG_ADDR_SHIFT) & ADI_BF52xC1_REG_ADDR_MASK);
                    /* Bit 8 to Bit 0 in BF52xC1 write packet holds the register data */
                    AccessBF52xC1.Address |= RegData;
                    /* Pass the new register data to device access service which inturn configures BF52xC1 */
                    Result = adi_bf52xc1_DeviceAccess(pDevice,&AccessBF52xC1);

/* for Debug build only - exit on error */
#if defined(ADI_DEV_DEBUG)
                    if (Result != ADI_DEV_RESULT_SUCCESS)
                    {
                        break;
                    }
#endif  /* ADI_DEV_DEBUG */

                    /* IF (the command is to access a single register) */
                    if (Command == ADI_DEV_CMD_REGISTER_FIELD_WRITE)
                    {
                        break;  /* done with register access. exit this loop */
                    }
                    pFieldAccess++; /* move to next register field access info */
                }
                
                break;
        
            /* CASE (Read block of BF52xC1 registers starting from first given address) */
            case(ADI_DEV_CMD_REGISTER_BLOCK_READ):
            
                /* get the address of Block access table submitted by the app */
                pBlockAccess = (ADI_DEV_ACCESS_REGISTER_BLOCK *) Value;
                /* Load the register block start address */
                RegAddr = pBlockAccess->Address;
                
                /* Access all the registers requested by the application */
                for (i = 0; i < pBlockAccess->Count ; i++)
                {
                    /* copy the register value from driver register cache */
                    *(pBlockAccess->pData+i) = pDevice->BF52xC1Reg[RegAddr];

                    /* IF (Register address exceeds the limit) */
                    if (RegAddr > BF52xC1_REG_ACTIVE_CTRL)
                    {
                        break;  /* no more registers left to read */
                    }
                    else
                    {
                        /* Move to next register address to access */
                        RegAddr++;
                    }
                }
                
                break;
                
            /* CASE (Write to a block of BF52xC1 registers starting from first given address) */
            case(ADI_DEV_CMD_REGISTER_BLOCK_WRITE):
            
                /* get the address of Block access table submitted by the app */
                pBlockAccess = (ADI_DEV_ACCESS_REGISTER_BLOCK *) Value;
                /* Load the register block start address */
                RegAddr = pBlockAccess->Address;
                
                /* Access all the registers requested by the application */
                for (i = 0; i < pBlockAccess->Count ; i++)
                {
                    /*** Packet this register address and data as per BF52xC1 register configuration requirements ***/
                    /* Shift the register address (Bit 15 to Bit 9 in BF52xC1 write packet holds the register address to configure) */
                    AccessBF52xC1.Address = ((RegAddr << ADI_BF52xC1_REG_ADDR_SHIFT) & ADI_BF52xC1_REG_ADDR_MASK);
                    /* Bit 8 to Bit 0 in BF52xC1 write packet holds the register data */
                    AccessBF52xC1.Address |= (*(pBlockAccess->pData+i) & ADI_BF52xC1_REG_DATA_MASK);
                    /* Pass the new register data to device access service which inturn configures BF52xC1 */
                    Result = adi_bf52xc1_DeviceAccess(pDevice,&AccessBF52xC1);

/* for Debug build only - exit on error */
#if defined(ADI_DEV_DEBUG)
                    if (Result != ADI_DEV_RESULT_SUCCESS)
                    {
                        break;
                    }
#endif  /* ADI_DEV_DEBUG */
                    
                    /* IF (Last register configured == Active Control register) */
                    if (RegAddr == BF52xC1_REG_ACTIVE_CTRL)
                    {
                        /* next register address to configure */
                        RegAddr = BF52xC1_REG_RESET;   
                    }
                    /* ELSE IF (Register address exceeds the limit) */
                    else if (RegAddr > BF52xC1_REG_RESET)
                    {
                        /* no registers left to configure */
                        break;
                    }
                    else
                    {
                        /* Move to next register address to access */
                        RegAddr++;
                    }
                }

                break;

            /* other commands */
            default:
                /* IF (SPORT device is open,pass this command to SPORT driver ) */
                if (pDevice->SportHandle != NULL)
                {
                    Result = adi_dev_Control(pDevice->SportHandle, Command, Value);
                }
                /* ELSE (command not supported. return error) */
                else
                {
                    Result = ADI_BF52xC1_RESULT_CMD_NOT_SUPPORTED;
                }
                break;
        /* ENDCASE */
        }

/* for Debug build only */
#if defined(ADI_DEV_DEBUG)
    }
#endif

    /* return */
    return(Result);
}              

/*********************************************************************

    Function:       adi_bf52xc1_DeviceAccess

    Description:    Updates a BF52xC1 hardware register using 
                    Device Access Service

*********************************************************************/
static u32 adi_bf52xc1_DeviceAccess(                 /* Writes to a BF52xC1 hardware register using Device Access Service */
    ADI_BF52xC1_DEF              *pDevice,           /* pointer to the driver instance                                   */
    ADI_DEV_ACCESS_REGISTER     *AccessBF52xC1       /* BF52xC1 register access info                                      */
){
    /* default return code */
    u32 Result = ADI_DEV_RESULT_SUCCESS;
    /* create a device access data instance */
    ADI_DEVICE_ACCESS_REGISTERS ConfigBF52xC1;
    /* structure to hold Device type and access type to be used */
    ADI_DEVICE_ACCESS_SELECT    AccessSelect;
    /* BF52xC1 register access info for TWI based register access */
    ADI_DEV_ACCESS_REGISTER     DevAccessTable;

    /* IF (Client set to use SPI to access BF52xC1 registers) */
    if (pDevice->DriverStatus == ADI_BF52xC1_DRIVER_USE_SPI)
    {
        /* This device falls under special case SPI access mode */
        AccessSelect.DeviceCS   = pDevice->SpiCS_TwiAddr;       /* SPI Chip-select for BF52xC1 */
        AccessSelect.Gaddr_len  = ADI_DEVICE_ACCESS_LENGTH0;    /* No SPI Global address for BF52xC1 */
        AccessSelect.Raddr_len  = ADI_DEVICE_ACCESS_LENGTH2;    /* Register address = 2bytes (Register address & data merged as one packet) */
        AccessSelect.Rdata_len  = ADI_DEVICE_ACCESS_LENGTH0;    /* Passing this as 0 sets Device access to consider BF52xC1 as special case SPI device */
        AccessSelect.AccessType = ADI_DEVICE_ACCESS_TYPE_SPI;   /* Use SPI to configure BF52xC1 registers */
        
        /* Populate Device Access instance fields specific to SPI */
        ConfigBF52xC1.DeviceAddress  = 0;                       /* No SPI Global address for BF52xC1    */
        ConfigBF52xC1.Value          = (void*)AccessBF52xC1;    /* command specific value               */
    }
    /* ELSE (Client has choosen to use TWI to access BF52xC1 registers) */
    else
    {
        AccessSelect.DeviceCS   = 0;                            /* Don't care for TWI access                */
        AccessSelect.Gaddr_len  = ADI_DEVICE_ACCESS_LENGTH0;    /* Don't care for TWI Access                */
        AccessSelect.Raddr_len  = ADI_DEVICE_ACCESS_LENGTH1;    /* Register address length                  */
        AccessSelect.Rdata_len  = ADI_DEVICE_ACCESS_LENGTH1;    /* Register data length                     */
        AccessSelect.AccessType = ADI_DEVICE_ACCESS_TYPE_TWI;   /* Use TWI to configure BF52xC1 registers   */

        /* Split the BF52xC1 datapacket for TWI access mode */
        DevAccessTable.Address  = (AccessBF52xC1->Address >> 8 & 0xFF);  /* Bits 15:8 passed as address field */
        DevAccessTable.Data     = (AccessBF52xC1->Address & 0xFF);       /* Bits 7:0 passed as data field     */
        
        /* Populate Device Access instance fields specific to TWI */
        ConfigBF52xC1.DeviceAddress  = pDevice->SpiCS_TwiAddr;      /* TWI Address for BF52xC1  */
        ConfigBF52xC1.Value          = (void*)&DevAccessTable;      /* command specific value   */
    }

    ConfigBF52xC1.ManagerHandle      = pDevice->ManagerHandle;          /* Device manager handle                                */
    ConfigBF52xC1.ClientHandle       = NULL;                            /* No client handle                                     */
    ConfigBF52xC1.DeviceNumber       = pDevice->SpiTwiDevNumber;        /* SPI/TWI Device number to use                         */
    ConfigBF52xC1.DCBHandle          = pDevice->DCBHandle;              /* handle to the callback manager                       */
    ConfigBF52xC1.DeviceFunction     = NULL;                            /* No Callback from device access                       */
    ConfigBF52xC1.Command            = ADI_DEV_CMD_REGISTER_WRITE;      /* Command ID to configure a register                   */
    ConfigBF52xC1.FinalRegAddr       = ADI_BF52xC1_FINAL_REG_ADDRESS;   /* Address of the last register BF52xC1 (with max data) */
    ConfigBF52xC1.RegisterField      = NULL;                            /* No need to check for register field errors           */
    ConfigBF52xC1.ReservedValues     = NULL;                            /* No need to update for reserved bits                  */
    ConfigBF52xC1.ValidateRegister   = NULL;                            /* Register address already validated. no need to repeat*/
    ConfigBF52xC1.ConfigTable        = pDevice->SpiTwiConfigTable;      /* SPI/TWI configuration table passed by the client     */
    ConfigBF52xC1.SelectAccess       = &AccessSelect;                   /* Device Access type                                   */
    ConfigBF52xC1.pAdditionalinfo    = (void *)NULL;                    /* No Additional info                                   */
    
    /* Updates driver register cache */
    Result = adi_bf52xc1_UpdateDriverCache(pDevice,AccessBF52xC1);

    /* IF (Updates driver register cache resulted in success) */
    if (Result == ADI_DEV_RESULT_SUCCESS)
    {    
        /* call device access to configure corresponding BF52xC1 register */
        Result = adi_device_access (&ConfigBF52xC1);
    }
    
    /* return */
    return (Result);
}
    
/*********************************************************************

    Function:       adi_bf52xc1_UpdateDriverCache

    Description:    Updates driver register cache to keep in track of 
                    BF52xC1 hardware register changes

*********************************************************************/
static u32 adi_bf52xc1_UpdateDriverCache(        /* Function to update BF52xC1 register cache */
    ADI_BF52xC1_DEF          *pDevice,           /* pointer to the driver instance           */
    ADI_DEV_ACCESS_REGISTER *AccessBF52xC1       /* BF52xC1 register access info              */
){
    u8  RegAddr;
    u16 u16Temp;
    /* default return code */
    u32 Result = ADI_DEV_RESULT_SUCCESS;
    
    /* Extract the register address from the given register access info */
    RegAddr = (u8) ((AccessBF52xC1->Address & ADI_BF52xC1_REG_ADDR_MASK) >> ADI_BF52xC1_REG_ADDR_SHIFT);

    /* IF (Configure Active Control Register) */
    if (RegAddr == BF52xC1_REG_ACTIVE_CTRL)
    {
        /* update driver register cache */ 
        pDevice->BF52xC1Reg[BF52xC1_REG_ACTIVE_CTRL] = (AccessBF52xC1->Address & ADI_BF52xC1_REG_DATA_MASK);
        
        /* IF (Activate Digital Audio Interface) */
        if (pDevice->BF52xC1Reg[BF52xC1_REG_ACTIVE_CTRL] & BF52xC1_RFLD_ACTIVATE_CODEC)
        {
            /* extract BF52xC1 audio input format */
            u16Temp = (pDevice->BF52xC1Reg[BF52xC1_REG_DIGITAL_IFACE] & BF52xC1_RFLD_IFACE_FORMAT);

            /* Auto-SPORT Configuration does not support Right-Justified or DSP mode */
            /* IF (Left Justified or I2S mode) */
            if ((u16Temp == BF52xC1_STEREO_MODE_LJ) || (u16Temp == BF52xC1_STEREO_MODE_I2S))
            {
                /* Calculate new SPORT register configuration value */
                pDevice->SportReg.TCR1 = ADI_SPORT_TFSR;
                pDevice->SportReg.RCR1 = ADI_SPORT_RFSR;
                pDevice->SportReg.TCR2 = ADI_SPORT_TSFSE;
                pDevice->SportReg.RCR2 = ADI_SPORT_RSFSE;   
                
                /* IF (Audio Data Format is set to Left-Justified Mode) */
                if (u16Temp == BF52xC1_STEREO_MODE_LJ)
                {
                    /* IF (DACLR Phase not Inverted) */
                    if (!(pDevice->BF52xC1Reg[BF52xC1_REG_DIGITAL_IFACE] & BF52xC1_RFLD_DAC_LR_POLARITY))
                    {
	                    /* Active Low TFS (Right channel DAC data when TFS is low) */
    	                pDevice->SportReg.TCR1 |= ADI_SPORT_LTFS;
        	            /* Active Low RFS (Right channel DAC data when RFS is low) */
            	        pDevice->SportReg.RCR1 |= ADI_SPORT_LRFS;
                	}
                    /* ELSE (DACLR Phase Inverted) */
                        /* Active High TFS (Right channel DAC data when TFS is High) */
    	                /* Active High RFS (Right channel DAC data when RFS is High) */
	
        	        /* IF (Bit Clock not Inverted) */
            	    if (!(pDevice->BF52xC1Reg[BF52xC1_REG_DIGITAL_IFACE] & BF52xC1_RFLD_BCLK_INVERT))
                	{
                        /* Drive Data & Internal Frame Syncs with falling edge of TSCLK. Sample External FS with rising edge of TSCLK */
                        pDevice->SportReg.TCR1 |= ADI_SPORT_TCKFE;
	                    /* Drive Data & Internal Frame Syncs with falling edge of RSCLK. Sample External FS with rising edge of RSCLK */
    	                pDevice->SportReg.RCR1 |= ADI_SPORT_RCKFE;
        	        }
            	    /* ELSE (Bit Clock is Inverted) */
                	    /* Drive Data & Internal Frame Syncs with rising edge of TSCLK. Sample External FS with falling edge of TSCLK */
                    	/* Drive Data & Internal Frame Syncs with rising edge of RSCLK. Sample External FS with falling edge of RSCLK */
                }
                /* ELSE (Audio Data Format is set to I2S Mode) */
                else
                {    
                    /* IF (DACLR Phase Inverted) */
	                if (pDevice->BF52xC1Reg[BF52xC1_REG_DIGITAL_IFACE] & BF52xC1_RFLD_DAC_LR_POLARITY)
    	            {
        	            /* Active Low TFS (Right channel DAC data when TFS is low) */
            	        pDevice->SportReg.TCR1 |= ADI_SPORT_LTFS;
                	    /* Active Low RFS (Right channel DAC data when RFS is low) */
                    	pDevice->SportReg.RCR1 |= ADI_SPORT_LRFS;
                    }
    	            /* ELSE (DACLR Phase not Inverted) */
        	            /* Active High TFS (Right channel DAC data when TFS is High) */
            	        /* Active High RFS (Right channel DAC data when RFS is High) */
	
    	            /* IF (Bit Clock not Inverted) */
        	        if (!(pDevice->BF52xC1Reg[BF52xC1_REG_DIGITAL_IFACE] & BF52xC1_RFLD_BCLK_INVERT))
            	    {
                	    /* Drive Data & Internal Frame Syncs with falling edge of TSCLK. Sample External FS with rising edge of TSCLK */
                    	pDevice->SportReg.TCR1 |= ADI_SPORT_TCKFE;
                        /* Drive Data & Internal Frame Syncs with falling edge of RSCLK. Sample External FS with rising edge of RSCLK */
	                    pDevice->SportReg.RCR1 |= ADI_SPORT_RCKFE;
                    }
        	        /* ELSE (Bit Clock is Inverted) */
            	        /* Drive Data & Internal Frame Syncs with rising edge of TSCLK. Sample External FS with falling edge of TSCLK */
                	    /* Drive Data & Internal Frame Syncs with rising edge of RSCLK. Sample External FS with falling edge of RSCLK */
                }

                /* extract Input Audio Data bit length */
                u16Temp = (pDevice->BF52xC1Reg[BF52xC1_REG_DIGITAL_IFACE] & BF52xC1_RFLD_AUDIO_DATA_LEN);
            
                /* IF (Input Audio Data bit length is set to 16 bits) */
                if (u16Temp == BF52xC1_WORD_LENGTH_16BITS)
                {
                    pDevice->SportReg.TCR2 |= ADI_SPORT_SLEN_16;
                    pDevice->SportReg.RCR2 |= ADI_SPORT_SLEN_16;
                }
                /* ELSE IF (Input Audio Data bit length is set to 20 bits) */
                else if (u16Temp == BF52xC1_WORD_LENGTH_20BITS)
                {
                    pDevice->SportReg.TCR2 |= ADI_SPORT_SLEN_20;
                    pDevice->SportReg.RCR2 |= ADI_SPORT_SLEN_20;
                }
                /* ELSE IF (Input Audio Data bit length is set to 24 bits) */
                else if (u16Temp == BF52xC1_WORD_LENGTH_24BITS)
                {    
                    pDevice->SportReg.TCR2 |= ADI_SPORT_SLEN_24;
                    pDevice->SportReg.RCR2 |= ADI_SPORT_SLEN_24;
                }
                /* ELSE (Input Audio Data bit length is set to 32 bits) */
                else
                {       
                    pDevice->SportReg.TCR2 |= ADI_SPORT_SLEN_32;
                    pDevice->SportReg.RCR2 |= ADI_SPORT_SLEN_32;
                }
                
                /* IF (BF52xC1 set in slave mode) */
                if (!(pDevice->BF52xC1Reg[BF52xC1_REG_DIGITAL_IFACE] & BF52xC1_RFLD_ENABLE_MASTER))
                {
                    /* Enable SPORT Internal Clock Generation and Internal FS generation */
                    pDevice->SportReg.TCR1 |= (ADI_SPORT_ITCLK | ADI_SPORT_ITFS);
                    pDevice->SportReg.RCR1 |= (ADI_SPORT_IRCLK | ADI_SPORT_IRFS);
                }
               
                /* update SPORT Configuration */
                Result = adi_bf52xc1_ConfigSport (pDevice);
            }
        }
    }
    /* ELSE IF (Configure Reset Register) */
    else if (RegAddr == BF52xC1_REG_RESET)
    {
        /* IF (soft-reset BF52xC1) */
        if (!(AccessBF52xC1->Address & ADI_BF52xC1_REG_DATA_MASK))
        {
            /* Initialise BF52xC1 register cache to default values */
    	    pDevice->BF52xC1Reg[BF52xC1_REG_LEFT_ADC_VOL]    = 0x004B;  /* Left Line In Mute, 0dB                       */
	        pDevice->BF52xC1Reg[BF52xC1_REG_RIGHT_ADC_VOL]   = 0x004B;  /* Right Line In Mute, 0dB                      */
            pDevice->BF52xC1Reg[BF52xC1_REG_LEFT_DAC_VOL]    = 0x0079;  /* Left HP volume = 0dB                         */
        	pDevice->BF52xC1Reg[BF52xC1_REG_RIGHT_DAC_VOL]   = 0x0079;  /* Right HP volume = 0dB                        */
    	    pDevice->BF52xC1Reg[BF52xC1_REG_ANALOGUE_PATH]   = 0x000A;  /* Enable Bypass, MIC Mute enabled              */
	        pDevice->BF52xC1Reg[BF52xC1_REG_DIGITAL_PATH]    = 0x0008;  /* Enable DAC Soft mute                         */
            pDevice->BF52xC1Reg[BF52xC1_REG_POWER]           = 0x009F;  /* Power-down all except ClkOut & Oscillator    */
        	pDevice->BF52xC1Reg[BF52xC1_REG_DIGITAL_IFACE]   = 0x000A;  /* I2S mode, 24-bits                            */
    	    pDevice->BF52xC1Reg[BF52xC1_REG_SAMPLING_CTRL]   = 0;       /* Normal mode, 256fs                           */
	        pDevice->BF52xC1Reg[BF52xC1_REG_ACTIVE_CTRL]     = 0;       /* BF52xC1 is Not Active                        */
            
            /* Initialise Sport register cache to default values */
            pDevice->SportReg.TCR1      = (ADI_SPORT_TFSR  | ADI_SPORT_TCKFE | ADI_SPORT_ITCLK | ADI_SPORT_ITFS);
            pDevice->SportReg.TCR2      = (ADI_SPORT_TSFSE | ADI_SPORT_SLEN_24);
            pDevice->SportReg.RCR1      = (ADI_SPORT_RFSR  | ADI_SPORT_RCKFE | ADI_SPORT_IRCLK | ADI_SPORT_IRFS);
            pDevice->SportReg.RCR2      = (ADI_SPORT_RSFSE | ADI_SPORT_SLEN_24);
        }
    }
    /* ELSE IF (registers between ADC volume and Sampling control) */
    else if (RegAddr <= BF52xC1_REG_SAMPLING_CTRL)
    {
        /* update driver register cache */
        pDevice->BF52xC1Reg[RegAddr] = (AccessBF52xC1->Address & ADI_BF52xC1_REG_DATA_MASK);
    }
    /* ELSE (invalid register, return error) */
    else
    {
        Result = ADI_DEV_RESULT_INVALID_REG_ADDRESS;
    }

    /* return */
    return (Result);
}

/*********************************************************************

    Function:       adi_bf52xc1_UpdateSampleRate

    Description:    Updates BF52xC1 Sampling rate register to match
                    the given ADC,DAC Sample rates.
                    
*********************************************************************/
static u32 adi_bf52xc1_UpdateSampleRate(        /* Updates BF52xC1 Sample Control register to match ADC/DAC sampling rate   */
    ADI_BF52xC1_DEF         *pDevice,           /* pointer to the driver instance                                           */
    ADI_BF52xC1_SAMPLE_RATE *pSampleRate        /* pointer to structure holding ADC/DAC Sample rates                        */
){
    u8  i,SRFieldValue;
    u16 RegData;
    u32 SamplingRate;
    /* default return code */
    u32 Result = ADI_DEV_RESULT_SUCCESS;
    /* structure to access one BF52xC1 register */
    ADI_DEV_ACCESS_REGISTER AccessBF52xC1;

    /* Get the Sampling Control register value */
    RegData = pDevice->BF52xC1Reg[BF52xC1_REG_SAMPLING_CTRL];
    /* Clear CLKDIV2 and SR fields */
    RegData &= ~(BF52xC1_RFLD_SAMPLE_RATE | BF52xC1_RFLD_CORECLK_DIV2);

    /*** Get the new SR field value from Sampling Rate Lookup Table ***/
    /* IF (ADC and DAC set to different sample rates) */
    if (pSampleRate->AdcSampleRate != pSampleRate->DacSampleRate)
    {
        /* This SR field value falls under Special case sampling rate */
        /* IF (ADC Sample Rate = 48kHz & DAC Sample Rate = 8kHz) */
        if ((pSampleRate->AdcSampleRate == 48000) && (pSampleRate->DacSampleRate == 8000))
        {
            /* SR Field value = 1 */
            SRFieldValue = 1;
        }
        /* ELSE IF (ADC Sample Rate = 8kHz & DAC Sample Rate = 48kHz) */
        else if ((pSampleRate->AdcSampleRate == 8000) && (pSampleRate->DacSampleRate == 48000))
        {
            /* SR Field value = 2 */
            SRFieldValue = 2;
        }
        /* ELSE IF (ADC Sample Rate = 44.1kHz & DAC Sample Rate = 8.02kHz) */
        else if ((pSampleRate->AdcSampleRate == 44100) && (pSampleRate->DacSampleRate == 8020))
        {
            /* SR Field value = 9 */
            SRFieldValue = 9;
        }
        /* ELSE IF (ADC Sample Rate = 8.02kHz & DAC Sample Rate = 44.1kHz) */
        else if ((pSampleRate->AdcSampleRate == 8020) && (pSampleRate->DacSampleRate == 44100))
        {
            /* SR Field value = A */
            SRFieldValue = 0x0A;
        }
        /* ELSE (sampling rate combination not supported. return error */
        else
        {
            Result = ADI_BF52xC1_RESULT_SAMPLE_RATE_NOT_SUPPORTED;
        }
    }
    /* ELSE (ADC and DAC sample rates are equal) */
    else
    {
        /* copy the given sampling rate to a temp location */
        SamplingRate = pSampleRate->AdcSampleRate;
        /* run thru SR mapping twice */
        i = 2;
        while (i--)
        {
            /* CASE OF (SamplingRate) */
            switch(SamplingRate)
            {              
                /* CASE (96kHz) */
                case (96000):
                    /* SR Field value = 7 */
                    SRFieldValue = 7;
                    break;

                /* CASE (88.2kHz) */
                case (88200):
                    /* SR Field value = F */
                    SRFieldValue = 0x0F;
                    break;
                
                /* CASE (48kHz) */
                case (48000):
                    /* SR Field value = 0 */
                    SRFieldValue = 0;
                    break;
                
                /* CASE (44.1kHz) */
                case (44100):
                    /* SR Field value = 8 */
                    SRFieldValue = 8;
                    break;

                /* CASE (32kHz) */
                case (32000):
                    /* SR Field value = 6 */
                    SRFieldValue = 6;
                    break;

                /* CASE (8.02kHz) */
                case (8020):
                    /* SR Field value = 0x0B */
                    SRFieldValue = 0x0B;
                    break;

                /* CASE (8kHz) */
                case (8000):
                    /* SR Field value = 3 */
                    SRFieldValue = 3;
                    break;
                
                default:
                    /* IF (Temp sampling rate is same as client provided sampling rate) */
                    if (SamplingRate == pSampleRate->AdcSampleRate)
                    {
                        /* assuming that the given sampling rate can be supported by reducing core clock by half */
                        /* set Sampling Control register CLKDIV2 bit */
                        RegData |= (1 << ADI_BF52xC1_SHIFT_CLKDIV2);
                        /* dobule the temp sampling rate */
                        SamplingRate <<= 1;
                    }
                    else
                    {
                        /* Sampling rate not supported. return error */
                        Result = ADI_BF52xC1_RESULT_SAMPLE_RATE_NOT_SUPPORTED;
                    }
                    break;
            }
        }
    }
    
    /* IF (given sample rates are valid) */
    if (Result == ADI_DEV_RESULT_SUCCESS)
    {
        /* update RegData with new SR field value */
        RegData |= (SRFieldValue << ADI_BF52xC1_SHIFT_SR);
        /* IF (USB mode enabled) */
        if (RegData & BF52xC1_RFLD_ENABLE_USB_MODE)
        {
            /* IF (set BOSR bit when Sampling rate is set to 88.2/44.1/22.05/8.02kHz) */
            if ((pSampleRate->AdcSampleRate == 88200) ||
                (pSampleRate->AdcSampleRate == 44100) ||
                (pSampleRate->AdcSampleRate == 22050) ||
                (pSampleRate->AdcSampleRate == 8020))
            {
                RegData |= BF52xC1_RFLD_BOS_RATE;
            }
            /* ELSE (clear BOSR for other sampling rates) */
            else
            {
                RegData &= ~BF52xC1_RFLD_BOS_RATE;
            }
        }
        
        /*** Packet the Sample Rate register address and data as per BF52xC1 register configuration requirements ***/
    	/* Shift the register address (Bit 15 to Bit 9 in BF52xC1 write packet holds the register address to configure) */
        AccessBF52xC1.Address = (BF52xC1_REG_SAMPLING_CTRL << ADI_BF52xC1_REG_ADDR_SHIFT);
        /* Bit 8 to Bit 0 in BF52xC1 write packet holds the register data */
    	AccessBF52xC1.Address |= RegData;
        /* update BF52xC1 Sampling Control register */
        Result = adi_bf52xc1_DeviceAccess(pDevice,&AccessBF52xC1);
    }
    
    /* return */
    return (Result);
}
    
/*********************************************************************
*
*   Function:       adi_bf52xc1_SportOpen
*
*   Description:    Opens SPORT device allocated to BF52xC1 Audio Codec
*
*********************************************************************/
static u32 adi_bf52xc1_SportOpen(            /* Opens SPORT Device               */
    ADI_BF52xC1_DEF          *pDevice        /* pointer to the driver instance   */
){
    /* default return code */
    u32 Result = ADI_DEV_RESULT_SUCCESS;

    /* Open the SPORT driver */
    if ((Result = adi_dev_Open( pDevice->ManagerHandle,     /* Device Manager handle                */
                                &ADISPORTEntryPoint,        /* SPORT Entry point                    */
                                pDevice->SportDevNumber,    /* SPORT device number                  */
                                pDevice,                    /* client handle                        */
                                &pDevice->SportHandle,      /* Location to store SPORT device handle*/
                                pDevice->Direction,         /* BF52xC1 Direction                    */
                                pDevice->DMAHandle,         /* DMA manager Handle                   */
                                NULL,                       /* Live callbacks                       */
                                adi_bf52xc1_SportCallback   /* SPORT callback function              */
                            )) == ADI_DEV_RESULT_SUCCESS)
    {
        /* Configure SPORT Device */
        Result = adi_bf52xc1_ConfigSport(pDevice);
    }
    
    /* return */
    return (Result);
}

/*********************************************************************
*
*   Function:       adi_bf52xc1_ConfigSport
*
*   Description:    Configures SPORT device as per 
*                   BF52xC1 operating conditions
*
*********************************************************************/
static u32 adi_bf52xc1_ConfigSport(      /* Function to Configure SPORT registers    */
    ADI_BF52xC1_DEF          *pDevice    /* pointer to the driver instance           */
){
    /* default return code */
    u32 Result = ADI_DEV_RESULT_SUCCESS;
    u16	u16Temp;
    /* Table to Configure SPORT Transmit/Receive configuration registers */
    ADI_DEV_CMD_VALUE_PAIR SportConfigRegTable[] = 
    {
        { ADI_SPORT_CMD_SET_TCR1,   (void *)(pDevice->SportReg.TCR1)},
        { ADI_SPORT_CMD_SET_TCR2,   (void *)(pDevice->SportReg.TCR2)},
        { ADI_SPORT_CMD_SET_RCR1,   (void *)(pDevice->SportReg.RCR1)},
        { ADI_SPORT_CMD_SET_RCR2,   (void *)(pDevice->SportReg.RCR2)},
        { ADI_DEV_CMD_END,          (void *)NULL                    },  /* End of Configuration table   */
    };
    
    /* IF (the SPORT device allocated to BF52xC1 is open and ready to configure and Auto-SPORT Configuration enabled) */
    if ((pDevice->SportHandle != NULL) && (pDevice->AutoSportEnable == TRUE))
    {
        if (Result == ADI_DEV_RESULT_SUCCESS)
        {
			/* extract BF52xC1 audio data format */
            u16Temp = (pDevice->BF52xC1Reg[BF52xC1_REG_DIGITAL_IFACE] & BF52xC1_RFLD_IFACE_FORMAT);
                
            /* IF (Left Justified or I2S Mode) */
            if ((u16Temp == BF52xC1_STEREO_MODE_LJ) || (u16Temp == BF52xC1_STEREO_MODE_I2S))
            {
                /* Configure SPORT Configuration registers */
            	Result = adi_dev_Control(pDevice->SportHandle, ADI_DEV_CMD_TABLE, (void *)SportConfigRegTable);
			}
            /* Auto-SPORT Configuration does not support Right-Justified or DSP mode        */
            /* DSP & Right-Justified modes - SPORT configuration registers left unchanged   */
        }
    }
    
    /* return */
    return (Result);
}

/*********************************************************************
*
*   Function:  adi_bf52xc1_SportCallback
*
*   Description: Callback from the SPORT Driver
*
*********************************************************************/
static void adi_bf52xc1_SportCallback(          /* Callback function passed to SPORT driver */
    void*                   DeviceHandle,       /* Callback Handle passed by BF52xC1        */
    u32                     Event,              /* Callback Event                           */
    void*                   pArg                /* Callback Argument                        */
){

    /* Pointer to BF52xC1 device instance */
    ADI_BF52xC1_DEF *pDevice = (ADI_BF52xC1_DEF *)DeviceHandle;
    
/* for Debug build only - check for errors if required  */
#if defined(ADI_DEV_DEBUG)
    /* Validate the given PDDHandle */    
    /* Continue only if the given PDDHandle is valid */
    if (ValidatePDDHandle(DeviceHandle) == ADI_DEV_RESULT_SUCCESS)
    {    
#endif

        /* Pass the callback to the Device Manager Callback */
        (pDevice->DMCallback)(pDevice->DeviceHandle,Event,pArg);
        
/* for Debug build only */
#if defined(ADI_DEV_DEBUG)
    }
#endif

    /* return */
    
}

#if defined(ADI_DEV_DEBUG)  /* Debug build only */

/*********************************************************************
*
*   Function:       adi_bf52xc1_ValidateRegAccess
*
*   Description:    Validates the given register access table
*
*********************************************************************/
static u32 adi_bf52xc1_ValidateRegAccess(       /* Function to validate register access table   */
    ADI_BF52xC1_DEF          *pDevice,          /* pointer to the driver instance               */
    u32                     Command,            /* Command ID passed by the application         */
    void                    *Value              /* Command specific value                       */
){
    
    /* default return code */
    u32 Result = ADI_DEV_RESULT_SUCCESS;

    /* pointer to selective register access table */
    ADI_DEV_ACCESS_REGISTER         *pSelectiveAccess;
    /* pointer to block register access table */
    ADI_DEV_ACCESS_REGISTER_BLOCK   *pBlockAccess;
    /* pointer to register field access table */
    ADI_DEV_ACCESS_REGISTER_FIELD   *pFieldAccess;
    
    /* CASEOF (Device Access Command) */
    switch (Command)
    {
        /* CASE (Read a specific BF52xC1 Register) */
        case (ADI_DEV_CMD_REGISTER_READ):
        /* CASE (Read a table of BF52xC1 registers) */
        case(ADI_DEV_CMD_REGISTER_TABLE_READ):
        
            /* get the address of selective register access table submitted by the app */
            pSelectiveAccess = (ADI_DEV_ACCESS_REGISTER *) Value;

            /* validate all registers in application provided access table until we reach the delimiter */
            while (pSelectiveAccess->Address != ADI_DEV_REGEND)  
            {
                /* IF (this is a write-only register) */
                if (pSelectiveAccess->Address == BF52xC1_REG_RESET)
                {
                    /* return error */
                    Result = ADI_DEV_RESULT_NOT_SUPPORTED;
                    break;
                }
                /* IF (the register address is not valid) */
                if (((pSelectiveAccess->Address > BF52xC1_REG_ACTIVE_CTRL) && 
                    (pSelectiveAccess->Address < BF52xC1_REG_RESET)) ||
                    (pSelectiveAccess->Address > BF52xC1_REG_RESET))
                {
                    /* return error */
                    Result = ADI_DEV_RESULT_INVALID_REG_ADDRESS;
                    break;
                }
                /* IF (the command is to access a single register) */
                if (Command == ADI_DEV_CMD_REGISTER_READ)
                {
                    break;  /* exit this loop */
                }
                pSelectiveAccess++; /* move to next selective register access info */
            }
            break;

        /* CASE (Configure a BF52xC1 Resigter) */
        case(ADI_DEV_CMD_REGISTER_WRITE):
        /* CASE (Configure a table BF52xC1 registers) */
        case(ADI_DEV_CMD_REGISTER_TABLE_WRITE): 
        
            /* get the address of selective register access table submitted by the app */
            pSelectiveAccess = (ADI_DEV_ACCESS_REGISTER *) Value;

            /* validate all registers in application provided access table until we reach the delimiter */
            while (pSelectiveAccess->Address != ADI_DEV_REGEND)  
            {
                /* IF (the register address is not valid) */
                if (((pSelectiveAccess->Address > BF52xC1_REG_ACTIVE_CTRL) && 
                    (pSelectiveAccess->Address < BF52xC1_REG_RESET)) ||
                    (pSelectiveAccess->Address > BF52xC1_REG_RESET))
                {
                    /* return error */
                    Result = ADI_DEV_RESULT_INVALID_REG_ADDRESS;
                    break;
                }
                /* IF (the command is to access a single register) */
                if (Command == ADI_DEV_CMD_REGISTER_WRITE)
                {
                    break;  /* exit this loop */
                }
                pSelectiveAccess++; /* move to next selective register access info */
            }
            break;

        /* CASE (Read a specific BF52xC1 register field) */
        case(ADI_DEV_CMD_REGISTER_FIELD_READ):
        /* CASE (Read a table BF52xC1 register(s) field(s)) */
        case(ADI_DEV_CMD_REGISTER_FIELD_TABLE_READ):

            /* get the address of Field access table submitted by the app */
            pFieldAccess = (ADI_DEV_ACCESS_REGISTER_FIELD *) Value;

            /* validate all registers in application provided access table until we reach the delimiter */
            while (pFieldAccess->Address != ADI_DEV_REGEND)  
            {
                /* IF (this is a write-only register) */
                if (pFieldAccess->Address == BF52xC1_REG_RESET)
                {
                    /* return error */
                    Result = ADI_DEV_RESULT_NOT_SUPPORTED;
                    break;
                }
                /* IF (the register address is not valid) */
                if (((pFieldAccess->Address > BF52xC1_REG_ACTIVE_CTRL) && 
                    (pFieldAccess->Address < BF52xC1_REG_RESET)) ||
                    (pFieldAccess->Address > BF52xC1_REG_RESET))
                {
                    /* return error */
                    Result = ADI_DEV_RESULT_INVALID_REG_ADDRESS;
                    break;
                }
                /* IF (the command is to access a single register) */
                if (Command == ADI_DEV_CMD_REGISTER_FIELD_READ)
                {
                    break;  /* exit this loop */
                }
                pFieldAccess++; /* move to next register field access info */
            }
            break;
                
        /* CASE (Configure a specific BF52xC1 register field) */
        case(ADI_DEV_CMD_REGISTER_FIELD_WRITE):
        /* CASE (Configure a table BF52xC1 register(s) field(s)) */
        case(ADI_DEV_CMD_REGISTER_FIELD_TABLE_WRITE):
                
            /* get the address of Field access table submitted by the app */
            pFieldAccess = (ADI_DEV_ACCESS_REGISTER_FIELD *) Value;
            
            /* validate all registers in application provided access table until we reach the delimiter */
            while (pFieldAccess->Address != ADI_DEV_REGEND)  
            {
                /* IF (the register address is not valid) */
                if (((pFieldAccess->Address > BF52xC1_REG_ACTIVE_CTRL) && 
                    (pFieldAccess->Address < BF52xC1_REG_RESET)) ||
                    (pFieldAccess->Address > BF52xC1_REG_RESET))
                {
                    /* return error */
                    Result = ADI_DEV_RESULT_INVALID_REG_ADDRESS;
                    break;
                }
                /* IF (the command is to access a single register) */
                if (Command == ADI_DEV_CMD_REGISTER_WRITE)
                {
                    break;  /* exit this loop */
                }
                pFieldAccess++; /* move to next register field access info */
            }
            break;
        
        /* CASE (Read block of BF52xC1 registers starting from first given address) */
        case(ADI_DEV_CMD_REGISTER_BLOCK_READ):
            
            /* get the address of Block access table submitted by the app */
            pBlockAccess = (ADI_DEV_ACCESS_REGISTER_BLOCK *) Value;

            /* IF (there are any registers to access) */
            if (pBlockAccess->Count)
            {
                /* IF (this the block access starts with a write-only register) */
                if (pBlockAccess->Address == BF52xC1_REG_RESET)
                {
                    /* return error */
                    Result = ADI_DEV_RESULT_NOT_SUPPORTED;
                    break;
                }

                /* IF (the block access exceeds the readable register boundary) */
                if ((pBlockAccess->Address+(pBlockAccess->Count-1)) > BF52xC1_REG_ACTIVE_CTRL)
                {
                    /* return error */
                    Result = ADI_DEV_RESULT_INVALID_REG_ADDRESS;
                    break;
                }
            }
            
            break;
                
        /* CASE (Write to a block of BF52xC1 registers starting from first given address) */
        case(ADI_DEV_CMD_REGISTER_BLOCK_WRITE):
            
            /* get the address of Block access table submitted by the app */
            pBlockAccess = (ADI_DEV_ACCESS_REGISTER_BLOCK *) Value;

            /* IF (there are any registers to access) */
            if (pBlockAccess->Count)
            {
                /* IF (the block access exceeds the writeable register boundary) */
                if ((pBlockAccess->Address+(pBlockAccess->Count-1)) > (BF52xC1_REG_ACTIVE_CTRL+1))
                {
                    /* return error */
                    Result = ADI_DEV_RESULT_INVALID_REG_ADDRESS;
                    break;
                }
            }
            break;

            /* other commands */
            default:
                break;
        /* ENDCASE */
        }

    /* return */
    return(Result);
}            

/*********************************************************************
*
*   Function:       ValidatePDDHandle
*
*   Description:    Validates a PDD handle
*
*********************************************************************/

static u32 ValidatePDDHandle(
    ADI_DEV_PDD_HANDLE      PDDHandle           /* PDD handle of a BF52xC1 device  */
)
{    
    /* Return value - insure the client has provided a valid PDD Handle */
    u32     Result = ADI_DEV_RESULT_BAD_PDD_HANDLE;
    /* index */
    u32     i;
    
    /* compare the given PDD handle with PDDHandle allocated to all BF52xC1 devices in the list    */
    for (i = 0; i < ADI_BF52xC1_NUM_DEVICES; i++) 
    {        
        if (PDDHandle == (ADI_DEV_PDD_HANDLE)&BF52xC1Device[i])
        {
            /* Given PDDHandle is valid. quit this loop */
            Result = ADI_DEV_RESULT_SUCCESS;
            break;
        }
    }
    /* return */
    return (Result);
}

#endif

/*****/
