//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Poll the status registers to keep the register cache somewhat coherent // for the user client to access status data properly. Polling avoids // accessing any interrupt register that is processed in the 'notifyHardwareEvent' // method to avoid potential corruption of the interrupt status. void AppleTopazPluginCS8420::poll ( void ) { for ( UInt32 registerAddress = map_CS8420_MISC_CNTRL_1; registerAddress <= map_CS8420_BUFFER_23; registerAddress++ ) { if ( ( 0x31 != registerAddress ) && ( map_CS8420_RX_ERROR != registerAddress ) ) { CODEC_ReadRegister ( registerAddress, &mShadowRegs[registerAddress], 1 ); if ( map_CS8420_SERIAL_OUTPUT_FMT >= registerAddress ) { // [3686032] initialize so log will show register dump a while longer debugIOLog ( 5, " AppleTopazPluginCS8420::poll register 0x%2.2X : 0x%2.2X", registerAddress, mShadowRegs[registerAddress] ); } } } CODEC_ReadRegister ( map_ID_VERSION, &mShadowRegs[map_ID_VERSION], 1 ); }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IOReturn AppleTopazPluginCS8420::makeClockSelectPreLock ( UInt32 clockSource ) { IOReturn result; UInt8 data; debugIOLog (5, "+ AppleTopazPluginCS8420::makeClockSelect ( %d )", (unsigned int)clockSource ); // Clear any pending error interrupt status and re-enable error interrupts after completing clock source selection result = CODEC_ReadRegister ( map_CS8420_RX_ERROR, &data, 1 ); FailIf ( kIOReturnSuccess != result, Exit ); // Enable error (i.e. RERR) interrupts ONLY IF C28420 IS CLOCK MASTER if ( kTRANSPORT_SLAVE_CLOCK == clockSource ) { result = CODEC_WriteRegister ( map_CS8420_RX_ERROR_MASK, kCS8420_RX_ERROR_MASK_ENABLE_RERR ); FailIf ( kIOReturnSuccess != result, Exit ); } switch ( clockSource ) { case kTRANSPORT_MASTER_CLOCK: data = mShadowRegs[map_CS8420_DATA_FLOW_CTRL]; data &= ~( bvCS8420_spdMASK << baCS8420_SPD ); data |= ( bvCS8420_spdSrcOut << baCS8420_SPD ); result = CODEC_WriteRegister ( map_CS8420_DATA_FLOW_CTRL, data ); data = mShadowRegs[map_CS8420_CLOCK_SOURCE_CTRL]; data &= ~( 1 << baCS8420_OUTC ); data |= ( bvCS8420_outcOmckXbaCLK << baCS8420_OUTC ); result = CODEC_WriteRegister ( map_CS8420_CLOCK_SOURCE_CTRL, data ); break; case kTRANSPORT_SLAVE_CLOCK: data = mShadowRegs[map_CS8420_DATA_FLOW_CTRL]; data &= ~( bvCS8420_spdMASK << baCS8420_SPD ); data |= ( bvCS8420_spdAES3 << baCS8420_SPD ); result = CODEC_WriteRegister ( map_CS8420_DATA_FLOW_CTRL, data ); data = mShadowRegs[map_CS8420_CLOCK_SOURCE_CTRL]; data &= ~( 1 << baCS8420_OUTC ); data |= ( bvCS8420_outcRecIC << baCS8420_OUTC ); result = CODEC_WriteRegister ( map_CS8420_CLOCK_SOURCE_CTRL, data ); break; } // restart the codec after switching clocks data = mShadowRegs[map_CS8420_CLOCK_SOURCE_CTRL]; data &= ~( 1 << baCS8420_RUN ); data |= ( bvCS8420_runNORMAL << baCS8420_RUN ); result = CODEC_WriteRegister ( map_CS8420_CLOCK_SOURCE_CTRL, data ); setChannelStatus ( &mChanStatusStruct ); // [3669626] Flush channel status buffer Exit: debugIOLog (5, "- AppleTopazPluginCS8420::makeClockSelect ( %d ) returns %d", (unsigned int)clockSource, (unsigned int)result ); return result; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // This method is invoked from the 'codecErrorInterruptHandler' residing in the // platform interface object. The 'codecErrorInterruptHandler' may be invoked // through GPIO hardware interrupt dispatch services or throught timer polled // services. void AppleTopazPluginCS8420::notifyHardwareEvent ( UInt32 statusSelector, UInt32 newValue ) { IOReturn error; UInt8 ratio; if ( kCodecErrorInterruptStatus == statusSelector ) { error = CODEC_ReadRegister ( map_CS8420_RX_ERROR, &mShadowRegs[map_CS8420_RX_ERROR], 1 ); FailIf ( kIOReturnSuccess != error, Exit ); // [4073140] - validate OMCK/RMCK ratio register error = CODEC_ReadRegister ( map_CS8420_SAMPLE_RATE_RATIO, &mShadowRegs[map_CS8420_SAMPLE_RATE_RATIO], 1 ); FailIf ( kIOReturnSuccess != error, Exit ); ratio = mShadowRegs[map_CS8420_SAMPLE_RATE_RATIO]; if ( ( ( bvCS8420_pllLocked << baCS8420_UNLOCK ) == ( ( bvCS8420_pllUnlocked << baCS8420_UNLOCK ) & mShadowRegs[map_CS8420_RX_ERROR] ) ) && ( ( kCS84XX_OMCK_RMCK_RATIO_LOCKED_MIN <= ratio ) && ( kCS84XX_OMCK_RMCK_RATIO_LOCKED_MAX >= ratio ) ) ) { mUnlockErrorCount = 0; mLockStatus = TRUE; } else { mUnlockErrorCount++; if ( kCLOCK_UNLOCK_ERROR_TERMINAL_COUNT < mUnlockErrorCount ) { mUnlockErrorCount = 0; mLockStatus = FALSE; } } if ( mLockStatus ) { debugIOLog ( 4, " AppleTopazPluginCS8420::notifyHardwareEvent posts kClockLockStatus, mShadowRegs[map_CS8420_RX_ERROR] = 0x%0.2X, OMCK/RMCK ratio = 0x%0.2X", mShadowRegs[map_CS8420_RX_ERROR], ratio ); mAudioDeviceProvider->interruptEventHandler ( kClockLockStatus, (UInt32)0 ); } else { debugIOLog ( 4, " AppleTopazPluginCS8420::notifyHardwareEvent posts kClockUnLockStatus, mShadowRegs[map_CS8420_RX_ERROR] = 0x%0.2X, OMCK/RMCK ratio = 0x%0.2X", mShadowRegs[map_CS8420_RX_ERROR], ratio ); mAudioDeviceProvider->interruptEventHandler ( kClockUnLockStatus, (UInt32)0 ); } } else if ( kCodecInterruptStatus == statusSelector ) { } Exit: return; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IOReturn AppleTopazPluginCS8420::initCodecRegisterCache ( void ) { IOReturn result = kIOReturnSuccess; IOReturn err; for ( UInt32 loopCnt = map_CS8420_MISC_CNTRL_1; loopCnt <= map_CS8420_BUFFER_23; loopCnt++ ) { if ( map_CS8420_RX_ERROR != loopCnt && map_CS8420_RESERVED_1F != loopCnt ) { // avoid hole in register address space err = CODEC_ReadRegister ( loopCnt, NULL, 1 ); // read I2C register into cache only if ( kIOReturnSuccess != err && kIOReturnSuccess == result ) { result = err; } } } return result; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ bool AppleTopazPluginCS8420::preDMAEngineInit ( void ) { bool result = false; IOReturn err; // Place device into power down state prior to initialization err = CODEC_WriteRegister ( map_CS8420_CLOCK_SOURCE_CTRL, kCS8420_CLOCK_SOURCE_CTRL_INIT_STOP ); FailIf ( kIOReturnSuccess != err, Exit ); err = CODEC_WriteRegister ( map_CS8420_MISC_CNTRL_1, kCS8420_MISC_CNTRL_1_INIT ); FailIf ( kIOReturnSuccess != err, Exit ); err = CODEC_WriteRegister ( map_CS8420_MISC_CNTRL_2, kCS8420_MISC_CNTRL_2_INIT ); FailIf ( kIOReturnSuccess != err, Exit ); err = CODEC_WriteRegister ( map_CS8420_DATA_FLOW_CTRL, kCS8420_DATA_FLOW_CTRL_INIT ); FailIf ( kIOReturnSuccess != err, Exit ); err = CODEC_WriteRegister ( map_CS8420_SERIAL_INPUT_FMT, kCS8420_SERIAL_AUDIO_INPUT_FORMAT_INIT ); FailIf ( kIOReturnSuccess != err, Exit ); err = CODEC_WriteRegister ( map_CS8420_SERIAL_OUTPUT_FMT, kCS8420_SERIAL_AUDIO_OUTPUT_FORMAT_INIT ); FailIf ( kIOReturnSuccess != err, Exit ); // Enable receiver error (i.e. RERR) interrupts err = CODEC_WriteRegister ( map_CS8420_RX_ERROR_MASK, kCS8420_RX_ERROR_MASK_ENABLE_RERR ); FailIf ( kIOReturnSuccess != err, Exit ); // Clear any pending error interrupt err = CODEC_ReadRegister ( map_CS8420_RX_ERROR, NULL, 1 ); FailIf ( kIOReturnSuccess != err, Exit ); err = CODEC_WriteRegister ( map_CS8420_CLOCK_SOURCE_CTRL, kCS8420_CLOCK_SOURCE_CTRL_INIT ); FailIf ( kIOReturnSuccess != err, Exit ); err = CODEC_WriteRegister ( map_CS8420_USER_DATA_BUF_CTRL, bvCS8420_ubmBlock << baCS8420_UBM ); FailIf ( kIOReturnSuccess != err, Exit ); result = true; Exit: return result; }
/******************************************************************************* * Function Name : CODEC_WriteRegister * Description : Writes a value in a register of the audio Codec through I2C. * Input : - RegisterAddr: The target register address (between 00x and 0x24) * : - RegisterValue: The target register value to be written * : - Verify: 0-> Don't verify the written data, 1-> Verify the written data * Output : None * Return : - 0 -> Correct write operation * : - !0 -> Incorrect write operation *******************************************************************************/ uint32_t CODEC_WriteRegister(uint32_t RegisterAddr, uint32_t RegisterValue) { uint32_t read_verif = 0; /* Reset all I2C2 registers */ I2C_SoftwareResetCmd(I2C1, ENABLE); I2C_SoftwareResetCmd(I2C1, DISABLE); /* Enable the I2C1 peripheral */ I2C_Cmd(I2C1, ENABLE); /* Configure the I2C peripheral */ I2C_Config(); /* Begin the config sequence */ I2C_GenerateSTART(I2C1, ENABLE); /* Test on EV5 and clear it */ while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)) {} /* Transmit the slave address and enable writing operation */ I2C_Send7bitAddress(I2C1, CODEC_ADDRESS, I2C_Direction_Transmitter); /* Test on EV6 and clear it */ while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) {} /* Transmit the first address for r/w operations */ I2C_SendData(I2C1, RegisterAddr); /* Test on EV8 and clear it */ while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) {} /* Prepare the register value to be sent */ I2C_SendData(I2C1, RegisterValue); /* Test on EV8 and clear it */ while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) {} /* End the configuration sequence */ I2C_GenerateSTOP(I2C1, ENABLE); /* Verify (if needed) that the loaded data is correct */ #ifdef VERIFY_WRITTENDATA /* Read the just written register*/ read_verif = CODEC_ReadRegister(RegisterAddr); /* Load the register and verify its value */ if (read_verif != RegisterValue) { /* Control data wrongly transferred */ read_verif = 1; } else { /* Control data correctly transferred */ read_verif = 0; } #endif /* Return the verifying value: 0 (Passed) or 1 (Failed) */ return read_verif; }