AudioI2SControl.cpp [plain text]
#include "AudioI2SControl.h"
#include "daca_hw.h"
#include "AudioI2SHardwareConstants.h"
#define super OSObject
OSDefineMetaClassAndStructors(AudioI2SControl, OSObject)
AudioI2SControl *AudioI2SControl::create(AudioI2SInfo *theInfo)
{
DEBUG_IOLOG("+ AudioI2SControl::create\n");
AudioI2SControl *myAudioI2SControl;
myAudioI2SControl = new AudioI2SControl;
if(myAudioI2SControl) {
if(!(myAudioI2SControl->init(theInfo))){
myAudioI2SControl->release();
myAudioI2SControl = 0;
}
}
DEBUG_IOLOG("- AudioI2SControl::create\n");
return myAudioI2SControl;
}
bool AudioI2SControl::init(AudioI2SInfo *theInfo)
{
debugIOLog("+ AudioI2SControl::init\n");
if(!super::init())
return(false);
if ( NULL == theInfo ) { return ( false ); }
IOMemoryMap *map = theInfo->map ;
switch ( theInfo->i2sSerialFormat ) { case kSerialFormatSony: case kSerialFormat64x: case kSerialFormat32x: case kSerialFormatDAV: case kSerialFormatSiliLabs:
serialFormat = theInfo->i2sSerialFormat; break;
default:
debugIOLog ( "### WRONG I2S Serial Format\n" );
serialFormat = kSerialFormatSony; break;
}
soundConfigSpace = (UInt8 *)map->getPhysicalAddress();
if ((((UInt32)soundConfigSpace ^ kI2S0BaseOffset) & 0x0001FFFF) == 0)
{
ioBaseAddress = (void *)((UInt32)soundConfigSpace - kI2S0BaseOffset);
ioBaseAddressMemory = IODeviceMemory::withRange ((IOPhysicalAddress)((UInt8 *)soundConfigSpace - kI2S0BaseOffset), 256);
i2SInterfaceNumber = kUseI2SCell0;
}
else if ((((UInt32)soundConfigSpace ^ kI2S1BaseOffset) & 0x0001FFFF) == 0)
{
ioBaseAddress = (void *)((UInt32)soundConfigSpace - kI2S1BaseOffset);
ioBaseAddressMemory = IODeviceMemory::withRange ((IOPhysicalAddress)((UInt8 *)soundConfigSpace - kI2S1BaseOffset), 256);
i2SInterfaceNumber = kUseI2SCell1;
}
else
{
DEBUG_IOLOG("AudioI2SControl::init ERROR: unable to setup ioBaseAddress and i2SInterfaceNumber\n");
}
if (NULL != ioBaseAddressMemory) {
ioConfigurationBaseAddress = (void *)ioBaseAddressMemory->map()->getVirtualAddress();
} else {
return false;
}
if (kUseI2SCell0 == i2SInterfaceNumber) {
ioI2SBaseAddressMemory = IODeviceMemory::withRange ((IOPhysicalAddress)((UInt8 *)soundConfigSpace), kI2S_IO_CONFIGURATION_SIZE);
} else {
ioI2SBaseAddressMemory = IODeviceMemory::withRange ((IOPhysicalAddress)((UInt8 *)soundConfigSpace), kI2S_IO_CONFIGURATION_SIZE);
}
if (NULL != ioI2SBaseAddressMemory) {
i2sBaseAddress = (void *)ioI2SBaseAddressMemory->map()->getVirtualAddress();
} else {
return false;
}
if ( kUseI2SCell0 == i2SInterfaceNumber ) {
KLSetRegister ( ((UInt8*)ioConfigurationBaseAddress) + kFCR1Offset, KLGetRegister ( ((UInt8*)ioConfigurationBaseAddress) + kFCR1Offset ) | kI2S0InterfaceEnable );
} else {
KLSetRegister ( ((UInt8*)ioConfigurationBaseAddress) + kFCR1Offset, KLGetRegister ( ((UInt8*)ioConfigurationBaseAddress) + kFCR1Offset ) | kI2S1InterfaceEnable );
}
DEBUG_IOLOG("- AudioI2SControl::init\n");
return(true);
}
void AudioI2SControl::free()
{
if (NULL != ioBaseAddressMemory) {
ioBaseAddressMemory->release();
}
if (NULL != ioI2SBaseAddressMemory) {
ioI2SBaseAddressMemory->release();
}
super::free();
}
bool AudioI2SControl::setSampleParameters(UInt32 sampleRate, UInt32 mclkToFsRatio, ClockSource *pClockSource, UInt32 *pMclkDivisor, UInt32 *pSclkDivisor, UInt32 newSerialFormat)
{
UInt32 mclkRatio;
UInt32 reqMClkRate;
mclkRatio = mclkToFsRatio;
if ( mclkRatio == 0 ) mclkRatio = 64;
reqMClkRate = sampleRate * mclkRatio;
if ((kClock18MHz % reqMClkRate) == 0) { clockSource = kClock18MHz;
} else if ((kClock45MHz % reqMClkRate) == 0) { clockSource = kClock45MHz;
} else if ((kClock49MHz % reqMClkRate) == 0) { clockSource = kClock49MHz;
} else {
CLOG("AppleDACAAudio::setSampleParameters Unable to find a suitable source clock (no globals changes take effect)\n");
return false;
}
*pClockSource = clockSource;
mclkDivisor = clockSource / reqMClkRate;
*pMclkDivisor = mclkDivisor;
switch (newSerialFormat) { case kSndIOFormatI2SSony:
case kSndIOFormatI2S64x:
sclkDivisor = mclkRatio / k64TicksPerFrame; serialFormat = newSerialFormat;
break;
case kSndIOFormatI2S32x:
sclkDivisor = mclkRatio / k32TicksPerFrame; serialFormat = newSerialFormat;
break;
default:
DEBUG_IOLOG("AppleDACAAudio::setSampleParameters Invalid serial format\n");
return false;
break;
}
*pSclkDivisor = sclkDivisor;
return true;
}
void AudioI2SControl::setSerialFormatRegister(ClockSource clockSource, UInt32 mclkDivisor, UInt32 sclkDivisor, SoundFormat serialFormat, UInt32 newDataFormat)
{
UInt32 regValue = 0;
switch ((int)clockSource) {
case kClock18MHz: regValue = kClockSource18MHz; break;
case kClock45MHz: regValue = kClockSource45MHz; break;
case kClock49MHz: regValue = kClockSource49MHz; break;
default: break;
}
switch (mclkDivisor) {
case 1: regValue |= kMClkDivisor1; break;
case 3: regValue |= kMClkDivisor3; break;
case 5: regValue |= kMClkDivisor5; break;
default: regValue |= (((mclkDivisor / 2) - 1) << kMClkDivisorShift) & kMClkDivisorMask; break;
}
switch ((int)sclkDivisor) { case 1: regValue |= kSClkDivisor1; break;
case 3: regValue |= kSClkDivisor3; break;
default: regValue |= (((sclkDivisor / 2) - 1) << kSClkDivisorShift) & kSClkDivisorMask; break;
}
regValue |= kSClkMaster;
switch (serialFormat) {
case kSndIOFormatI2SSony: regValue |= kSerialFormatSony; break;
case kSndIOFormatI2S64x: regValue |= kSerialFormat64x; break;
case kSndIOFormatI2S32x: regValue |= kSerialFormat32x; break;
default: break;
}
clockRun(false);
SetSerialFormatReg ( regValue );
dataFormat = newDataFormat; SetDataWordSizesReg ( dataFormat ); clockRun(true);
}
#pragma mark + GENERIC REGISTER ACCESS ROUTINES
UInt32 AudioI2SControl::ReadWordLittleEndian(void *address, UInt32 offset )
{
return OSReadLittleInt32(address, offset);
}
void AudioI2SControl::WriteWordLittleEndian(void *address, UInt32 offset, UInt32 value)
{
OSWriteLittleInt32(address, offset, value);
}
UInt32 AudioI2SControl::GetIntCtlReg(void)
{
return ReadWordLittleEndian(i2sBaseAddress, kI2SIntCtlOffset);
}
void AudioI2SControl::SetIntCtlReg(UInt32 value)
{
WriteWordLittleEndian(i2sBaseAddress, kI2SIntCtlOffset, value);
}
UInt32 AudioI2SControl::GetSerialFormatReg(void)
{
return ReadWordLittleEndian(i2sBaseAddress, kI2SSerialFormatOffset);
}
void AudioI2SControl::SetSerialFormatReg(UInt32 value)
{
WriteWordLittleEndian(i2sBaseAddress, kI2SSerialFormatOffset, value);
}
UInt32 AudioI2SControl::GetCodecMsgOutReg(void)
{
return ReadWordLittleEndian(i2sBaseAddress, kI2SCodecMsgOutOffset);
}
void AudioI2SControl::SetCodecMsgOutReg(UInt32 value)
{
WriteWordLittleEndian(i2sBaseAddress, kI2SCodecMsgOutOffset, value);
}
UInt32 AudioI2SControl::GetCodecMsgInReg(void)
{
return ReadWordLittleEndian(i2sBaseAddress, kI2SCodecMsgInOffset);
}
void AudioI2SControl::SetCodecMsgInReg(UInt32 value)
{
WriteWordLittleEndian(i2sBaseAddress, kI2SCodecMsgInOffset, value);
}
UInt32 AudioI2SControl::GetFrameCountReg(void)
{
return ReadWordLittleEndian(i2sBaseAddress, kI2SFrameCountOffset);
}
void AudioI2SControl::SetFrameCountReg(UInt32 value)
{
WriteWordLittleEndian(i2sBaseAddress, kI2SFrameCountOffset, value);
}
UInt32 AudioI2SControl::GetFrameMatchReg(void)
{
return ReadWordLittleEndian(i2sBaseAddress, kI2SFrameMatchOffset);
}
void AudioI2SControl::SetFrameMatchReg(UInt32 value)
{
WriteWordLittleEndian(i2sBaseAddress, kI2SFrameMatchOffset, value);
}
UInt32 AudioI2SControl::GetDataWordSizesReg(void)
{
return ReadWordLittleEndian(i2sBaseAddress, kI2SDataWordSizesOffset);
}
void AudioI2SControl::SetDataWordSizesReg(UInt32 value)
{
WriteWordLittleEndian(i2sBaseAddress, kI2SDataWordSizesOffset, value);
}
UInt32 AudioI2SControl::GetPeakLevelSelReg(void)
{
return ReadWordLittleEndian(i2sBaseAddress, kI2SPeakLevelSelOffset);
}
void AudioI2SControl::SetPeakLevelSelReg(UInt32 value)
{
WriteWordLittleEndian(i2sBaseAddress, kI2SPeakLevelSelOffset, value);
}
UInt32 AudioI2SControl::GetPeakLevelIn0Reg(void)
{
return ReadWordLittleEndian(i2sBaseAddress, kI2SPeakLevelIn0Offset);
}
void AudioI2SControl::SetPeakLevelIn0Reg(UInt32 value)
{
WriteWordLittleEndian(i2sBaseAddress, kI2SPeakLevelIn0Offset, value);
}
UInt32 AudioI2SControl::GetPeakLevelIn1Reg(void)
{
return ReadWordLittleEndian(i2sBaseAddress, kI2SPeakLevelIn1Offset);
}
void AudioI2SControl::SetPeakLevelIn1Reg(UInt32 value)
{
WriteWordLittleEndian(i2sBaseAddress, kI2SPeakLevelIn1Offset, value);
}
UInt32 AudioI2SControl::GetCounterReg(void )
{
return ((UInt32)(i2sBaseAddress) + kI2SFrameCountOffset);
}
UInt32 AudioI2SControl::FCR1GetReg( void )
{
return ReadWordLittleEndian ( ioConfigurationBaseAddress, kFCR1Offset ); }
void AudioI2SControl::Fcr1SetReg(UInt32 value)
{
WriteWordLittleEndian( ioConfigurationBaseAddress, kFCR1Offset, value ); }
UInt32 AudioI2SControl::FCR3GetReg( void )
{
return ReadWordLittleEndian ( ioConfigurationBaseAddress, kFCR3Offset ); }
void AudioI2SControl::Fcr3SetReg(UInt32 value)
{
WriteWordLittleEndian( ioConfigurationBaseAddress, kFCR3Offset, value ); }
void AudioI2SControl::KLSetRegister(void *klRegister, UInt32 value)
{
OSWriteLittleInt32(klRegister, 0, value);
}
UInt32 AudioI2SControl::KLGetRegister(void *klRegister)
{
return (OSReadLittleInt32(klRegister, 0));
}
bool AudioI2SControl::clockRun(bool start)
{
bool success = true;
if (start) {
switch ( i2SInterfaceNumber ) {
case kUseI2SCell0:
KLSetRegister(((UInt8*)ioConfigurationBaseAddress) + kFCR1Offset, KLGetRegister( ((UInt8*)ioConfigurationBaseAddress) + kFCR1Offset ) | kI2S0ClockEnable);
break;
case kUseI2SCell1:
KLSetRegister(((UInt8*)ioConfigurationBaseAddress) + kFCR1Offset, KLGetRegister( ((UInt8*)ioConfigurationBaseAddress) + kFCR1Offset ) | kI2S1ClockEnable);
break;
}
} else {
UInt16 loop = 50;
switch ( i2SInterfaceNumber ) {
case kUseI2SCell0:
KLSetRegister(((UInt8*)ioConfigurationBaseAddress) + kFCR1Offset, KLGetRegister( ((UInt8*)ioConfigurationBaseAddress) + kFCR1Offset ) & (~kI2S0ClockEnable));
break;
case kUseI2SCell1:
KLSetRegister(((UInt8*)ioConfigurationBaseAddress) + kFCR1Offset, KLGetRegister( ((UInt8*)ioConfigurationBaseAddress) + kFCR1Offset ) & (~kI2S1ClockEnable));
break;
}
while (((GetIntCtlReg() & kClocksStoppedPending) == 0) && (loop--)) {
IOSleep(10);
}
success = ((GetIntCtlReg() & kClocksStoppedPending) != 0);
}
if (!success)
debug2IOLog("PPCDACA::clockRun(%s) failed\n", (start ? "true" : "false"));
return success;
}
#define kCommonFrameRate 44100
UInt32 AudioI2SControl::frameRate(UInt32 index)
{
return (UInt32)kCommonFrameRate;
}