/* Copyright (c) 2016, Texas Instruments Incorporated - http://www.ti.com/ All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ // // I/O device configuration data structure definitions D10 (DA10x EVM). // ----------------------------------------------------------------------------- // This file contains the necessary configurations and functions for // using the DA10x Audio DC card in the PA environment. In particular, the // SAP configurations are referenced in the pa(i/y)-evmda10x-io.c files // for use in IOS (Input/Output Switching) shortcuts. Each configuration // contains settings appropriate to the various devices on the DA10x-AudioDC; // the DIR, DACs, ADCs, and DIT output. Also each configuration points to // a common control function (D10_sapControl), which handles the various // requests made by the PA framework. // A note about clocking. There are two different master clocks // available corresponding to the two primary input choices, DIR and ADC. // // DIR: // . 512fs @ <= 48kHz // . 256fs @ > 48kHz & <=96 kHz // . 128fs @ > 96kHz // ADC: // . 768fs @ 32kHz // . 512fs @ 48kHz // . 256fs @ 96kHz // // This faciliates the logic used for the McASP transmit sections TX0 (DAC) and // TX2 (DIT) which divide the master clock down to generate bit and frame clocks. // ----------------------------------------------------------------------------- // Includes #include #include // ----------------------------------------------------------------------------- // Local function declarations XDAS_Int32 D10_sapControl (DEV2_Handle device, const PAF_SIO_Params *pParams, XDAS_Int32 code, XDAS_Int32 arg); static inline XDAS_Int32 initD10 (DEV2_Handle device) ; static XDAS_Int32 clockMuxTx (int sel, int force); static int manageInput (DEV2_Handle device, const SAP_D10_Rx_Params *pParams, PAF_SIO_InputStatus *pStatusOut); static int manageOutput (DEV2_Handle device, const SAP_D10_Tx_Params *pParams, float rateX); void HSR4_readStatus (PAF_SIO_InputStatus *pStatus); unsigned int HDMIGpioGetState (void); // ----------------------------------------------------------------------------- // State machine variables and defines // flag to facilitate one time initialization of DA10x Audio hardware // 0 ==> not initialized, 1 ==> initialized static char initDone = 0; // input status static PAF_SIO_InputStatus primaryStatus = { 0, // lock PAF_IEC_AUDIOMODE_UNKNOWN, // nonaudio PAF_IEC_PREEMPHASIS_UNKNOWN, // emphasis PAF_SAMPLERATE_UNKNOWN, // sampleRateMeasured PAF_SAMPLERATE_UNKNOWN, // sampleRateData 0,0,0, // unused }; // The McASP outputs (both for DAC and DIT) receive a high speed clock // and in turn generate a bit and frame clock. The needed clock divider // values are kept here for easy lookup. unsigned char *pClkxDiv = NULL; static const unsigned char clkxDivDIR[PAF_SAMPLERATE_N] = { 0x2, //PAF_SAMPLERATE_UNKNOWN 0x8, //PAF_SAMPLERATE_NONE 0x8, //PAF_SAMPLERATE_32000HZ 0x2, //PAF_SAMPLERATE_44100HZ 0x2, //PAF_SAMPLERATE_48000HZ 0x4, //PAF_SAMPLERATE_88200HZ 0x2, //PAF_SAMPLERATE_96000HZ 0x2, //PAF_SAMPLERATE_192000HZ 0x4, //PAF_SAMPLERATE_64000HZ 0x2, //PAF_SAMPLERATE_128000HZ 0x2, //PAF_SAMPLERATE_176400HZ 0x8, //PAF_SAMPLERATE_8000HZ 0x8, //PAF_SAMPLERATE_11025HZ 0x8, //PAF_SAMPLERATE_12000HZ 0x8, //PAF_SAMPLERATE_16000HZ 0x8, //PAF_SAMPLERATE_22050HZ 0x8, //PAF_SAMPLERATE_24000HZ }; static const unsigned char clkxDivADC[PAF_SAMPLERATE_N] = { 0x8, //PAF_SAMPLERATE_UNKNOWN 0x8, //PAF_SAMPLERATE_NONE 0xC, //PAF_SAMPLERATE_32000HZ 0x8, //PAF_SAMPLERATE_44100HZ 0x8, //PAF_SAMPLERATE_48000HZ 0x4, //PAF_SAMPLERATE_88200HZ 0x4, //PAF_SAMPLERATE_96000HZ 0x2, //PAF_SAMPLERATE_192000HZ 0x4, //PAF_SAMPLERATE_64000HZ 0x2, //PAF_SAMPLERATE_128000HZ 0x2, //PAF_SAMPLERATE_176400HZ 0x8, //PAF_SAMPLERATE_8000HZ 0x8, //PAF_SAMPLERATE_11025HZ 0x8, //PAF_SAMPLERATE_12000HZ 0x8, //PAF_SAMPLERATE_16000HZ 0x8, //PAF_SAMPLERATE_22050HZ 0x8, //PAF_SAMPLERATE_24000HZ }; static const unsigned char clkxDivHDMI[PAF_SAMPLERATE_N] = { 0x8, //PAF_SAMPLERATE_UNKNOWN 0x8, //PAF_SAMPLERATE_NONE 0x8, //PAF_SAMPLERATE_32000HZ 0x2, //PAF_SAMPLERATE_44100HZ 0x2, //PAF_SAMPLERATE_48000HZ 0x4, //PAF_SAMPLERATE_88200HZ 0x4, //PAF_SAMPLERATE_96000HZ 0x2, //PAF_SAMPLERATE_192000HZ 0x4, //PAF_SAMPLERATE_64000HZ 0x2, //PAF_SAMPLERATE_128000HZ 0x2, //PAF_SAMPLERATE_176400HZ 0x8, //PAF_SAMPLERATE_8000HZ 0x8, //PAF_SAMPLERATE_11025HZ 0x8, //PAF_SAMPLERATE_12000HZ 0x8, //PAF_SAMPLERATE_16000HZ 0x8, //PAF_SAMPLERATE_22050HZ 0x8, //PAF_SAMPLERATE_24000HZ }; // The ADCs, when operating as the master input, can only // generate a limited set of audio sample rates since the clock // is derived from AUXCLK which is the oscillator connected to the DSP. // This table faciliates the access and definition of these rates. static const Uint16 oscRateTable[8] = { PAF_SAMPLERATE_UNKNOWN, // 0 PAF_SAMPLERATE_32000HZ, PAF_SAMPLERATE_44100HZ, // D10_RATE_44_1KHZ PAF_SAMPLERATE_48000HZ, PAF_SAMPLERATE_88200HZ, // D10_RATE_88_2KHZ PAF_SAMPLERATE_96000HZ, PAF_SAMPLERATE_176400HZ, // D10_RATE_176_4KHZ PAF_SAMPLERATE_192000HZ }; static const Uint16 RateTable_hdmi[8] = { PAF_SAMPLERATE_UNKNOWN, // HSDIO_AudioFreq_RESERVED PAF_SAMPLERATE_32000HZ, // HSDIO_AudioFreq_32K PAF_SAMPLERATE_44100HZ, // HSDIO_AudioFreq_44_1K PAF_SAMPLERATE_48000HZ, // HSDIO_AudioFreq_48K PAF_SAMPLERATE_88200HZ, // HSDIO_AudioFreq_88_2K PAF_SAMPLERATE_96000HZ, // HSDIO_AudioFreq_96_4K PAF_SAMPLERATE_176400HZ, // HSDIO_AudioFreq_176_4K PAF_SAMPLERATE_192000HZ // HSDIO_AudioFreq_192K }; static const Uint16 RateTable_spdif[4] = { PAF_SAMPLERATE_44100HZ, // AudioFreq_44_1K PAF_SAMPLERATE_48000HZ, // AudioFreq_48K PAF_SAMPLERATE_UNKNOWN, // AudioFreq_RESERVED PAF_SAMPLERATE_32000HZ, // HSDIO_AudioFreq_32K }; // base mcasp addresses for easy lookup static volatile Uint32 * mcaspAddr[_MCASP_PORT_CNT] = { (volatile Uint32 *) _MCASP_BASE_PORT0, (volatile Uint32 *) _MCASP_BASE_PORT1, (volatile Uint32 *) _MCASP_BASE_PORT2 }; // The DA10x HW is configured for the DAC's mute lines to be operated based // on McASP0's AMUTE (out) line. This is the hard mute. static inline void dacHardMute (void) { volatile Uint32 *mcasp0 = (volatile Uint32 *) _MCASP_BASE_PORT0; mcasp0[_MCASP_PDOUT_OFFSET] |= _MCASP_PDOUT_AMUTE_MASK; } static inline void dacHardUnMute (void) { volatile Uint32 *mcasp0 = (volatile Uint32 *) _MCASP_BASE_PORT0; mcasp0[_MCASP_PDOUT_OFFSET] &= ~_MCASP_PDOUT_AMUTE_MASK; mcasp0[_MCASP_AMUTE_OFFSET] |= MCASP_AMUTE_MUTEN_ERRLOW; } // How should the PCM18x DAC's soft mute functionality be used here? // i.e, as different from the hard mute? need to review. static inline void dacSoftMute (void) { volatile Uint32 *mcasp0 = (volatile Uint32 *) _MCASP_BASE_PORT0; mcasp0[6] = 0x000 ; mcasp0[6] = 0x400 ; } static inline void dacSoftUnMute (void) { volatile Uint32 *mcasp0 = (volatile Uint32 *) _MCASP_BASE_PORT0; mcasp0[6] = 0x000 ; mcasp0[6] = 0x400 ; } // ----------------------------------------------------------------------------- // McASP Input Configuration Definitions static const MCASP_ConfigRcv rxConfigDIR = { MCASP_RMASK_OF(0xFFFFFFFF), MCASP_RFMT_RMK( MCASP_RFMT_RDATDLY_1BIT, MCASP_RFMT_RRVRS_MSBFIRST, MCASP_RFMT_RPAD_RPBIT, MCASP_RFMT_RPBIT_OF(0), MCASP_RFMT_RSSZ_32BITS, MCASP_RFMT_RBUSEL_DAT, MCASP_RFMT_RROT_NONE), MCASP_AFSRCTL_RMK( MCASP_AFSRCTL_RMOD_OF(2), MCASP_AFSRCTL_FRWID_WORD, MCASP_AFSRCTL_FSRM_EXTERNAL, MCASP_AFSRCTL_FSRP_ACTIVELOW), MCASP_ACLKRCTL_RMK( MCASP_ACLKRCTL_CLKRP_RISING, MCASP_ACLKRCTL_CLKRM_EXTERNAL, MCASP_ACLKRCTL_CLKRDIV_DEFAULT), MCASP_AHCLKRCTL_RMK( MCASP_AHCLKRCTL_HCLKRM_EXTERNAL, MCASP_AHCLKRCTL_HCLKRP_RISING, MCASP_AHCLKRCTL_HCLKRDIV_DEFAULT), MCASP_RTDM_OF(3), MCASP_RINTCTL_DEFAULT, MCASP_RCLKCHK_DEFAULT }; static const MCASP_ConfigRcv rxConfigADC = { MCASP_RMASK_OF(0xFFFFFFFF), MCASP_RFMT_RMK( MCASP_RFMT_RDATDLY_1BIT, MCASP_RFMT_RRVRS_MSBFIRST, MCASP_RFMT_RPAD_RPBIT, MCASP_RFMT_RPBIT_OF(0), MCASP_RFMT_RSSZ_32BITS, MCASP_RFMT_RBUSEL_DAT, MCASP_RFMT_RROT_NONE), MCASP_AFSRCTL_RMK( MCASP_AFSRCTL_RMOD_OF(2), MCASP_AFSRCTL_FRWID_WORD, MCASP_AFSRCTL_FSRM_INTERNAL, MCASP_AFSRCTL_FSRP_ACTIVEHIGH), MCASP_ACLKRCTL_RMK( MCASP_ACLKRCTL_CLKRP_RISING, MCASP_ACLKRCTL_CLKRM_INTERNAL, MCASP_ACLKXCTL_CLKXDIV_OF(7)), MCASP_AHCLKRCTL_RMK( MCASP_AHCLKRCTL_HCLKRM_INTERNAL, MCASP_AHCLKRCTL_HCLKRP_RISING, MCASP_AHCLKRCTL_HCLKRDIV_DEFAULT), MCASP_RTDM_OF(3), MCASP_RINTCTL_DEFAULT, MCASP_RCLKCHK_DEFAULT }; // ----------------------------------------------------------------------------- // McASP Output Configuration Definitions static const MCASP_ConfigXmt txConfigDAC = { MCASP_XMASK_OF(0xFFFFFFFF), MCASP_XFMT_RMK( MCASP_XFMT_XDATDLY_1BIT, MCASP_XFMT_XRVRS_MSBFIRST, MCASP_XFMT_XPAD_ZERO, MCASP_XFMT_XPBIT_DEFAULT, MCASP_XFMT_XSSZ_32BITS, MCASP_XFMT_XBUSEL_DAT, MCASP_XFMT_XROT_NONE), MCASP_AFSXCTL_RMK( MCASP_AFSXCTL_XMOD_OF(2), MCASP_AFSXCTL_FXWID_WORD, MCASP_AFSXCTL_FSXM_INTERNAL, MCASP_AFSXCTL_FSXP_ACTIVELOW), MCASP_ACLKXCTL_RMK( MCASP_ACLKXCTL_CLKXP_FALLING, MCASP_ACLKXCTL_ASYNC_ASYNC, MCASP_ACLKXCTL_CLKXM_INTERNAL, MCASP_ACLKXCTL_CLKXDIV_OF(1)), MCASP_AHCLKXCTL_RMK( MCASP_AHCLKXCTL_HCLKXM_EXTERNAL, MCASP_AHCLKXCTL_HCLKXP_FALLING, MCASP_AHCLKXCTL_HCLKXDIV_OF(0)), MCASP_XTDM_OF(3), MCASP_XINTCTL_DEFAULT, MCASP_XCLKCHK_DEFAULT }; static const MCASP_ConfigXmt txConfigDACSlave = { MCASP_XMASK_OF(0xFFFFFFFF), MCASP_XFMT_RMK( MCASP_XFMT_XDATDLY_1BIT, MCASP_XFMT_XRVRS_MSBFIRST, MCASP_XFMT_XPAD_ZERO, MCASP_XFMT_XPBIT_DEFAULT, MCASP_XFMT_XSSZ_32BITS, MCASP_XFMT_XBUSEL_DAT, MCASP_XFMT_XROT_NONE), MCASP_AFSXCTL_RMK( MCASP_AFSXCTL_XMOD_OF(2), MCASP_AFSXCTL_FXWID_WORD, MCASP_AFSXCTL_FSXM_INTERNAL, MCASP_AFSXCTL_FSXP_ACTIVELOW), MCASP_ACLKXCTL_RMK( MCASP_ACLKXCTL_CLKXP_FALLING, MCASP_ACLKXCTL_ASYNC_ASYNC, MCASP_ACLKXCTL_CLKXM_INTERNAL, MCASP_ACLKXCTL_CLKXDIV_OF(1)), MCASP_AHCLKXCTL_RMK( MCASP_AHCLKXCTL_HCLKXM_INTERNAL, MCASP_AHCLKXCTL_HCLKXP_FALLING, MCASP_AHCLKXCTL_HCLKXDIV_OF(0)), MCASP_XTDM_OF(3), MCASP_XINTCTL_DEFAULT, MCASP_XCLKCHK_DEFAULT }; static const MCASP_ConfigXmt txConfigDIT = { MCASP_XMASK_OF(0x00FFFFFF), MCASP_XFMT_RMK( MCASP_XFMT_XDATDLY_1BIT, MCASP_XFMT_XRVRS_LSBFIRST, MCASP_XFMT_XPAD_DEFAULT, MCASP_XFMT_XPBIT_DEFAULT, MCASP_XFMT_XSSZ_32BITS, MCASP_XFMT_XBUSEL_DAT, MCASP_XFMT_XROT_NONE), MCASP_AFSXCTL_RMK( MCASP_AFSXCTL_XMOD_OF(0x180), MCASP_AFSXCTL_FXWID_BIT, MCASP_AFSXCTL_FSXM_INTERNAL, MCASP_AFSXCTL_FSXP_ACTIVEHIGH), MCASP_ACLKXCTL_RMK( MCASP_ACLKXCTL_CLKXP_FALLING, MCASP_ACLKXCTL_ASYNC_ASYNC, MCASP_ACLKXCTL_CLKXM_INTERNAL, MCASP_ACLKXCTL_CLKXDIV_OF(0)), MCASP_AHCLKXCTL_RMK( MCASP_AHCLKXCTL_HCLKXM_EXTERNAL, MCASP_AHCLKXCTL_HCLKXP_FALLING, MCASP_AHCLKXCTL_HCLKXDIV_OF(0)), MCASP_XTDM_OF(0xFFFFFFFF), MCASP_XINTCTL_DEFAULT, MCASP_XCLKCHK_DEFAULT }; static const MCASP_ConfigXmt txConfigDIT_16bit = { MCASP_XMASK_OF(0x0000FFFF), MCASP_XFMT_RMK( MCASP_XFMT_XDATDLY_1BIT, MCASP_XFMT_XRVRS_LSBFIRST, MCASP_XFMT_XPAD_DEFAULT, MCASP_XFMT_XPBIT_DEFAULT, MCASP_XFMT_XSSZ_32BITS, MCASP_XFMT_XBUSEL_DAT, MCASP_XFMT_XROT_24BITS), MCASP_AFSXCTL_RMK( MCASP_AFSXCTL_XMOD_OF(0x180), MCASP_AFSXCTL_FXWID_BIT, MCASP_AFSXCTL_FSXM_INTERNAL, MCASP_AFSXCTL_FSXP_ACTIVEHIGH), MCASP_ACLKXCTL_RMK( MCASP_ACLKXCTL_CLKXP_FALLING, MCASP_ACLKXCTL_ASYNC_ASYNC, MCASP_ACLKXCTL_CLKXM_INTERNAL, MCASP_ACLKXCTL_CLKXDIV_OF(0)), MCASP_AHCLKXCTL_RMK( MCASP_AHCLKXCTL_HCLKXM_EXTERNAL, MCASP_AHCLKXCTL_HCLKXP_FALLING, MCASP_AHCLKXCTL_HCLKXDIV_OF(0)), MCASP_XTDM_OF(0xFFFFFFFF), MCASP_XINTCTL_DEFAULT, MCASP_XCLKCHK_DEFAULT }; // ----------------------------------------------------------------------------- // DAP Input Parameter Definitions const SAP_D10_Rx_Params SAP_D10_RX_DIR = { sizeof (SAP_D10_Rx_Params), // size "SAP", // name MCASP_DEV2, // moduleNum --> mcasp # (Void *)&rxConfigDIR, // pConfig 4, // wordSize (unused) 24, // precision (unused) D10_sapControl, // control 0x00000020, // pinMask (D10_MCLK_DIR << D10_MCLK_SHIFT), // mode 0,0 // unused[2] }; const SAP_D10_Rx_Params SAP_D10_RX_ADC_44100HZ = { sizeof (SAP_D10_Rx_Params), // size "SAP", // name MCASP_DEV1, // moduleNum --> mcasp # (Void *)&rxConfigADC, // pConfig 4, // wordSize (unused) 24, // precision (unused) D10_sapControl, // control 0xE000000F, // pinMask (D10_RATE_44_1KHZ << D10_RATE_SHIFT) | (D10_MCLK_OSC << D10_MCLK_SHIFT), // mode 0,0 // unused[2] }; const SAP_D10_Rx_Params SAP_D10_RX_ADC_6CH_44100HZ = { sizeof (SAP_D10_Rx_Params), // size "SAP", // name MCASP_DEV1, // moduleNum --> mcasp # (Void *)&rxConfigADC, // pConfig -1, // wordSize (unused) -1, // precision (unused) D10_sapControl, // control 0xE0000007, // pinMask (D10_RATE_44_1KHZ << D10_RATE_SHIFT) | (D10_MCLK_OSC << D10_MCLK_SHIFT), // mode 0,0 // unused[2] }; const SAP_D10_Rx_Params SAP_D10_RX_ADC_STEREO_44100HZ = { sizeof (SAP_D10_Rx_Params), // size "SAP", // name MCASP_DEV1, // moduleNum --> mcasp # (Void *)&rxConfigADC, // pConfig -1, // wordSize (unused) -1, // precision (unused) D10_sapControl, // control 0xE0000001, // pinMask (D10_RATE_44_1KHZ << D10_RATE_SHIFT) | (D10_MCLK_OSC << D10_MCLK_SHIFT), // mode 0,0 // unused[2] }; const SAP_D10_Rx_Params SAP_D10_RX_ADC_88200HZ = { sizeof (SAP_D10_Rx_Params), // size "SAP", // name MCASP_DEV1, // moduleNum --> mcasp # (Void *)&rxConfigADC, // pConfig -1, // wordSize (unused) -1, // precision (unused) D10_sapControl, // control 0xE000000F, // pinMask (D10_RATE_88_2KHZ << D10_RATE_SHIFT) | (D10_MCLK_OSC << D10_MCLK_SHIFT), // mode 0,0 // unused[2] }; const SAP_D10_Rx_Params SAP_D10_RX_ADC_6CH_88200HZ = { sizeof (SAP_D10_Rx_Params), // size "SAP", // name MCASP_DEV1, // moduleNum --> mcasp # (Void *)&rxConfigADC, // pConfig -1, // wordSize (unused) -1, // precision (unused) D10_sapControl, // control 0xE0000007, // pinMask (D10_RATE_88_2KHZ << D10_RATE_SHIFT) | (D10_MCLK_OSC << D10_MCLK_SHIFT), // mode 0,0 // unused[2] }; const SAP_D10_Rx_Params SAP_D10_RX_ADC_STEREO_88200HZ = { sizeof (SAP_D10_Rx_Params), // size "SAP", // name MCASP_DEV1, // moduleNum --> mcasp # (Void *)&rxConfigADC, // pConfig -1, // wordSize (unused) -1, // precision (unused) D10_sapControl, // control 0xE0000001, // pinMask (D10_RATE_88_2KHZ << D10_RATE_SHIFT) | (D10_MCLK_OSC << D10_MCLK_SHIFT), // mode 0,0 // unused[2] }; const SAP_D10_Rx_Params SAP_D10_RX_HDMI_STEREO = { sizeof (SAP_D10_Rx_Params), // size "SAP", // name MCASP_DEV0, // moduleNum --> mcasp # (Void *)&rxConfigDIR, // pConfig 4, // wordSize (unused) -1, // precision (unused) D10_sapControl, // control 0x00001000, // pinMask (D10_MODE_HDMI << D10_MODE_SHIFT) | (D10_MCLK_HDMI << D10_MCLK_SHIFT), // mode 0,0 // unused[2] }; const SAP_D10_Rx_Params SAP_D10_RX_HDMI = { sizeof (SAP_D10_Rx_Params), // size "SAP", // name MCASP_DEV0, // moduleNum --> mcasp # (Void *)&rxConfigDIR, // pConfig 4, // wordSize (unused) -1, // precision (unused) D10_sapControl, // control 0xE000F000, // pinMask (D10_MODE_HDMI << D10_MODE_SHIFT) | (D10_MCLK_HDMI << D10_MCLK_SHIFT), // mode 0,0 // unused[2] }; // ----------------------------------------------------------------------------- // SAP Output Parameter Definitions const SAP_D10_Tx_Params SAP_D10_TX_DAC = { sizeof (SAP_D10_Tx_Params), // size "SAP", // name MCASP_DEV0, // moduleNum --> mcasp # (Void *)&txConfigDAC, // pConfig 4, // wordSize (in bytes) 24, // precision (in bits) D10_sapControl, // control 0x1600000F, // pinMask 0, // mode 0,0,0 // unused[3] }; const SAP_D10_Tx_Params SAP_D10_TX_STEREO_DAC = { sizeof (SAP_D10_Tx_Params), // size "SAP", // name MCASP_DEV0, // moduleNum --> mcasp # (Void *)&txConfigDAC, // pConfig 4, // wordSize (in bytes) 24, // precision (in bits) D10_sapControl, // control 0x16000001, // pinMask 0, // mode 0,0,0 // unused[3] }; const SAP_D10_Tx_Params SAP_D10_TX_DIT = { sizeof (SAP_D10_Tx_Params), // size "SAP", // name MCASP_DEV2, // moduleNum --> mcasp # (Void *) &txConfigDIT, // pConfig 3, // wordSize (in bytes) 24, // precision (in bits) D10_sapControl, // control 0x1C000001, // pinMask 0, // mode 0,0,0 // unused[3] }; const SAP_D10_Tx_Params SAP_D10_TX_DAC_SLAVE = { sizeof (SAP_D10_Tx_Params), // size "SAP", // name MCASP_DEV0, // moduleNum --> mcasp # (Void *)&txConfigDACSlave, // pConfig 4, // wordSize (in bytes) 24, // precision (in bits) D10_sapControl, // control 0x1E00000F, // pinMask 0, // mode 0,0,0 // unused[3] }; const SAP_D10_Tx_Params SAP_D10_TX_STEREO_DAC_SLAVE = { sizeof (SAP_D10_Tx_Params), // size "SAP", // name MCASP_DEV0, // moduleNum --> mcasp # (Void *)&txConfigDAC, // pConfig 4, // wordSize (in bytes) 24, // precision (in bits) D10_sapControl, // control 0x16000001, // pinMask 0, // mode 0,0,0 // unused[3] }; const SAP_D10_Tx_Params SAP_D10_TX_DAC_12CH = { sizeof (SAP_D10_Tx_Params), // size "SAP", // name MCASP_DEV0, // moduleNum --> mcasp # (Void *)&txConfigDAC, // pConfig 4, // wordSize (in bytes) 24, // precision (in bits) D10_sapControl, // control 0x1600003F, // pinMask 0, // mode 0,0,0 // unused[3] }; const SAP_D10_Tx_Params SAP_D10_TX_DAC_16CH = { sizeof (SAP_D10_Tx_Params), // size "SAP", // name MCASP_DEV0, // moduleNum --> mcasp # (Void *)&txConfigDAC, // pConfig 4, // wordSize (in bytes) 24, // precision (in bits) D10_sapControl, // control 0x160000FF, // pinMask 0, // mode 0,0,0 // unused[3] }; // ----------------------------------------------------------------------------- // One time initialization of the DA10x audio hardware. /* DAC default configuration parameters */ DacConfig dacCfg = { DAC_AMUTE_CTRL_SCKI_LOST, /* Amute event */ 0, /* Amute control */ DAC_SAMPLING_MODE_SINGLE_RATE, /* Sampling mode */ DAC_DATA_FORMAT_I2S, /* Data format */ 0, /* Soft mute control */ DAC_ATTENUATION_WIDE_RANGE, /* Attenuation mode */ DAC_DEEMP_44KHZ, /* De-emph control */ 100 /* Volume */ }; /* ADC default configuration parameters */ AdcConfig adcCfg = { 90, /* ADC gain */ ADC_INL_SE_VINL1, /* Left input mux for ADC1L */ ADC_INL_SE_VINL2, /* Left input mux for ADC2L */ ADC_INR_SE_VINR1, /* Right input mux for ADC1R */ ADC_INR_SE_VINR2, /* Right input mux for ADC2R */ ADC_RX_WLEN_24BIT, /* ADC word length */ ADC_DATA_FORMAT_I2S, /* ADC data format */ 0 }; Platform_STATUS setAudioDacConfig(void) { Platform_STATUS status; /* Initialize Audio DAC module */ status = audioDacConfig(DAC_DEVICE_ALL, &dacCfg); if (status) Log_info0("SAP_D10: Audio DAC Configuration Failed!!!\n"); return status; } static inline XDAS_Int32 initD10 (DEV2_Handle device) { Platform_STATUS status = Platform_EOK; /* Initialize common audio configurations */ status = platformAudioInit(); if(status != Platform_EOK) { System_printf("Audio Init Failed!\n"); return status; } /* Initialize Audio ADC module */ status = audioAdcConfig(ADC_DEVICE_ALL, &adcCfg); if(status != Platform_EOK) { platform_write("Audio ADC Configuration Failed!\n"); return status; } /* Setup DIR 9001 for SPDIF input operation */ //status = platformAudioSelectClkSrc(AUDIO_CLK_SRC_DIR); status = audioDirConfig(); if(status != Platform_EOK) { Log_info0("Audio DIR Init Failed!\n"); return status; } #if 1 /* Setup HSR41 for HDMI input operation */ //status = platformAudioSelectClkSrc(AUDIO_CLK_SRC_I2S); /* Initialize the HDMI Card */ while(HDMIGpioGetState()); status = audioHDMIConfig(); if(status != Platform_EOK) { Log_info0("Audio HDMI Init Failed!\n"); return status; } #endif // This is needed because DAC configuration needs some default clocking. // We start with S/PDIF, because it's onboard the Audio DC & has its own crystal. // HDMI is an add-on board & Audio OSC would need AUX clocking - both unfit for "default". status = platformAudioSelectClkSrc(AUDIO_CLK_SRC_DIR); platform_delay(20000); // Without delay between these 2 calls system aborts. status = setAudioDacConfig(); return status; } //initD10 // ----------------------------------------------------------------------------- // The McASP TX section is *only* used as a master clock mux. // Mux functionality is achieved by selecting either external high // speed clocks (DIR/HDMI) or the internal AUXCLK (Audio_OSC). This is divided down // output via ACLKX0 which is connected to the high speed input // of TX0 (DAC) and TX2 (DIT). static XDAS_Int32 clockMuxTx (int sel, int force) { Platform_STATUS status = 0; // select clkxDiv table if (sel == D10_MCLK_DIR) { status = platformAudioSelectClkSrc(AUDIO_CLK_SRC_DIR); pClkxDiv = (unsigned char *) clkxDivDIR; } else if (sel == D10_MCLK_HDMI) { status = platformAudioSelectClkSrc(AUDIO_CLK_SRC_I2S); pClkxDiv = (unsigned char *) clkxDivHDMI; } else if (sel == D10_MCLK_OSC) { status = platformAudioSelectClkSrc(AUDIO_CLK_SRC_OSC); pClkxDiv = (unsigned char *) clkxDivADC; } platform_delay(20000); return status; } //clockMuxTx // ----------------------------------------------------------------------------- // This function returns the input status of the specified device. // This is called once when the device is opened // (PAF_SIO_CONTROL_OPEN) and periodically thereafter // (PAF_SIO_CONTROL_GET_INPUT_STATUS). static int manageInput (DEV2_Handle device, const SAP_D10_Rx_Params *pParams, PAF_SIO_InputStatus *pStatusOut) { PAF_SIO_InputStatus *pStatusIn = &primaryStatus; volatile Uint32 *mcasp0 = (volatile Uint32 *) _MCASP_BASE_PORT0; volatile Uint32 *mcasp1 = (volatile Uint32 *) _MCASP_BASE_PORT1; volatile Uint32 *mcasp2 = (volatile Uint32 *) _MCASP_BASE_PORT2; Platform_STATUS status; static int PrevSampRate = 0; int Rate_spdif=0; if ((((pParams->d10rx.mode & D10_MCLK_MASK) >> D10_MCLK_SHIFT) == D10_MCLK_DIR) & (((pParams->d10rx.mode & D10_MODE_MASK) >> D10_MODE_SHIFT) == D10_MODE_STD)) { pStatusIn->lock = !(platformAudioDirGetClkStatus()); pStatusIn->nonaudio = !(platformAudioDirGetAudioStatus()); pStatusIn->emphasis = platformAudioDirGetEmphStatus(); pStatusIn->sampleRateMeasured = RateTable_spdif[platformAudioDirGetFsOut()]; pStatusIn->sampleRateData = pStatusIn->sampleRateMeasured; PrevSampRate = pStatusIn->sampleRateMeasured; // GJ: Is this needed? Probably not. mcasp0[_MCASP_PDOUT_OFFSET] = 0x000 ; mcasp0[_MCASP_PDOUT_OFFSET] = 0x400 ; } else if ((((pParams->d10rx.mode & D10_MCLK_MASK) >> D10_MCLK_SHIFT) == D10_MCLK_OSC) & (((pParams->d10rx.mode & D10_MODE_MASK) >> D10_MODE_SHIFT) == D10_MODE_STD)) { int adcRate = (pParams->d10rx.mode & D10_RATE_MASK) >> D10_RATE_SHIFT; int regData; pStatusIn->lock = 1; pStatusIn->nonaudio = PAF_IEC_AUDIOMODE_AUDIO; pStatusIn->emphasis = PAF_IEC_PREEMPHASIS_NO; pStatusIn->sampleRateMeasured = oscRateTable[adcRate]; pStatusIn->sampleRateData = pStatusIn->sampleRateMeasured; } else if ((((pParams->d10rx.mode & D10_MCLK_MASK) >> D10_MCLK_SHIFT) == D10_MCLK_HDMI) & (((pParams->d10rx.mode & D10_MODE_MASK) >> D10_MODE_SHIFT) == D10_MODE_HDMI)) { pStatusIn->lock = 1; pStatusIn->nonaudio = PAF_IEC_AUDIOMODE_AUDIO; pStatusIn->emphasis = PAF_IEC_PREEMPHASIS_NO; if(!HDMIGpioGetState()) { HSR4_readStatus (pStatusIn); pStatusIn->sampleRateData = pStatusIn->sampleRateMeasured; PrevSampRate = pStatusIn->sampleRateMeasured; } else { pStatusIn->sampleRateMeasured = PrevSampRate; pStatusIn->sampleRateData = pStatusIn->sampleRateMeasured; } } else return -1; // update another status if requested if (pStatusOut) *pStatusOut = *pStatusIn; return 0; } //manageInput // ----------------------------------------------------------------------------- // This function configures the McASP TX clock dividers based on the // master clock rate. This is called once when the device is opened // (PAF_SIO_CONTROL_OPEN) and periodically thereafter (PAF_SIO_CONTROL_SET_RATEX). static int manageOutput (DEV2_Handle device, const SAP_D10_Tx_Params *pParams, float rateX) { volatile Uint32 *mcasp = mcaspAddr[pParams->sio.moduleNum]; PAF_SIO_InputStatus *pStatusIn = &primaryStatus; Uint32 divider; if (!pClkxDiv) return 1; // set clock divider if (rateX < .354) rateX = 0.25; else if (rateX < .707) rateX = 0.50; else if (rateX < 1.6) rateX = 1.00; else if (rateX < 2.828) rateX = 2.00; else rateX = 4.00; // if asynchronous then force clock change (assumes osc master) if (pParams->d10tx.mode & D10_SYNC_MASK) { int dacRate = (pParams->d10tx.mode & D10_RATE_MASK) >> D10_RATE_SHIFT; divider = pClkxDiv[oscRateTable[dacRate]]; } else divider = pClkxDiv[pStatusIn->sampleRateMeasured]; divider /= rateX; Log_info2("SAP_D10: Inside manageOutput with divider = %d, rateX = %d", divider, rateX); // DIT requires 2x clock if ((mcasp[_MCASP_AFSXCTL_OFFSET] & _MCASP_AFSXCTL_XMOD_MASK) == (MCASP_AFSXCTL_XMOD_OF(0x180) << _MCASP_AFSXCTL_XMOD_SHIFT)) { if (divider < 2) return (SIO2_EINVAL); divider >>= 1; } mcasp[_MCASP_ACLKXCTL_OFFSET] = (mcasp[_MCASP_ACLKXCTL_OFFSET] & ~_MCASP_ACLKXCTL_CLKXDIV_MASK) | (MCASP_ACLKXCTL_CLKXDIV_OF(divider-1) << _MCASP_ACLKXCTL_CLKXDIV_SHIFT); return 0; } //manageOutput // ----------------------------------------------------------------------------- // This function is called by the peripheral driver (DAP) in response to // various SIO_ctrl() calls made by the framework. XDAS_Int32 D10_sapControl (DEV2_Handle device, const PAF_SIO_Params *pParams, XDAS_Int32 code, XDAS_Int32 arg) { const SAP_D10_Rx_Params *pDapD10RxParams = (const SAP_D10_Rx_Params *)pParams; const SAP_D10_Tx_Params *pDapD10TxParams = (const SAP_D10_Tx_Params *)pParams; Platform_STATUS status; volatile Uint32 *mcasp = mcaspAddr[pParams->sio.moduleNum]; XDAS_Int32 result = 0; // perform one time hardware initialization if (!initDone) { result = initD10 (device); if (result) return result; initDone = 1; } switch (code) { // ............................................................................. // This case provides a regular entry point for managing the specified // input device. Nominally, this is used to provide lock and sample rate // status to the framework. case PAF_SIO_CONTROL_GET_INPUT_STATUS: if (device->mode != DEV2_INPUT) return SIO2_EINVAL; manageInput (device, pDapD10RxParams, (PAF_SIO_InputStatus *) arg); break; // ............................................................................. // This case provides a regular entry point for managing the specified // output device. Nominally this is used to change the output clock dividers // in the case of double rate output (e.g. DTS 96/24). case PAF_SIO_CONTROL_SET_RATEX: // Support only output rate control, for now if (device->mode != DEV2_OUTPUT) return (SIO2_EINVAL); // configure clock divider (bit and frame clocks) manageOutput (device, pDapD10TxParams, *((float *) arg)); break; // ............................................................................. // This case is called once when the device is opened/allocated by the framework. // Here, for both input and output, this allows for configuring all needed // clocks for proper operation. case PAF_SIO_CONTROL_OPEN: if (device->mode == DEV2_INPUT) { // determine the master clock based on the mode element of the // parameter configuration. int sel = (pDapD10RxParams->d10rx.mode & D10_MCLK_MASK) >> D10_MCLK_SHIFT; manageInput (device, pDapD10RxParams, NULL); // select appropriate master clock (but dont force) clockMuxTx (sel, -1); } else { // Since DAC is a slave to the chosen input, operate the clksel switch appropriately // Also, this is a create-time (i.e, CTRL_OPEN) only call & not appropriate under // the periodic manage_(in/out)put calls int sel = (pDapD10RxParams->d10rx.mode & D10_MCLK_MASK) >> D10_MCLK_SHIFT; clockMuxTx (sel, -1); platform_delay(20000); // Without delay between Tx McASP & DAC configs, system aborts. setAudioDacConfig(); dacHardUnMute (); // configure clock divider (bit and frame clocks) manageOutput (device, pDapD10TxParams, 1.0); } break; // ............................................................................. // This case is called once when the device is closed/freed by the framework. case PAF_SIO_CONTROL_CLOSE: // If TX0 then signal it is no longer in use by the DACs and // configure manually to generate ADC clocks. Also hard mute // the DACs since they are not in use. if ((device->mode == DEV2_OUTPUT) && (pParams->sio.moduleNum == MCASP_DEV0)) { dacHardMute (); // if async then clear forced clock mux // if asynchronous then force clock change if (pDapD10TxParams->d10tx.mode & D10_SYNC_MASK) clockMuxTx (0, 0); } break; // ............................................................................. // These cases are called as appropriate by the framework when there is // valid output data (UNMUTE) or no valid output (MUTE). case PAF_SIO_CONTROL_MUTE: if ((device->mode == DEV2_OUTPUT) && (pParams->sio.moduleNum == MCASP_DEV0)) dacSoftMute (); break; case PAF_SIO_CONTROL_UNMUTE: if ((device->mode == DEV2_OUTPUT) && (pParams->sio.moduleNum == MCASP_DEV0)) dacSoftUnMute (); break; // ............................................................................. // This case is called when the device is idled. // There is no specific handling -- but needed to avoid error return. case PAF_SIO_CONTROL_IDLE: break; // ............................................................................. // Called from the IDL Loop to allow for clock management and the like // The call is protected by a TSK_disable and HWI_disable so it is safe // to read/write shared resources. case PAF_SIO_CONTROL_WATCHDOG: // call manageInput in case the sample rate has changed resulting // in no output clocks which may have blocked the audio processing // thread. This call will reconfigure the AK4588 and restart the clocks. if (device->mode == DEV2_INPUT) manageInput (device, pDapD10RxParams, (PAF_SIO_InputStatus *) arg); break; // ............................................................................. // Called from DOB_issue to allow for different values of the channel status // fields of the SPDIF output. case PAF_SIO_CONTROL_SET_DITSTATUS: // No action necessary. break; case PAF_SIO_CONTROL_SET_WORDSIZE: if(((pDapD10RxParams->d10rx.mode & D10_MCLK_MASK) >> D10_MCLK_SHIFT) != D10_MCLK_OSC) { if ((device->mode == DEV2_INPUT) && (arg == 2)) { Log_info0("Inside SAP_D10Control PAF_SIO_CONTROL_SET_WORDSIZE for arg=2"); mcasp[_MCASP_RFMT_OFFSET] = (mcasp[_MCASP_RFMT_OFFSET] & ~_MCASP_RFMT_RROT_MASK) | MCASP_RFMT_RROT_16BITS; } else if ((device->mode == DEV2_INPUT) && (arg == 4)) { Log_info0("Inside SAP_D10Control PAF_SIO_CONTROL_SET_WORDSIZE for arg=4"); mcasp[_MCASP_RFMT_OFFSET] = (mcasp[_MCASP_RFMT_OFFSET] & ~_MCASP_RFMT_RROT_MASK) | MCASP_RFMT_RROT_NONE; } } break; // ............................................................................. // Any other cases are not handled and return an error. default: return SIO2_EINVAL; } return result; } //D10_sapControl // ----------------------------------------------------------------------------- extern unsigned int read_hdmi_samprate(); int RateHdmi=0; void HSR4_readStatus (PAF_SIO_InputStatus *pStatus) { //if(!RateHdmi) RateHdmi=read_hdmi_samprate(); pStatus->sampleRateMeasured = RateTable_hdmi[RateHdmi]; } unsigned int HDMIGpioGetState (void) { return(gpioReadInput(GPIO_PORT_0, PLATFORM_AUDIO_HSR_HMINTz_GPIO)); } // EOF