/*********************************************************************************

Copyright(c) 2005 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.

*********************************************************************************/
/*************************************************************************************

Description:        This is the virtual driver source code for Audio EZ-Extender. 
                    It is layered on top of the AD1938 and ADAV801 device drivers, 
                    which configure various audio modes.
			        Currently the audio mode is fixed for BF537 and the ADAV801 driver 
			        is not available.  Only SPORT1 is used.
                    The driver opens the SPI and SPORT devices on the ADSP-BF537 and uses
                    them to configure the AD1938 codec A and B.
                    And then transfers audio data to/from the DAC and ADC over SPORT1 in TDM mode.
                        
Hardware:           ADSP-BF537 EZ-KIT Board	Rev. 1.1
                    Audio EZ-Extender Card Rev. 1.0/1.1

Hardware Setup:     Connect the Audio EZ-Extender Card to the EZ-KIT 
                    Settings of the switches on the Audio EZ-Extender Card:
                    SPORT1 MODE:
                        			JP1-> 1-2 (BF537_SEL)
									JP1-> 5-6 (SPORT1_EN)
									JP2-> 5-6 (ADAV801_SYSCLK3)

                    Settings of the switches on the EZ-Kit:
                    Switch all SW to default settings, then
                        SW5 - all OFF
                        SW7 - 6 OFF
                            - 8 OFF

*********************************************************************************/


/*********************************************************************

Include files

*********************************************************************/

#include <services\services.h>          // system service include file
#include <drivers\adi_dev.h>                    // device manager include file
#include <drivers\spi\adi_spi.h>            // spi driver include file
#include <drivers\sport\adi_sport.h>          // sport driver include file
#include <drivers/deviceaccess/adi_device_access.h>  	// adi_device_access driver includes

#include <drivers\codec\adi_AD1938.h>   // AD1938 driver
//#include "adi_AD1938.h"   // AD1938 driver
//include <drivers\codec\adi_AD1938_ii.h>   // AD1938 driver
#if (ADAV801_SUPPORT)
#include "adi_ADAV801.h"                // ADAV801 driver  *not included
#endif
#include "adi_AudioEZExtender.h"

/*********************************************************************

Enumerations and definitions

*********************************************************************/
// number of Audio EZ-Extender devices in the system
#define ADI_AUDIOEZEXTENDER_NUM_DEVICES	(sizeof(Device)/sizeof(ADI_AUDIOEZEXTENDER))

// ADAV801 slave selection on BF537
#define ADAV801_SPICS_BF537KIT  0x01        // Chipselect specific to BF537 kit (PF10)

// AD1938 A slave selection on BF537
#define AD1938_A_SPICS_BF537KIT  0x05        // Chipselect specific to BF537 kit (PF5)

// AD1938 B slave selection on BF537
#define AD1938_B_SPICS_BF537KIT  0x06        // Chipselect specific to BF537 kit (PF4)

#define ADI_AD1938_CMD_SET_SPI_CS 0x345679

/**********************************************************************************

  Audio EZ-Extender specific definitions / data

**********************************************************************************/

#define b0_1	0x01
#define b1_1	0x02
#define b2_1	0x04
#define b3_1	0x08
#define b4_1	0x10
#define b5_1	0x20
#define b6_1	0x40
#define b7_1	0x80

#define b0_0	0x00
#define b1_0	0x00
#define b2_0	0x00
#define b3_0	0x00
#define b4_0	0x00
#define b5_0	0x00
#define b6_0	0x00
#define b7_0	0x00

//=================================================================================
// AD1938 CODEC

//PLL_CLK_CONTROL_0
#define DIS_ADC_DAC			(b7_0)
#define ENA_ADC_DAC			(b7_1)

#define PLL_IN_MCLK			(b6_0 | b5_0)
#define PLL_IN_DLRCLK		(b6_0 | b5_1)
#define PLL_IN_ALRCLK		(b6_1 | b5_0)

#define MCLK_OUT_XTAL		(b4_0 | b3_0)
#define MCLK_OUT_256FS		(b4_0 | b3_1)
#define MCLK_OUT_512FS		(b4_1 | b3_0)
#define MCLK_OUT_OFF		(b4_1 | b3_1)

#define INPUT256			(b2_0 | b1_0)
#define INPUT384			(b2_0 | b1_1)
#define INPUT512			(b2_1 | b1_0)
#define INPUT768			(b2_1 | b1_1)

#define PLL_PWR_UP			(b0_0)
#define PLL_PWR_DWN			(b0_1)


//PLL_CLK_CONTROL_1
#define DIS_VREF			(b2_0)
#define ENA_VREF			(b2_1)

#define ADC_CLK_PLL			(b1_0)
#define ADC_CLK_MCLK		(b1_1)

#define DAC_CLK_PLL			(b0_0)
#define DAC_CLK_MCLK		(b0_1)


//DAC_CONTROL_0
#define DAC_FMT_I2S			(b7_0 | b6_0)
#define DAC_FMT_TDM			(b7_0 | b6_1)
#define DAC_FMT_AUX			(b7_1 | b6_0)
#define DAC_FMT_DUALTDM		(b7_1 | b6_1)


#define DAC_BLK_DLY_1		(b5_0 | b4_0 | b3_0)
#define DAC_BLK_DLY_0		(b5_0 | b4_0 | b3_1)
#define DAC_BLK_DLY_8		(b5_0 | b4_1 | b3_0)
#define DAC_BLK_DLY_12		(b5_0 | b4_1 | b3_1)
#define DAC_BLK_DLY_16		(b5_1 | b4_0 | b3_0)

#define DAC_SR_48K			(b2_0 | b1_0)
#define DAC_SR_96K			(b2_0 | b1_1)
#define DAC_SR_192K			(b2_1 | b1_0)

#define DAC_PWR_UP			(b0_0)
#define DAC_PWR_DWN			(b0_1)


//DAC_CONTROL_1
#define DAC_BCLK_POL_NORM		(b7_0)
#define DAC_BCLK_POL_INV		(b7_1)

#define DAC_BCLK_SRC_PIN		(b6_0)
#define DAC_BCLK_SRC_INTERNAL	(b6_1)

#define DAC_BCLK_SLAVE			(b5_0)
#define DAC_BCLK_MASTER			(b5_1)

#define DAC_LRCLK_SLAVE			(b4_0)
#define DAC_LRCLK_MASTER		(b4_1)

#define DAC_LRCLK_POL_NORM		(b3_0)
#define DAC_LRCLK_POL_INV		(b3_1)

#define DAC_CHANNELS_2			(b2_0 | b1_0)
#define DAC_CHANNELS_4			(b2_0 | b1_1)
#define DAC_CHANNELS_8			(b2_1 | b1_0)
#define DAC_CHANNELS_16			(b2_1 | b1_1)

#define DAC_LTCH_MID			(b0_0)
#define DAC_LTCH_END			(b0_1)


//DAC_CONTROL_2
#define DAC_OUT_POL_NORM	(b5_0)
#define DAC_OUT_POL_INV		(b5_1)

#define DAC_WIDTH_24		(b4_0 | b3_0)
#define DAC_WIDTH_20		(b4_0 | b3_1)
#define DAC_WIDTH_16		(b4_1 | b3_1)

#define DAC_DEEMPH_FLAT		(b2_0 | b1_0)
#define DAC_DEEMPH_48K		(b2_0 | b1_1)
#define DAC_DEEMPH_44_1K	(b2_1 | b1_0)
#define DAC_DEEMPH_32K		(b2_1 | b1_1)

#define DAC_UNMUTE			(b0_0)
#define DAC_MUTE			(b0_1)


//ADC_CONTROL_0
#define ADC_SR_48K			(b7_0 | b6_0)
#define ADC_SR_96K			(b7_0 | b6_1)
#define ADC_SR_192K			(b7_1 | b6_0)

#define ADC_R2_UNMUTE		(b5_0)
#define ADC_R2_MUTE			(b5_1)

#define ADC_L2_UNMUTE		(b4_0)
#define ADC_L2_MUTE			(b4_1)

#define ADC_R1_UNMUTE		(b3_0)
#define ADC_R1_MUTE			(b3_1)

#define ADC_L1_UNMUTE		(b2_0)
#define ADC_L1_MUTE			(b2_1)

#define ADC_HP_FILT_OFF		(b1_0)
#define ADC_HP_FILT_ON		(b1_1)

#define ADC_PWR_UP			(b0_0)
#define ADC_PWN_DWN			(b0_1)


//ADC_CONTROL_1		0x000f
#define ADC_LTCH_MID		(b7_0)
#define ADC_LTCH_END		(b7_1)

#define ADC_FMT_I2S			(b6_0 | b5_0)
#define ADC_FMT_TDM			(b6_0 | b5_1)
#define ADC_FMT_AUX			(b6_1 | b5_0)

#define ADC_BLK_DLY_1		(b4_0 | b3_0 | b2_0)
#define ADC_BLK_DLY_0		(b4_0 | b3_0 | b2_1)
#define ADC_BLK_DLY_8		(b4_0 | b3_1 | b2_0)
#define ADC_BLK_DLY_12		(b4_0 | b3_1 | b2_1)
#define ADC_BLK_DLY_16		(b4_1 | b3_0 | b2_0)

#define ADC_WIDTH_24		(b1_0 | b0_0)
#define ADC_WIDTH_20		(b1_0 | b0_1)
#define ADC_WIDTH_16		(b1_1 | b0_1)


//ADC_CONTROL_2		0x0010
#define ADC_BCLK_SRC_PIN		(b7_0)
#define ADC_BCLK_SRC_INTERNAL	(b7_1)

#define ADC_BCLK_SLAVE			(b6_0)
#define ADC_BCLK_MASTER			(b6_1)

#define ADC_CHANNELS_2			(b5_0 | b4_0)
#define ADC_CHANNELS_4			(b5_0 | b4_1)
#define ADC_CHANNELS_8			(b5_1 | b4_0)
#define ADC_CHANNELS_16			(b5_1 | b4_1)

#define ADC_LRCLK_SLAVE			(b3_0)
#define ADC_LRCLK_MASTER		(b3_1)

#define ADC_LRCLK_POL_NORM		(b2_0)
#define ADC_LRCLK_POL_INV		(b2_1)

#define ADC_BCLK_POL_NORM		(b1_0)
#define ADC_BCLK_POL_INV		(b1_1)

#define ADC_LRCLK_FMT_50_50		(b0_0)
#define ADC_LRCLK_FMT_PULSE		(b0_1)


//=================================================================================
// ADAV801 CODEC

//Register 0x00/5:4
#define INTCLK2_DIV_1				b5_0	| b4_0
#define INTCLK2_DIV_1_5				b5_0	| b4_1
#define INTCLK2_DIV_2				b5_1	| b4_0
#define INTCLK2_DIV_3				b5_1	| b4_1
//Register 0x00/3:2
#define INTCLK1_DIV_1					b3_0	| b2_0	
#define INTCLK1_DIV_1_5					b3_0	| b2_1	
#define INTCLK1_DIV_2					b3_1	| b2_0	
#define INTCLK1_DIV_3					b3_1	| b2_1	

//Register 0x04
#define PRI_RX_CLK_SRC_SLAVE		b4_0	| b3_0
#define PRI_RX_CLK_SRC_SPDIF_RX_CLK	b4_0	| b3_1
#define PRI_RX_CLK_SRC_INTCLK1		b4_1	| b3_0
#define PRI_RX_CLK_SRC_INTCLK2		b4_1	| b3_1

//Register 0x05
#define SEC_RX_CLK_SRC_SLAVE		b4_0	| b3_0
#define SEC_RX_CLK_SRC_SPDIF_RX_CLK	b4_0	| b3_1
#define SEC_RX_CLK_SRC_INTCLK1		b4_1	| b3_0
#define SEC_RX_CLK_SRC_INTCLK2		b4_1	| b3_1

//Register 0x06
#define PRI_TX_CLK_SRC_SLAVE		b5_0	| b4_0
#define PRI_TX_CLK_SRC_SPDIF_RX_CLK	b5_0	| b4_1
#define PRI_TX_CLK_SRC_INTCLK1		b5_1	| b4_0
#define PRI_TX_CLK_SRC_INTCLK2		b5_1	| b4_1

//Register 0x07
#define SEC_TX_CLK_SRC_SLAVE		b5_0	| b4_0
#define SEC_TX_CLK_SRC_SPDIF_RX_CLK	b5_0	| b4_1
#define SEC_TX_CLK_SRC_INTCLK1		b5_1	| b4_0
#define SEC_TX_CLK_SRC_INTCLK2		b5_1	| b4_1

//Register 0x0C
#define SPDIF_TX_CLK_SRC_INTCLK1		b2_0	| b1_0
#define SPDIF_TX_CLK_SRC_INTCLK2		b2_0	| b1_1
#define SPDIF_TX_CLK_SRC_SPDIF_RX_CLK	b2_1	| b1_0

//Register 0x62
#define PRI_TX_DAT_SRC_ADC			b5_0 	| b4_0	| b3_0
#define PRI_TX_DAT_SRC_SPDIF_RX		b5_0	| b4_0	| b3_1
#define PRI_TX_DAT_SRC_PRI_RX		b5_0	| b4_1	| b3_0
#define PRI_TX_DAT_SRC_SEC_RX		b5_0	| b4_1	| b3_1
#define PRI_TX_DAT_SRC_SRC			b5_1	| b4_0	| b3_0
//Register 0x62
#define SEC_TX_DAT_SRC_ADC			b2_0 	| b1_0	| b0_0
#define SEC_TX_DAT_SRC_SPDIF_RX		b2_0	| b1_0	| b0_1
#define SEC_TX_DAT_SRC_PRI_RX		b2_0	| b1_1	| b0_0
#define SEC_TX_DAT_SRC_SEC_RX		b2_0	| b1_1	| b0_1
#define SEC_TX_DAT_SRC_SRC			b2_1	| b1_0	| b0_0

//Register 0x63
#define SPDIF_TX_DAT_SRC_ADC			b2_0 	| b1_0	| b0_0
#define SPDIF_TX_DAT_SRC_SPDIF			b2_0	| b1_0	| b0_1
#define SPDIF_TX_DAT_SRC_PRI_RX			b2_0	| b1_1	| b0_0
#define SPDIF_TX_DAT_SRC_SEC_RX			b2_0	| b1_1	| b0_1
#define SPDIF_TX_DAT_SRC_SRC			b2_1	| b1_0	| b0_0

//Register 0x74/7:6
#define SCLK3_SRC_PLL2_CLK				b7_0	| b6_0	
#define SCLK3_SRC_SPDIF_RX_CLK			b7_1	| b6_1	
//Register 0x74/0
#define FS3_FS_RATIO_512FS				b0_0
#define FS3_FS_RATIO_256FS				b0_1

//Register 0x75/7:6
#define FS2_FS_SEL_48K					b7_0	| b6_0	
#define FS2_FS_SEL_32K					b7_1	| b6_0	
#define FS2_FS_SEL_441K					b7_1	| b6_1	
//Register 0x75/5
#define FS2_FS_RATIO_256FS				b5_0
#define FS2_FS_RATIO_384FS				b5_1
//Register 0x75/4
#define FS2_MUL_1						b4_0
#define FS2_MUL_2						b4_1
//Register 0x75/3:2
#define FS1_FS_SEL_48K					b3_0	| b2_0	
#define FS1_FS_SEL_32K					b3_1	| b2_0	
#define FS1_FS_SEL_441K					b3_1	| b2_1	
//Register 0x75/1
#define FS1_FS_RATIO_256FS				b1_0
#define FS1_FS_RATIO_384FS				b1_1
//Register 0x75/0
#define FS1_MUL_1						b0_0
#define FS1_MUL_2						b0_1

//Register 0x76/1:0
#define INTCLK2_SRC_XIN					b1_0	| b0_0
#define INTCLK2_SRC_MCLK				b1_0	| b0_1
#define INTCLK2_SRC_PLLINT1				b1_1	| b0_0
#define INTCLK2_SRC_PLLINT2				b1_1	| b0_1

//Register 0x77/4:3
#define INTCLK1_SRC_XIN					b4_0	| b3_0
#define INTCLK1_SRC_MCLK				b4_0	| b3_1
#define INTCLK1_SRC_PLLINT1				b4_1	| b3_0
#define INTCLK1_SRC_PLLINT2				b4_1	| b3_1
//Register 0x77/2:1
#define PLL2_FS2_DIV_1					b2_0 	| b1_0
#define PLL2_FS2_DIV_2					b2_0 	| b1_1
#define PLL2_FS3_DIV_1					b2_1 	| b1_0
#define PLL2_FS3_DIV_2					b2_1 	| b1_1
//Register 0x77/0
#define PLL1_DIV_1						b0_0
#define PLL1_DIV_2						b0_1


//=================================================================================
// Audio EZ-Extender mode specific definition

#define SPDIF_TX_FREQ_SPDIF_RX_CLK 1
#define SPDIF_TX_FREQ_192K 2
#define SPDIF_TX_FREQ_144K 21
#define SPDIF_TX_FREQ_96K 3
#define SPDIF_TX_FREQ_48K 4
#define SPDIF_RX_DEST_BOTH 5
#define SPDIF_RX_DEST_SECONDARY 6 
#define SPDIF_RX_DEST_PRIMARY 7
#define SPDIF_RX_DEST_DISABLED 8
#define SPDIF_TX_SRC_DISABLED 9
#define SPDIF_TX_SRC_PRIMARY 10
#define SPDIF_TX_SRC_SECONDARY 11
#define SPDIF_TX_CLK_SELECT_SPDIF_RX_CLK 12
#define SPDIF_TX_CLK_SELECT_INTCLK1 13
#define SCLK3_SRC_SPDIF_RX_CLK_MODE			14
#define SCLK3_SRC_PLL2_CLK_MODE		15
#define ANALOG_INPUT_MODE_AUX 	16
#define ANALOG_INPUT_MODE_TDM 	17
#define ANALOG_OUTPUT_MODE_AUX 	16
#define ANALOG_OUTPUT_MODE_TDM 	17

//=================================================================================
// Audio EZ-Extender mode specific data

#if (ADAV801_SUPPORT)
// ADAV801 driver specific configuration command pair
volatile ADI_DEV_CMD_VALUE_PAIR ADAV801_Config [] = 
{
    { ADI_ADAV801_CMD_SET_SPI_SLAVE_SELECT, (void *)1 }, // ADAV801 slave select for BF537
    { ADI_ADAV801_CMD_SET_REG_00, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_03, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_04, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_05, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_06, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_07, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_09, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_0A, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_0B, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_0C, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_1E, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_62, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_63, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_64, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_65, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_6E, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_6F, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_74, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_75, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_76, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_77, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_78, (void*)0 },
    { ADI_ADAV801_CMD_SET_REG_7A, (void*)0 },
    { ADI_DEV_CMD_END, NULL },
};
#endif

// AD1938 A codec specific configuration command pair
volatile ADI_DEV_CMD_VALUE_PAIR AD1938_A_Config [] = 
{
   // { ADI_AD1938_CMD_SET_SPI_SLAVE_SELECT, (void *)5 }, // AD1938-A slave select for BF537
    { ADI_AD1938_CMD_SET_PLL_CLOCK_CONTROL_0, (void*)0 },
    { ADI_AD1938_CMD_SET_PLL_CLOCK_CONTROL_0, (void*)0 },
	{ ADI_AD1938_CMD_SET_PLL_CLOCK_CONTROL_1,	(void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_CONTROL_0, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_CONTROL_1, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_CONTROL_2, (void*)0 },
    { ADI_AD1938_CMD_SET_ADC_CONTROL_0, (void*)0 },
	{ ADI_AD1938_CMD_SET_ADC_CONTROL_1, (void*)0 },
	{ ADI_AD1938_CMD_SET_ADC_CONTROL_2, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_CHANNEL_MUTES, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_1LVOLUME_CONTROL, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_1RVOLUME_CONTROL, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_2LVOLUME_CONTROL, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_2RVOLUME_CONTROL, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_3LVOLUME_CONTROL, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_3RVOLUME_CONTROL, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_4LVOLUME_CONTROL, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_4RVOLUME_CONTROL, (void*)0 },
    { ADI_AD1938_CMD_SET_PLL_CLOCK_CONTROL_0, (void*)0 },
    { ADI_AD1938_CMD_SET_PLL_CLOCK_CONTROL_0, (void*)0 },
    { ADI_DEV_CMD_END, NULL },
};

// AD1938 B codec specific configuration command pair
volatile ADI_DEV_CMD_VALUE_PAIR AD1938_B_Config [] = 
{
   // { ADI_AD1938_CMD_SET_SPI_SLAVE_SELECT, (void *)6 }, // AD1938-B slave select for BF537
    { ADI_AD1938_CMD_SET_PLL_CLOCK_CONTROL_0, (void*)0 },
    { ADI_AD1938_CMD_SET_PLL_CLOCK_CONTROL_0, (void*)0 },
	{ ADI_AD1938_CMD_SET_PLL_CLOCK_CONTROL_1,	(void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_CONTROL_0, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_CONTROL_1, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_CONTROL_2, (void*)0 },
    { ADI_AD1938_CMD_SET_ADC_CONTROL_0, (void*)0 },
	{ ADI_AD1938_CMD_SET_ADC_CONTROL_1, (void*)0 },
	{ ADI_AD1938_CMD_SET_ADC_CONTROL_2, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_CHANNEL_MUTES, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_1LVOLUME_CONTROL, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_1RVOLUME_CONTROL, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_2LVOLUME_CONTROL, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_2RVOLUME_CONTROL, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_3LVOLUME_CONTROL, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_3RVOLUME_CONTROL, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_4LVOLUME_CONTROL, (void*)0 },
	{ ADI_AD1938_CMD_SET_DAC_4RVOLUME_CONTROL, (void*)0 },
    { ADI_AD1938_CMD_SET_PLL_CLOCK_CONTROL_0, (void*)0 },
    { ADI_AD1938_CMD_SET_PLL_CLOCK_CONTROL_0, (void*)0 },
    { ADI_DEV_CMD_END, NULL },
};

// digital mode index mapping table for configuration
int DigitalConstant[16][4] =
{
    { 0, 0, 0, 0 },
    { SPDIF_TX_FREQ_192K, SPDIF_TX_SRC_PRIMARY, SPDIF_RX_DEST_PRIMARY, SCLK3_SRC_SPDIF_RX_CLK_MODE },
    { SPDIF_TX_FREQ_48K, SPDIF_TX_SRC_PRIMARY, SPDIF_RX_DEST_PRIMARY, SCLK3_SRC_SPDIF_RX_CLK_MODE },
    { SPDIF_TX_FREQ_96K, SPDIF_TX_SRC_PRIMARY, SPDIF_RX_DEST_PRIMARY, SCLK3_SRC_SPDIF_RX_CLK_MODE },
    { SPDIF_TX_FREQ_SPDIF_RX_CLK, SPDIF_TX_SRC_PRIMARY, SPDIF_RX_DEST_PRIMARY, SCLK3_SRC_SPDIF_RX_CLK_MODE },
    { SPDIF_TX_FREQ_192K, SPDIF_TX_SRC_PRIMARY, SPDIF_RX_DEST_PRIMARY, SCLK3_SRC_PLL2_CLK_MODE },
    { SPDIF_TX_FREQ_48K, SPDIF_TX_SRC_PRIMARY, SPDIF_RX_DEST_PRIMARY, SCLK3_SRC_PLL2_CLK_MODE },
    { SPDIF_TX_FREQ_96K, SPDIF_TX_SRC_PRIMARY, SPDIF_RX_DEST_PRIMARY, SCLK3_SRC_PLL2_CLK_MODE },
    { SPDIF_TX_FREQ_SPDIF_RX_CLK, SPDIF_TX_SRC_PRIMARY, SPDIF_RX_DEST_PRIMARY, SCLK3_SRC_PLL2_CLK_MODE },
    { SPDIF_TX_FREQ_48K, SPDIF_TX_SRC_SECONDARY, SPDIF_RX_DEST_PRIMARY, SCLK3_SRC_PLL2_CLK_MODE },
    { SPDIF_TX_FREQ_192K, SPDIF_TX_SRC_PRIMARY, SPDIF_RX_DEST_SECONDARY, SCLK3_SRC_SPDIF_RX_CLK_MODE },
    { SPDIF_TX_FREQ_48K, SPDIF_TX_SRC_PRIMARY, SPDIF_RX_DEST_SECONDARY, SCLK3_SRC_SPDIF_RX_CLK_MODE },
    { SPDIF_TX_FREQ_96K, SPDIF_TX_SRC_PRIMARY, SPDIF_RX_DEST_SECONDARY, SCLK3_SRC_SPDIF_RX_CLK_MODE },
    { SPDIF_TX_FREQ_SPDIF_RX_CLK, SPDIF_TX_SRC_PRIMARY, SPDIF_RX_DEST_SECONDARY, SCLK3_SRC_SPDIF_RX_CLK_MODE },
    { SPDIF_TX_FREQ_SPDIF_RX_CLK, SPDIF_TX_SRC_SECONDARY, SPDIF_RX_DEST_SECONDARY, SCLK3_SRC_SPDIF_RX_CLK_MODE },
    { SPDIF_TX_FREQ_SPDIF_RX_CLK, SPDIF_TX_SRC_SECONDARY, SPDIF_RX_DEST_PRIMARY, SCLK3_SRC_SPDIF_RX_CLK_MODE },
};

// local variables for configuring Audio EZ-Extender
static int cSPDIF_TX_FREQ;
static int cSPDIF_TX_SRC;
static int cSPDIF_RX_DEST;
static int cSCLK3_SRC_MODE;

static int cSPDIF_TX_CLK_SELECT;
static int cFS2_FS_SEL;
static int cFS2_FS_RATIO;
static int cFS2_MUL;
static int cFS3_FS_RATIO;
static int cPLL2_DIV;
static int cINTCLK1_SRC;
static int cINTCLK1_DIV;

static int cPRI_RX_CLK_SRC;
static int cSEC_RX_CLK_SRC;
static int cSPDIF_TX_DAT_SRC;
static int cSPDIF_TX_CLK_SRC;

static int cPRI_TX_CLK_SRC;
static int cPRI_TX_DAT_SRC;
static int cSEC_TX_CLK_SRC;
static int cSEC_TX_DAT_SRC;

static int cSCLK3_SRC;
static int cINPUT_MUL;

static int cFS1_FS_SEL;
static int cFS1_FS_RATIO;
static int cFS1_MUL;
static int cPLL1_DIV;

static int cINTCLK2_SRC;
static int cINTCLK2_DIV;

static int cANALOG_SR;
static int cTDM_SLOTS;
static int cANALOG_INPUT_MODE;
static int cANALOG_OUTPUT_MODE;

static int cDAC_FMT;
static int cADC_FMT;

static int cDAC_SAMPLE_RATE;
static int cADC_SAMPLE_RATE;

static int cDAC_CHANNELS;
static int cADC_CHANNELS;

// DMA channel layout of Audio EZ-Extender
static int cADC_L1;
static int cADC_R1;
static int cADC_L2;
static int cADC_R2;
static int cADC_L3;
static int cADC_R3;
static int cADC_L4;
static int cADC_R4;
static int cSPDIF_RX_L;
static int cSPDIF_RX_R;

static int cDAC_L1;
static int cDAC_R1;
static int cDAC_L2;
static int cDAC_R2;
static int cDAC_L3;
static int cDAC_R3;
static int cDAC_L4;
static int cDAC_R4;
static int cDAC_L5;
static int cDAC_R5;
static int cDAC_L6;
static int cDAC_R6;
static int cDAC_L7;
static int cDAC_R7;
static int cDAC_L8;
static int cDAC_R8;
static int cSPDIF_TX_L;
static int cSPDIF_TX_R;


/**********************************************************************************

  Driver specific definitions / prototype / data

**********************************************************************************/
// type definition of physical driver instance
typedef struct 
{
    ADI_DEV_MANAGER_HANDLE      ManagerHandle;      // Manager Handle
    ADI_DEV_DEVICE_HANDLE       DMHandle;           // Handle of Device Manager instance
    ADI_DMA_MANAGER_HANDLE      DMAHandle;          // handle to the DMA manager
    ADI_DCB_HANDLE              DCBHandle;          // callback handle
    u32                         InUseFlag;          // flag to indicate whether an instance is in use or not
    ADI_DCB_CALLBACK_FN         DMCallback;         // the callback function supplied by the Device Manager
    ADI_DEV_PDD_HANDLE          AD1938Handle;       // handle for AD1938 A&B device
    ADI_DEV_PDD_HANDLE          ADAV801Handle;      // handle for ADAV801 device
    u32                         AnalogMode;         // analog mode selection
    u32                         DigitalMode;        // digital mode selection
    u32                         SportSelect;        // select SPORT0/1 jumper setting on the board
    // select which device the read/write/control message is redirected to
    AUDIOEZEXTENDER_CODEC_SELECTION SelectedDevice;
}
  ADI_AUDIOEZEXTENDER;

// The initial values for the device instance
static ADI_AUDIOEZEXTENDER Device[] = 
{
    {
        NULL,
        NULL,
        NULL,
        NULL,
        false,
        NULL,
        NULL,   // AD1938 device handle
        NULL,   // ADAV801 device handle
        0,      // analog mode index
        6,      // digital mode index
        0,      // 0: OFF SPORT1 selected for SPORT A
        ADI_AD1938,  // default device
    },
};

// forward declaration for callback function
static void AudioEZExtenderCallbackFunction(void* DeviceHandle, u32 Event, void* pArg);


/*********************************************************************
*
*	Function:		setAudioMode
*
*	Description:	Configuration command for each device is determined here
*                   based on analog and digital mode index number.
*                   It calls driver control functions to configure each.
*
*********************************************************************/
static void setAudioMode(ADI_AUDIOEZEXTENDER *pAUDIOEZEXTENDER)
{
    u32 Result = ADI_DEV_RESULT_SUCCESS;
  	int regval;
    // get the local parameters from the digital mode index
    cSPDIF_TX_FREQ = DigitalConstant[pAUDIOEZEXTENDER->DigitalMode][0];
    cSPDIF_TX_SRC = DigitalConstant[pAUDIOEZEXTENDER->DigitalMode][1];
    cSPDIF_RX_DEST = DigitalConstant[pAUDIOEZEXTENDER->DigitalMode][2];
    cSCLK3_SRC_MODE = DigitalConstant[pAUDIOEZEXTENDER->DigitalMode][3];

    switch (cSPDIF_TX_FREQ)
    {
    case SPDIF_TX_FREQ_48K:
        cSPDIF_TX_CLK_SELECT = SPDIF_TX_CLK_SELECT_INTCLK1;
        //PLL2/SCLK2/SCLK3 Setup
        cFS2_FS_SEL = FS2_FS_SEL_48K;
        cFS2_FS_RATIO = FS2_FS_RATIO_256FS;
        cFS2_MUL = FS2_MUL_1;
        cFS3_FS_RATIO = FS3_FS_RATIO_512FS;
        cPLL2_DIV = PLL2_FS2_DIV_1;
        //INTCLK1 Setup					
        cINTCLK1_SRC = INTCLK1_SRC_PLLINT2;
        cINTCLK1_DIV = INTCLK1_DIV_1;
        break;
    case SPDIF_TX_FREQ_96K:
        cSPDIF_TX_CLK_SELECT = SPDIF_TX_CLK_SELECT_INTCLK1;
        //PLL2/SCLK2/SCLK3 Setup		
        cFS2_FS_SEL = FS2_FS_SEL_48K;
        cFS2_FS_RATIO = FS2_FS_RATIO_256FS;
        cFS2_MUL = FS2_MUL_1;
        cFS3_FS_RATIO = FS3_FS_RATIO_512FS;
        cPLL2_DIV = PLL2_FS3_DIV_1;
        //INTCLK1 Setup					
        cINTCLK1_SRC = INTCLK1_SRC_PLLINT2;
        cINTCLK1_DIV = INTCLK1_DIV_1;
        break;
    case SPDIF_TX_FREQ_192K:
        //IMPORTANT NOTE: to use this mode you need to change the jumper JP2 to use SYSCLK1
        cSPDIF_TX_CLK_SELECT = SPDIF_TX_CLK_SELECT_INTCLK1;
        //PLL2/SCLK2/SCLK3 Setup		
        cFS2_FS_SEL = FS2_FS_SEL_48K;
        cFS2_FS_RATIO = FS2_FS_RATIO_256FS;
        cFS2_MUL = FS2_MUL_2;
        cFS3_FS_RATIO = FS3_FS_RATIO_512FS;
        cPLL2_DIV = PLL2_FS3_DIV_1;
        //INTCLK1 Setup					
        cINTCLK1_SRC = INTCLK1_SRC_PLLINT2;
        cINTCLK1_DIV = INTCLK1_DIV_1;
        break;
    case SPDIF_TX_FREQ_SPDIF_RX_CLK:
        cSPDIF_TX_CLK_SELECT = SPDIF_TX_CLK_SELECT_SPDIF_RX_CLK;
        //PLL2/SCLK2/SCLK3 Setup		
        cFS2_FS_SEL = FS2_FS_SEL_48K;
        cFS2_FS_RATIO = FS2_FS_RATIO_256FS;
        cFS2_MUL = FS2_MUL_1;
        cFS3_FS_RATIO = FS3_FS_RATIO_512FS;
        cPLL2_DIV = PLL2_FS2_DIV_1;
        //INTCLK1 Setup					
        cINTCLK1_SRC = INTCLK1_SRC_PLLINT2;
        cINTCLK1_DIV = INTCLK1_DIV_1;
        break;
    }

    switch (cSPDIF_TX_SRC)
    {
    case SPDIF_TX_SRC_DISABLED:
        if (cSPDIF_TX_CLK_SELECT == SPDIF_TX_CLK_SELECT_INTCLK1)
        {
            cPRI_RX_CLK_SRC = PRI_RX_CLK_SRC_SLAVE;
            cSEC_RX_CLK_SRC = SEC_RX_CLK_SRC_SPDIF_RX_CLK;
            cSPDIF_TX_DAT_SRC = SPDIF_TX_DAT_SRC_PRI_RX;
            cSPDIF_TX_CLK_SRC = SPDIF_TX_CLK_SRC_INTCLK1;
        }
        else if (cSPDIF_TX_CLK_SELECT == SPDIF_TX_CLK_SELECT_SPDIF_RX_CLK)
        {
            cPRI_RX_CLK_SRC = PRI_RX_CLK_SRC_SLAVE;
            cSEC_RX_CLK_SRC = SEC_RX_CLK_SRC_SPDIF_RX_CLK;
            cSPDIF_TX_DAT_SRC = SPDIF_TX_DAT_SRC_PRI_RX;
            cSPDIF_TX_CLK_SRC = SPDIF_TX_CLK_SRC_SPDIF_RX_CLK;
        }
        break;
    case SPDIF_TX_SRC_PRIMARY:
        if (cSPDIF_TX_CLK_SELECT == SPDIF_TX_CLK_SELECT_INTCLK1)
        {
            cPRI_RX_CLK_SRC = PRI_RX_CLK_SRC_INTCLK1;
            cSEC_RX_CLK_SRC = SEC_RX_CLK_SRC_SPDIF_RX_CLK;
            cSPDIF_TX_DAT_SRC = SPDIF_TX_DAT_SRC_PRI_RX;
            cSPDIF_TX_CLK_SRC = SPDIF_TX_CLK_SRC_INTCLK1;
        }
        else if (cSPDIF_TX_CLK_SELECT == SPDIF_TX_CLK_SELECT_SPDIF_RX_CLK)
        {
            cPRI_RX_CLK_SRC = PRI_RX_CLK_SRC_SPDIF_RX_CLK;
            cSEC_RX_CLK_SRC = SEC_RX_CLK_SRC_SPDIF_RX_CLK;
            cSPDIF_TX_DAT_SRC = SPDIF_TX_DAT_SRC_PRI_RX;
            cSPDIF_TX_CLK_SRC = SPDIF_TX_CLK_SRC_SPDIF_RX_CLK;
        }
        break;
    case SPDIF_TX_SRC_SECONDARY:
        if (cSPDIF_TX_CLK_SELECT == SPDIF_TX_CLK_SELECT_INTCLK1)
        {
            cPRI_RX_CLK_SRC = PRI_RX_CLK_SRC_SLAVE;
            cSEC_RX_CLK_SRC = SEC_RX_CLK_SRC_SPDIF_RX_CLK;
            cSPDIF_TX_DAT_SRC = SPDIF_TX_DAT_SRC_SEC_RX;
            cSPDIF_TX_CLK_SRC = SPDIF_TX_CLK_SRC_INTCLK1;
        }
        else if (cSPDIF_TX_CLK_SELECT == SPDIF_TX_CLK_SELECT_SPDIF_RX_CLK)
        {
            cPRI_RX_CLK_SRC = PRI_RX_CLK_SRC_SLAVE;
            cSEC_RX_CLK_SRC = SEC_RX_CLK_SRC_SPDIF_RX_CLK;
            cSPDIF_TX_DAT_SRC = SPDIF_TX_DAT_SRC_SEC_RX;
            cSPDIF_TX_CLK_SRC = SPDIF_TX_CLK_SRC_SPDIF_RX_CLK;
        }
        break;
    }

    switch (cSPDIF_RX_DEST)
    {
    case SPDIF_RX_DEST_DISABLED:
        cPRI_TX_CLK_SRC = PRI_TX_CLK_SRC_SLAVE;
        cPRI_TX_DAT_SRC = PRI_TX_DAT_SRC_SPDIF_RX;
        cSEC_TX_CLK_SRC = SEC_TX_CLK_SRC_SLAVE;
        cSEC_TX_DAT_SRC = SEC_TX_DAT_SRC_SPDIF_RX;
        break;
    case SPDIF_RX_DEST_PRIMARY:
        cPRI_TX_CLK_SRC = PRI_TX_CLK_SRC_SPDIF_RX_CLK;
        cPRI_TX_DAT_SRC = PRI_TX_DAT_SRC_SPDIF_RX;
        cSEC_TX_CLK_SRC = SEC_TX_CLK_SRC_SLAVE;
        cSEC_TX_DAT_SRC = SEC_TX_DAT_SRC_SPDIF_RX;
        break;
    case SPDIF_RX_DEST_SECONDARY:
        cPRI_TX_CLK_SRC = PRI_TX_CLK_SRC_SLAVE;
        cPRI_TX_DAT_SRC = PRI_TX_DAT_SRC_SPDIF_RX;
        cSEC_TX_CLK_SRC = SEC_TX_CLK_SRC_SLAVE;
        cSEC_TX_DAT_SRC = SEC_TX_DAT_SRC_SPDIF_RX;
        break;
    case SPDIF_RX_DEST_BOTH:
        cPRI_TX_CLK_SRC = PRI_TX_CLK_SRC_SPDIF_RX_CLK;
        cPRI_TX_DAT_SRC = PRI_TX_DAT_SRC_SPDIF_RX;
        cSEC_TX_CLK_SRC = SEC_TX_CLK_SRC_SLAVE;
        cSEC_TX_DAT_SRC = SEC_TX_DAT_SRC_SPDIF_RX;
        break;
    }

    switch (cSCLK3_SRC_MODE)
    {
    case SCLK3_SRC_SPDIF_RX_CLK_MODE:
	    cSCLK3_SRC = SCLK3_SRC_SPDIF_RX_CLK;
        break;
    case SCLK3_SRC_PLL2_CLK_MODE:
	    cSCLK3_SRC = SCLK3_SRC_PLL2_CLK;
        break;
    }

    if ((cSCLK3_SRC_MODE == SCLK3_SRC_SPDIF_RX_CLK_MODE) || (cSPDIF_TX_FREQ == SPDIF_TX_FREQ_192K))
	    cINPUT_MUL = INPUT256;
    else
	    cINPUT_MUL = INPUT512;


    //PLL1/SCLK1 Setup				
    cFS1_FS_SEL = FS1_FS_SEL_48K;
    cFS1_FS_RATIO = FS1_FS_RATIO_256FS;
    cFS1_MUL = FS1_MUL_2;
    cPLL1_DIV = PLL1_DIV_1;
    //INTCLK2 Setup					
    cINTCLK2_SRC = INTCLK2_SRC_MCLK;
    cINTCLK2_DIV = INTCLK2_DIV_1;


    switch (pAUDIOEZEXTENDER->AnalogMode)
    {
    case 1:
	    cANALOG_SR = 192;
	    cTDM_SLOTS = 4;
	    cANALOG_INPUT_MODE = ANALOG_INPUT_MODE_TDM;
	    cANALOG_OUTPUT_MODE = ANALOG_OUTPUT_MODE_TDM;
        break;
    case 2:
	    cANALOG_SR = 96;
	    cTDM_SLOTS = 4;
	    cANALOG_INPUT_MODE = ANALOG_INPUT_MODE_TDM;
	    cANALOG_OUTPUT_MODE = ANALOG_OUTPUT_MODE_TDM;
        break;
    case 3:
	    cANALOG_SR = 48;
	    cTDM_SLOTS = 4;
	    cANALOG_INPUT_MODE = ANALOG_INPUT_MODE_TDM;
	    cANALOG_OUTPUT_MODE = ANALOG_OUTPUT_MODE_TDM;
        break;
    case 4:
	    cANALOG_SR = 96;
	    cTDM_SLOTS = 8;
	    cANALOG_INPUT_MODE = ANALOG_INPUT_MODE_TDM;
	    cANALOG_OUTPUT_MODE = ANALOG_OUTPUT_MODE_TDM;
        break;
    case 5:
	    cANALOG_SR = 48;
	    cTDM_SLOTS = 8;
	    cANALOG_INPUT_MODE = ANALOG_INPUT_MODE_TDM;
	    cANALOG_OUTPUT_MODE = ANALOG_OUTPUT_MODE_TDM;
        break;
    case 6:
	    cANALOG_SR = 48;
	    cTDM_SLOTS = 16;
	    cANALOG_INPUT_MODE = ANALOG_INPUT_MODE_TDM;
	    cANALOG_OUTPUT_MODE = ANALOG_OUTPUT_MODE_TDM;
        break;
    case 7:
	    cANALOG_SR = 48;
	    cTDM_SLOTS = 16;
	    cANALOG_INPUT_MODE = ANALOG_INPUT_MODE_TDM;
	    cANALOG_OUTPUT_MODE = ANALOG_OUTPUT_MODE_AUX;
        break;
    case 8:
	    cANALOG_SR = 48;
	    cTDM_SLOTS = 8;
	    cANALOG_INPUT_MODE = ANALOG_INPUT_MODE_TDM;
	    cANALOG_OUTPUT_MODE = ANALOG_OUTPUT_MODE_TDM;
        break;
    case 9:
	    cANALOG_SR = 96;
	    cTDM_SLOTS = 8;
	    cANALOG_INPUT_MODE = ANALOG_INPUT_MODE_TDM;
	    cANALOG_OUTPUT_MODE = ANALOG_OUTPUT_MODE_TDM;
        break;
    case 10:
	    cANALOG_SR = 48;
	    cTDM_SLOTS = 16;
	    cANALOG_INPUT_MODE = ANALOG_INPUT_MODE_TDM;
	    cANALOG_OUTPUT_MODE = ANALOG_OUTPUT_MODE_AUX;
        break;
    }


    if (cANALOG_OUTPUT_MODE == ANALOG_OUTPUT_MODE_TDM)
        cDAC_FMT = DAC_FMT_TDM;
    else // ANALOG_OUTPUT_MODE_AUX
        cDAC_FMT = DAC_FMT_AUX;

    if (cANALOG_INPUT_MODE == ANALOG_INPUT_MODE_TDM)
        cADC_FMT = DAC_FMT_TDM;
    else // ANALOG_INPUT_MODE_AUX
        cADC_FMT = DAC_FMT_AUX;


    switch (cANALOG_SR)
    {
    case 48:
        cDAC_SAMPLE_RATE = DAC_SR_48K;
        cADC_SAMPLE_RATE = ADC_SR_48K;
        break;
    case 96:
        cDAC_SAMPLE_RATE = DAC_SR_96K;
        cADC_SAMPLE_RATE = ADC_SR_96K;
        break;
    case 192:
        cDAC_SAMPLE_RATE = DAC_SR_192K;
        cADC_SAMPLE_RATE = ADC_SR_192K;
        break;
    }


    switch (cTDM_SLOTS)
    {
    case 4:
        cDAC_CHANNELS = DAC_CHANNELS_4;
        cADC_CHANNELS = ADC_CHANNELS_4;
        break;
    case 8:
        cDAC_CHANNELS = DAC_CHANNELS_8;
        cADC_CHANNELS = ADC_CHANNELS_8;
        break;
    case 16:
        cDAC_CHANNELS = DAC_CHANNELS_16;
        cADC_CHANNELS = ADC_CHANNELS_16;
        break;
    }

    // names for slots in ad1938 audio frame
    cADC_L1 = 0;
    cADC_R1 = 2;
    cADC_L2 = 4;
    cADC_R2 = 6;
    cADC_L3 = 1;
    cADC_R3 = 3;
    cADC_L4 = 5;
    cADC_R4 = 7;
    cSPDIF_RX_L = 8;
    cSPDIF_RX_R = 10;

    if ((cTDM_SLOTS == 16) && (cANALOG_OUTPUT_MODE == ANALOG_OUTPUT_MODE_TDM))
    {
        cDAC_L1 = 16;
        cDAC_R1 = 18;
        cDAC_L2 = 20;
        cDAC_R2 = 22;
        cDAC_L3 = 24;
        cDAC_R3 = 26;
        cDAC_L4 = 28;
        cDAC_R4 = 30;
        cDAC_L5 = 17;
        cDAC_R5 = 19;
        cDAC_L6 = 21;
        cDAC_R6 = 23;
        cDAC_L7 = 25;
        cDAC_R7 = 27;
        cDAC_L8 = 29;
        cDAC_R8 = 31;
    }
    else if ((cTDM_SLOTS == 16) && (cANALOG_OUTPUT_MODE == ANALOG_OUTPUT_MODE_AUX))
    {
        cDAC_L1 = 8;
        cDAC_R1 = 10;
        cDAC_L2 = 12;
        cDAC_R2 = 14;
        cDAC_L3 = 16;
        cDAC_R3 = 18;
        cDAC_L4 = 20;
        cDAC_R4 = 22;
        cSPDIF_TX_L = 24;
        cSPDIF_TX_R = 26;
        cDAC_L5 = 17;
        cDAC_R5 = 19;
        cDAC_L6 = 21;
        cDAC_R6 = 23;
        cDAC_L7 = 25;
        cDAC_R7 = 27;
        cDAC_L8 = 29;
        cDAC_R8 = 31;
    }
    else
    {
        cDAC_L1 = 0;
        cDAC_R1 = 2;
        cDAC_L2 = 4;
        cDAC_R2 = 6;
        cDAC_L3 = 8;
        cDAC_R3 = 10;
        cDAC_L4 = 12;
        cDAC_R4 = 14;
        cDAC_L5 = 1;
        cDAC_R5 = 3;
        cDAC_L6 = 5;
        cDAC_R6 = 7;
        cDAC_L7 = 9;
        cDAC_R7 = 11;
        cDAC_L8 = 13;
        cDAC_R8 = 15;
    }


#if (ADAV801_SUPPORT)
    ADAV801_Config[1].Value =  (void*)( b7_0	| b6_0	| cINTCLK2_DIV	| cINTCLK1_DIV	| b1_0	| b0_0);
	ADAV801_Config[2].Value =  (void*)(		    											    | b0_0);
	ADAV801_Config[3].Value =  (void*)(		    				cPRI_RX_CLK_SRC	| b2_0	| b1_0	| b0_1);
	ADAV801_Config[4].Value =  (void*)(		    				cSEC_RX_CLK_SRC	| b2_0	| b1_0	| b0_1);
	ADAV801_Config[5].Value =  (void*)(		    		cPRI_TX_CLK_SRC	| b3_0	| b2_0	| b1_0	| b0_1);
	ADAV801_Config[6].Value =  (void*)(		    		cSEC_TX_CLK_SRC	| b3_0	| b2_0	| b1_0	| b0_1);
	ADAV801_Config[7].Value =  (void*)( b7_0	| b6_0	| b5_0	| b4_0	| b3_0	| b2_0	| b1_0	| b0_0);
	ADAV801_Config[8].Value =  (void*)( b7_0	| b6_0	| b5_0	| b4_0	| b3_0	| b2_0	| b1_0	| b0_0);
	ADAV801_Config[9].Value =  (void*)(  	    		| b5_0	| b4_0	| b3_0	| b2_0	| b1_0	| b0_0);
	ADAV801_Config[10].Value = (void*)(     	| b6_0	| b5_0	| b4_0	| b3_0	| cSPDIF_TX_CLK_SRC	| b0_1);
	ADAV801_Config[11].Value = (void*)(  	    		| b5_0			| b3_0	| b2_0	| b1_0	| b0_0);
	ADAV801_Config[12].Value = (void*)( b7_0	| b6_0	| cPRI_TX_DAT_SRC		| cSEC_TX_DAT_SRC);
	ADAV801_Config[13].Value = (void*)(		        	| b5_0	| b4_0	| b3_0	| cSPDIF_TX_DAT_SRC);
	ADAV801_Config[14].Value = (void*)( b7_0	| b6_0	| b5_0	| b4_0	| b3_0	| b2_0	| b1_0	| b0_0);
	ADAV801_Config[15].Value = (void*)(     			| b5_0	| b4_0	| b3_0	| b2_0	| b1_0	| b0_0);
	ADAV801_Config[16].Value = (void*)( b7_0	| b6_0	| b5_1	| b4_0	| b3_0	| b2_0	| b1_0	| b0_0);
	ADAV801_Config[17].Value = (void*)(  			    		| b4_1					| b1_0	| b0_0);
	ADAV801_Config[18].Value = (void*)(     cSCLK3_SRC	| b5_0	| b4_0	| b3_0	| b2_0	| b1_0	| cFS3_FS_RATIO);
	ADAV801_Config[19].Value = (void*)( cFS2_FS_SEL	| cFS2_FS_RATIO	| cFS2_MUL	| cFS1_FS_SEL	| cFS1_FS_RATIO	| cFS1_MUL);
	ADAV801_Config[20].Value = (void*)( b7_0	| b6_0	| b5_0	| b4_0	| b3_0	| b2_0	| cINTCLK2_SRC);
	ADAV801_Config[21].Value = (void*)(					| cINTCLK1_SRC	| cPLL2_DIV	| cPLL1_DIV);
	ADAV801_Config[22].Value = (void*)( b7_0	| b6_0);
	ADAV801_Config[23].Value = (void*)(  	    		| b5_0	| b4_0			| b2_0	| b1_0	| b0_0);
#endif


    // AD1938 A CODEC
   // AD1938_A_Config[0].Value  = (void*)0x5;
    AD1938_A_Config[1].Value =  (void*)(DIS_ADC_DAC | PLL_IN_MCLK | MCLK_OUT_OFF | cINPUT_MUL | PLL_PWR_DWN );
	AD1938_A_Config[2].Value =  (void*)(DAC_CLK_PLL | ADC_CLK_PLL | DIS_VREF );
	AD1938_A_Config[3].Value =  (void*)(cDAC_FMT | DAC_BLK_DLY_1 | cDAC_SAMPLE_RATE | DAC_PWR_UP);
	AD1938_A_Config[4].Value =  (void*)(DAC_BCLK_POL_INV | DAC_BCLK_SRC_PIN | DAC_BCLK_SLAVE | DAC_LRCLK_SLAVE | DAC_LRCLK_POL_NORM | cDAC_CHANNELS | DAC_LTCH_MID);
	AD1938_A_Config[5].Value =  (void*)(DAC_OUT_POL_NORM | DAC_WIDTH_24 | DAC_DEEMPH_FLAT | DAC_UNMUTE);
	AD1938_A_Config[6].Value =  (void*)(cADC_SAMPLE_RATE |  ADC_R2_UNMUTE | ADC_L2_UNMUTE | ADC_R1_UNMUTE | ADC_L1_UNMUTE |ADC_HP_FILT_OFF | ADC_PWR_UP);
	AD1938_A_Config[7].Value =  (void*)(ADC_LTCH_MID | cADC_FMT | ADC_BLK_DLY_1 | ADC_WIDTH_24);
	AD1938_A_Config[8].Value =  (void*)(ADC_BCLK_SRC_PIN | ADC_BCLK_MASTER | cADC_CHANNELS | ADC_LRCLK_MASTER | ADC_LRCLK_POL_INV | ADC_BCLK_POL_INV | ADC_LRCLK_FMT_PULSE);
	AD1938_A_Config[9].Value =  (void*)0x00;
	AD1938_A_Config[10].Value = (void*)0x00;
	AD1938_A_Config[11].Value = (void*)0x00;
	AD1938_A_Config[12].Value = (void*)0x00;
	AD1938_A_Config[13].Value = (void*)0x00;
	AD1938_A_Config[14].Value = (void*)0x00;
	AD1938_A_Config[15].Value = (void*)0x00;
	AD1938_A_Config[16].Value = (void*)0x00;
	AD1938_A_Config[17].Value = (void*)0x00;
	AD1938_A_Config[18].Value = (void*)(DIS_ADC_DAC | PLL_IN_MCLK | MCLK_OUT_OFF | cINPUT_MUL | PLL_PWR_UP );
	AD1938_A_Config[19].Value = (void*)(ENA_ADC_DAC | PLL_IN_MCLK | MCLK_OUT_OFF | cINPUT_MUL | PLL_PWR_UP );

    // AD1938 B CODEC
    AD1938_B_Config[1].Value =  (void*)(DIS_ADC_DAC | PLL_IN_MCLK | MCLK_OUT_OFF | cINPUT_MUL | PLL_PWR_DWN );
	AD1938_B_Config[2].Value =  (void*)(DAC_CLK_PLL | ADC_CLK_PLL | DIS_VREF );
	AD1938_B_Config[3].Value =  (void*)(DAC_FMT_TDM | DAC_BLK_DLY_1 | cDAC_SAMPLE_RATE | DAC_PWR_UP);
	AD1938_B_Config[4].Value =  (void*)(DAC_BCLK_POL_INV | DAC_BCLK_SRC_PIN | DAC_BCLK_SLAVE | DAC_LRCLK_SLAVE | DAC_LRCLK_POL_NORM | cDAC_CHANNELS | DAC_LTCH_MID);
	AD1938_B_Config[5].Value =  (void*)(DAC_OUT_POL_NORM | DAC_WIDTH_24 | DAC_DEEMPH_FLAT | DAC_UNMUTE);
	AD1938_B_Config[6].Value =  (void*)(cADC_SAMPLE_RATE |  ADC_R2_UNMUTE | ADC_L2_UNMUTE | ADC_R1_UNMUTE | ADC_L1_UNMUTE |ADC_HP_FILT_OFF | ADC_PWR_UP);
	AD1938_B_Config[7].Value =  (void*)(ADC_LTCH_MID | ADC_FMT_AUX | ADC_BLK_DLY_1 | ADC_WIDTH_24);
	AD1938_B_Config[8].Value =  (void*)(ADC_BCLK_SRC_PIN | ADC_BCLK_SLAVE | cADC_CHANNELS | ADC_LRCLK_SLAVE | ADC_LRCLK_POL_INV | ADC_BCLK_POL_INV| ADC_LRCLK_FMT_PULSE);
	AD1938_B_Config[9].Value =  (void*)0x00;
	AD1938_B_Config[10].Value = (void*)0x00;
	AD1938_B_Config[11].Value = (void*)0x00;
	AD1938_B_Config[12].Value = (void*)0x00;
	AD1938_B_Config[13].Value = (void*)0x00;
	AD1938_B_Config[14].Value = (void*)0x00;
	AD1938_B_Config[15].Value = (void*)0x00;
	AD1938_B_Config[16].Value = (void*)0x00;
	AD1938_B_Config[17].Value = (void*)0x00;
	AD1938_B_Config[18].Value = (void*)(DIS_ADC_DAC | PLL_IN_MCLK | MCLK_OUT_OFF | cINPUT_MUL | PLL_PWR_UP );
	AD1938_B_Config[19].Value = (void*)(ENA_ADC_DAC | PLL_IN_MCLK | MCLK_OUT_OFF | cINPUT_MUL | PLL_PWR_UP );

#if (ADAV801_SUPPORT)

    Result = adi_dev_Control(pAUDIOEZEXTENDER->ADAV801Handle, ADI_DEV_CMD_TABLE, ADAV801_Config);
#ifdef ADI_DEV_DEBUG
	if (Result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif

    // always I2S for SPORT
    Result = adi_dev_Control(pAUDIOEZEXTENDER->ADAV801Handle, ADI_ADAV801_CMD_SET_OPERATION_MODE_I2S, (void*)0);
#ifdef ADI_DEV_DEBUG
	if (Result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif

    // configure the ADAV801 dataflow method to circular(autobuffer) mode (FIXED)
    Result = adi_dev_Control(pAUDIOEZEXTENDER->ADAV801Handle, ADI_DEV_CMD_SET_DATAFLOW_METHOD, (void*)ADI_DEV_MODE_CIRCULAR);
#ifdef ADI_DEV_DEBUG
	if (Result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif

#endif  // ADAV801


//Result = adi_dev_Control(pAUDIOEZEXTENDER->AD1938Handle, 
//                   ADI_DEV_CMD_REGISTER_WRITE, 
//                   (void*)ADI_AD1938_CMD_SET_PLL_CLOCK_CONTROL_0 );

// Set AD1938 A SPI Chipselect
Result = adi_dev_Control(pAUDIOEZEXTENDER->AD1938Handle, 
                 ADI_AD1938_CMD_SET_SPI_SLAVE_SELECT, 
                   (void*)AD1938_A_SPICS_BF537KIT );

Result = adi_dev_Control(pAUDIOEZEXTENDER->AD1938Handle, 
                   ADI_SPI_CMD_EXECUTE_DUMMY_READ, 
                   (void*)0x8 );

                   
Result = adi_dev_Control(pAUDIOEZEXTENDER->AD1938Handle, ADI_DEV_CMD_TABLE, (void*)AD1938_A_Config);

#if 0
Result = adi_dev_Control(pAUDIOEZEXTENDER->AD1938Handle, 
                 ADI_AD1938_CMD_SET_SPI_SLAVE_DESELECT, 
                   (void*)AD1938_A_SPICS_BF537KIT );
#endif              

#ifdef ADI_DEV_DEBUG
	if (Result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif

// Set AD1938 B SPI Chipselect
    Result = adi_dev_Control(pAUDIOEZEXTENDER->AD1938Handle, 
                   ADI_AD1938_CMD_SET_SPI_SLAVE_SELECT, 
                   (void*)AD1938_B_SPICS_BF537KIT );
#ifdef ADI_DEV_DEBUG
    if (Result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif

Result = adi_dev_Control(pAUDIOEZEXTENDER->AD1938Handle, ADI_DEV_CMD_TABLE, (void*)AD1938_B_Config);

#ifdef ADI_DEV_DEBUG
	if (Result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif

#if 0
Result = adi_dev_Control(pAUDIOEZEXTENDER->AD1938Handle, 
                   ADI_AD1938_CMD_SET_SPI_SLAVE_DESELECT, 
                   (void*)AD1938_B_SPICS_BF537KIT );
#endif                   
                   
#ifdef ADI_DEV_DEBUG
    if (Result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif


    // always TDM for SPORT
    Result = adi_dev_Control(pAUDIOEZEXTENDER->AD1938Handle, ADI_AD1938_CMD_SET_OPERATION_MODE_TDM, (void*)0);

    #ifdef ADI_DEV_DEBUG
	if (Result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif
    

    // configure the AD1938 dataflow method to circular(autobuffer) mode (FIXED)
    Result = adi_dev_Control(pAUDIOEZEXTENDER->AD1938Handle, ADI_DEV_CMD_SET_DATAFLOW_METHOD, (void*)ADI_DEV_MODE_CIRCULAR);

    #ifdef ADI_DEV_DEBUG
	if (Result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif

    // Set Multichannel Frame Delay (must match AD1938 BCLK delay)
    Result = adi_dev_Control(pAUDIOEZEXTENDER->AD1938Handle, ADI_SPORT_CMD_SET_MC_FRAME_DELAY, (void*)1);
#ifdef ADI_DEV_DEBUG
    if (Result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif

}

/*********************************************************************
*
*	Function:		adi_pdd_Open
*
*	Description:	Opens the Audio EZ-Extender device for use
*
*********************************************************************/

static u32 adi_pdd_Open(
	ADI_DEV_MANAGER_HANDLE	ManagerHandle,			// device manager handle
	u32 					DeviceNumber,			// device number
	ADI_DEV_DEVICE_HANDLE	DMHandle,				// device handle
	ADI_DEV_PDD_HANDLE 		*pPDDHandle,			// pointer to PDD handle location
	ADI_DEV_DIRECTION 		Direction,				// data direction
	void					*pEnterCriticalArg,		// enter critical region parameter
	ADI_DMA_MANAGER_HANDLE	DMAHandle,				// handle to the DMA manager
	ADI_DCB_HANDLE			DCBHandle,				// callback handle
	ADI_DCB_CALLBACK_FN		DMCallback				// client callback function
) {

	// default return code
	u32 Result = ADI_DEV_RESULT_SUCCESS;
	ADI_AUDIOEZEXTENDER *pAUDIOEZEXTENDER;		// pointer to the Audio EZ-Extender device we're working on
	void *pExitCriticalArg;		// exit critical region parameter

	// Check for a valid device number 
#ifdef ADI_DEV_DEBUG
	if (DeviceNumber >= ADI_AUDIOEZEXTENDER_NUM_DEVICES) return (ADI_DEV_RESULT_BAD_DEVICE_NUMBER);
#endif

	// assign the pointer to the device instance
	pAUDIOEZEXTENDER = &Device[DeviceNumber];
	// and store the Manager handle
	pAUDIOEZEXTENDER->ManagerHandle = ManagerHandle;
	// and store the Device Manager handle
	pAUDIOEZEXTENDER->DMHandle = DMHandle;
	// and store the DMA Manager handle
	pAUDIOEZEXTENDER->DMAHandle = DMAHandle;
	// and store the DCallback Manager handle
	pAUDIOEZEXTENDER->DCBHandle = DCBHandle;
	// and callback function
	pAUDIOEZEXTENDER->DMCallback = DMCallback;

	// Check that this device instance is not already in use. If not,
	// assign flag to indicate that it is now.
	pExitCriticalArg = adi_int_EnterCriticalRegion(pEnterCriticalArg);
	if (pAUDIOEZEXTENDER->InUseFlag == FALSE) {
		pAUDIOEZEXTENDER->InUseFlag = TRUE;
		Result = ADI_DEV_RESULT_SUCCESS;
	}
    adi_int_ExitCriticalRegion(pExitCriticalArg);
#ifdef ADI_DEV_DEBUG
	if (Result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif

	// save the physical device handle in the client supplied location
	*pPDDHandle = (ADI_DEV_PDD_HANDLE *)pAUDIOEZEXTENDER;
	
    // open AD1938 CODEC A&B physical driver
    Result = adi_dev_Open(ManagerHandle,
                    &ADIAD1938EntryPoint,               // entry point for the instance API
                    0,                                  // device instance index (CODEC A&B)
                    pAUDIOEZEXTENDER,                   // client handle callback identifier
                    &pAUDIOEZEXTENDER->AD1938Handle,    // device handle for AD1938
                    ADI_DEV_DIRECTION_BIDIRECTIONAL,    // direction for AD1938A&B
                    DMAHandle,                          // DMA handle for SPORT
                    NULL,                               // Doesn't use deferred callback handle
                    AudioEZExtenderCallbackFunction);   // client's callback function
#ifdef ADI_DEV_DEBUG
    if (Result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif
#if (ADAV801_SUPPORT)
    // open ADAV801 CODEC physical driver
    Result = adi_dev_Open(ManagerHandle,
                    &ADIADAV801EntryPoint,              // entry point for the instance API
                    0,                                  // device instance index
                    pAUDIOEZEXTENDER,                   // client handle callback identifier
                    &pAUDIOEZEXTENDER->ADAV801Handle,   // device handle for ADAV801
                    ADI_DEV_DIRECTION_BIDIRECTIONAL,    // direction for ADAV801
                    DMAHandle,                          // DMA handle for SPORT
                    NULL,                               // Doesn't use deferred callback handle
                    AudioEZExtenderCallbackFunction);   // client's callback function
#ifdef ADI_DEV_DEBUG
    if (result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif
#endif

    // Open dependent devices SPI
    Result = adi_dev_Control(pAUDIOEZEXTENDER->AD1938Handle, ADI_AD1938_CMD_OPEN_SPI, (void*)0);
#ifdef ADI_DEV_DEBUG
    if (Result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif
    
    // Open dependent device SPORT1 for AD1938 codec.
    Result = adi_dev_Control(pAUDIOEZEXTENDER->AD1938Handle, 
                ADI_AD1938_CMD_OPEN_SPORT, 
                (void*)(pAUDIOEZEXTENDER->SportSelect == 0 ? 1 : 0));  // fixed
#ifdef ADI_DEV_DEBUG
    if (Result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif

#if (ADAV801_SUPPORT)
    // Open dependent device SPORT0 for ADAV801 codec.
    Result = adi_dev_Control(pAUDIOEZEXTENDER->ADAV801Handle, ADI_ADAV801_CMD_OPEN_SPORT, (void*)0);  // fixed
#ifdef ADI_DEV_DEBUG
    if (result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif
#endif

	// return after successful completion
	return(Result);
}


/*********************************************************************
*
*	Function:		adi_pdd_Close
*
*	Description:	Closes the associated devices
*
*********************************************************************/
static u32 adi_pdd_Close(		// Closes a device
	ADI_DEV_PDD_HANDLE PDDHandle	// PDD handle
) {
	u32 Result;		// return value
	ADI_AUDIOEZEXTENDER *pAUDIOEZEXTENDER = (ADI_AUDIOEZEXTENDER *)PDDHandle;

	// check for errors if required
#if defined(ADI_DEV_DEBUG)
//	if ((Result = ValidatePDDHandle(PDDHandle)) != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif

	// close AD1938 driver
	Result = adi_dev_Close(pAUDIOEZEXTENDER->AD1938Handle);
#ifdef ADI_DEV_DEBUG
	if (Result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif

#if (ADAV801_SUPPORT)
	// close ADAV801 driver
	Result = adi_dev_Close(pAUDIOEZEXTENDER->ADAV801Handle);
#ifdef ADI_DEV_DEBUG
	if (Result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif
#endif
	// mark the device as closed
	pAUDIOEZEXTENDER->InUseFlag = FALSE;

	return(Result);
}


/*********************************************************************
*
*	Function:		adi_pdd_Read
*
*	Description:	Never called as SPI uses DMA
*
*********************************************************************/


static u32 adi_pdd_Read(		// Reads data or queues an inbound buffer to a device
	ADI_DEV_PDD_HANDLE 	PDDHandle,	// PDD handle
	ADI_DEV_BUFFER_TYPE	BufferType,	// buffer type
	ADI_DEV_BUFFER 		*pBuffer	// pointer to buffer
){
	// check for errors if required
	u32 Result = ADI_DEV_RESULT_SUCCESS;
#if defined(ADI_DEV_DEBUG)
//	if ((Result = ValidatePDDHandle(PDDHandle)) != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif

    // Simply pass the request on
	ADI_AUDIOEZEXTENDER *pAUDIOEZEXTENDER = (ADI_AUDIOEZEXTENDER *)PDDHandle;
	
    if (pAUDIOEZEXTENDER->SelectedDevice == ADI_AD1938)
    {
        Result = adi_dev_Read(pAUDIOEZEXTENDER->AD1938Handle, BufferType, pBuffer);
    }
#if (ADAV801_SUPPORT)
    else
    {
        Result = adi_dev_Read(pAUDIOEZEXTENDER->ADAV801Handle, BufferType, pBuffer);
    }
#endif
#ifdef ADI_DEV_DEBUG
	if (Result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif

	return(Result);
}

/*********************************************************************
*
*	Function:		adi_pdd_Write
*
*	Description:	Never called as SPI uses DMA
*
*********************************************************************/


static u32 adi_pdd_Write(		// Writes data or queues an outbound buffer to a device
	ADI_DEV_PDD_HANDLE 	PDDHandle,	// PDD handle
	ADI_DEV_BUFFER_TYPE	BufferType,	// buffer type
	ADI_DEV_BUFFER 		*pBuffer	// pointer to buffer
){
	// check for errors if required
	u32 Result = ADI_DEV_RESULT_SUCCESS;
#if defined(ADI_DEV_DEBUG)
//	if ((Result = ValidatePDDHandle(PDDHandle)) != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif

	// Simply pass the request on
	ADI_AUDIOEZEXTENDER *pAUDIOEZEXTENDER = (ADI_AUDIOEZEXTENDER *)PDDHandle;

    if (pAUDIOEZEXTENDER->SelectedDevice == ADI_AD1938)
    {
        Result = adi_dev_Write(pAUDIOEZEXTENDER->AD1938Handle, BufferType, pBuffer);
    }
#if (ADAV801_SUPPORT)
    else
    {
        Result = adi_dev_Write(pAUDIOEZEXTENDER->ADAV801Handle, BufferType, pBuffer);
    }
#endif
#ifdef ADI_DEV_DEBUG
	if (Result != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif

	return(Result);
}


/*********************************************************************
*
*	Function:		adi_pdd_Control
*
*	Description:	Configures device
*
*********************************************************************/

static u32 adi_pdd_Control(		// Sets or senses a device specific parameter
	ADI_DEV_PDD_HANDLE 	PDDHandle,	// PDD handle
	u32 				Command,	// command ID
	void 				*Value		// command specific value
) {

	ADI_AUDIOEZEXTENDER     *pAUDIOEZEXTENDER;	// pointer to the device we're working on

	u32 			Result;		// return value
	u32				u32Value;	// u32 type to avoid casts/warnings etc.
	u16				u16Value;	// u16 type to avoid casts/warnings etc.
	u8				u8Value;	// u8 type to avoid casts/warnings etc.
    u8              *pu8Value; // pointer for get set 8 bit data
	// avoid casts
	pAUDIOEZEXTENDER = (ADI_AUDIOEZEXTENDER *)PDDHandle; // Pointer to Audio EZ-Extender device driver instance
    // assign 16 and 32 bit values for the Value argument
	u32Value = (u32)Value;
    	u16Value = ((u16)((u32)Value));
    	u8Value = ((u8)(u16Value));
		pu8Value = &u8Value;	
	
	// assume we're going to be successful
	Result = ADI_DEV_RESULT_SUCCESS;

	switch (Command)
	{
        // CASE (query for DMA support)		
        case (ADI_DEV_CMD_GET_PERIPHERAL_DMA_SUPPORT):
            // no, we do not support it at this level (it is delegated down to SPORT driver)
            *((u32 *)Value) = FALSE;
            break;
        
        case (ADI_AUDIOEZEXTENDER_CMD_SET_OPERATION_MODE):
        {
            // upper 16bit of 32bit value is analog mode index, lower 16bit is digital mode index
            pAUDIOEZEXTENDER->AnalogMode = (u32Value >> 16);
            pAUDIOEZEXTENDER->DigitalMode = (u32Value & 0x0FFFF);
            setAudioMode(pAUDIOEZEXTENDER);
            break;
        }
        
        case (ADI_AUDIOEZEXTENDER_CMD_SET_ANALOG_OPERATION_MODE):
        {
            // change analog mode only
            pAUDIOEZEXTENDER->AnalogMode = u32Value;
            setAudioMode(pAUDIOEZEXTENDER);
            break;
        }
        
        case (ADI_AUDIOEZEXTENDER_CMD_SET_DIGITAL_OPERATION_MODE):
        {
            // change digital mode only
            pAUDIOEZEXTENDER->DigitalMode = u32Value;
            setAudioMode(pAUDIOEZEXTENDER);
            break;
        }
        
        case (ADI_AUDIOEZEXTENDER_CMD_DEVICE_SELECT):
#if defined(ADI_DEV_DEBUG)
            // validate the device number
            if ((u32Value < 0) || (u32Value > 1)) return(ADI_AUDIOEZEXTENDER_RESULT_BAD_DEVICE_NUMBER);
#endif
            // select target device for read/write function
            pAUDIOEZEXTENDER->SelectedDevice = (AUDIOEZEXTENDER_CODEC_SELECTION)u32Value;
            break;
        
        default:
            // pass anything we don't specifically handle to the dependent drivers
            Result = adi_dev_Control(pAUDIOEZEXTENDER->AD1938Handle, Command, Value);
#if (ADAV801_SUPPORT)
            Result = adi_dev_Control(pAUDIOEZEXTENDER->ADAV801Handle, Command, Value);
#endif
            break;
	}

	return(Result);
}

/*********************************************************************

	Function:		AudioEZExtenderCallbackFunction

	Description:	invokes the callback function from the SPORT Driver

*********************************************************************/

static void AudioEZExtenderCallbackFunction(void* DeviceHandle, u32 Event, void* pArg)
{
	ADI_AUDIOEZEXTENDER *pAUDIOEZEXTENDER = (ADI_AUDIOEZEXTENDER *)DeviceHandle;
#if defined(ADI_DEV_DEBUG)
//	if (ValidatePDDHandle(DeviceHandle) != ADI_DEV_RESULT_SUCCESS) {  	// verify the DM handle
//		return;
//	}
#endif
	// simply pass the callback along to the Device Manager Callback without interpretation
	(pAUDIOEZEXTENDER->DMCallback)(pAUDIOEZEXTENDER->DMHandle, Event, pArg);
}


/*********************************************************************

Entry point for device manager

*********************************************************************/

ADI_DEV_PDD_ENTRY_POINT ADIAudioEZExtenderEntryPoint = {
	adi_pdd_Open,
	adi_pdd_Close,
	adi_pdd_Read,
	adi_pdd_Write,
	adi_pdd_Control
};
