AudioI2SControl.cpp [plain text]
#include "AudioI2SControl.h"
#include "daca_hw.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)
{
DEBUG_IOLOG("+ AudioI2SControl::init\n");
IOMemoryMap *map = theInfo->map ;
if(!super::init())
return(false);
soundConfigSpace = (UInt8 *)map->getPhysicalAddress();
if ((((UInt32)soundConfigSpace ^ kI2S0BaseOffset) & 0x0001FFFF) == 0)
{
ioBaseAddress = (void *)((UInt32)soundConfigSpace - kI2S0BaseOffset);
i2SInterfaceNumber = 0;
}
else if ((((UInt32)soundConfigSpace ^ kI2S1BaseOffset) & 0x0001FFFF) == 0)
{
ioBaseAddress = (void *)((UInt32)soundConfigSpace - kI2S1BaseOffset);
i2SInterfaceNumber = 1;
}
else
{
DEBUG_IOLOG("AudioI2SControl::init ERROR: unable to setup ioBaseAddress and i2SInterfaceNumber\n");
}
ioClockBaseAddress = (void *)((UInt32)ioBaseAddress + kI2SClockOffset);
ioStatusRegister_GPIO12 = (void *)((UInt32)ioBaseAddress + kGPio12);
KLSetRegister(ioClockBaseAddress, KLGetRegister(ioClockBaseAddress) | kI2S0InterfaceEnable);
if (!dependentSetup())
{
DEBUG_IOLOG("AudioI2SControl::init ERROR: DAC-3550 setup failed\n");
}
DEBUG_IOLOG("- AudioI2SControl::init\n");
return(true);
}
void AudioI2SControl::free()
{
super::free();
}
bool AudioI2SControl::setSampleParameters(
UInt32 sampleRate,
UInt32 mclkToFsRatio)
{
UInt32 mclkRatio;
UInt32 reqMClkRate;
mclkRatio = mclkToFsRatio;
if ( mclkRatio == 0 ) mclkRatio = 64;
reqMClkRate = sampleRate * mclkRatio;
if ((kClock18MHz % reqMClkRate) == 0) { dacaClockSource = kClock18MHz;
} else if ((kClock45MHz % reqMClkRate) == 0) { dacaClockSource = kClock45MHz;
} else if ((kClock49MHz % reqMClkRate) == 0) { dacaClockSource = kClock49MHz;
} else {
CLOG("AppleDACAAudio::setSampleParameters Unable to find a suitable source clock (no globals changes take effect)\n");
return false;
}
dacaMclkDivisor = dacaClockSource / reqMClkRate;
switch (dacaSerialFormat) { case kSndIOFormatI2SSony:
case kSndIOFormatI2S64x:
dacaSclkDivisor = mclkRatio / k64TicksPerFrame; break;
case kSndIOFormatI2S32x:
dacaSclkDivisor = mclkRatio / k32TicksPerFrame; break;
default:
DEBUG_IOLOG("AppleDACAAudio::setSampleParameters Invalid serial format\n");
return false;
break;
}
return true;
}
void AudioI2SControl::setSerialFormatRegister(
ClockSource clockSource,
UInt32 mclkDivisor,
UInt32 sclkDivisor,
SoundFormat serialFormat)
{
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);
I2SSetSerialFormatReg(regValue);
clockRun(true);
}
bool AudioI2SControl::dependentSetup(
void)
{
DEBUG_IOLOG( "+ AppleDACAAudio::dependentSetup\n");
UInt32 myFrameRate = frameRate(0);
dacaSerialFormat = kSndIOFormatI2S32x;
if (dacaSerialFormat == kSndIOFormatUnknown)
dacaSerialFormat = kSndIOFormatI2SSony;
if (!setSampleParameters(myFrameRate, 0))
{
DEBUG_IOLOG("AppleDACAAudio::dependentSetup can not set i2s sample rate\n");
return false;
}
else
{
setSerialFormatRegister(dacaClockSource, dacaMclkDivisor, dacaSclkDivisor, dacaSerialFormat);
}
DEBUG_IOLOG( "+ AppleDACAAudio::dependentSetup\n");
return true;
}
#pragma mark + GENERIC REGISTER ACCESS ROUTINES
INLINE UInt32 AudioI2SControl::ReadWordLittleEndian(
void *address,
UInt32 offset )
{
#if 0
UInt32 *realAddress = (UInt32*)(address) + offset;
UInt32 value = *realAddress;
UInt32 newValue =
((value & 0x000000FF) << 16) |
((value & 0x0000FF00) << 8) |
((value & 0x00FF0000) >> 8) |
((value & 0xFF000000) >> 16);
return (newValue);
#else
return OSReadLittleInt32(address, offset);
#endif
}
INLINE void AudioI2SControl::WriteWordLittleEndian(
void *address,
UInt32 offset,
UInt32 value)
{
#if 0
UInt32 *realAddress = (UInt32*)(address) + offset;
UInt32 newValue =
((value & 0x000000FF) << 16) |
((value & 0x0000FF00) << 8) |
((value & 0x00FF0000) >> 8) |
((value & 0xFF000000) >> 16);
*realAddress = newValue;
#else
OSWriteLittleInt32(address, offset, value);
#endif
}
INLINE UInt32 AudioI2SControl::I2SGetIntCtlReg(
void)
{
return ReadWordLittleEndian(soundConfigSpace, kI2SIntCtlOffset);
}
INLINE void AudioI2SControl::I2SSetIntCtlReg(
UInt32 value)
{
WriteWordLittleEndian(soundConfigSpace, kI2SIntCtlOffset, value);
}
INLINE UInt32 AudioI2SControl::I2SGetSerialFormatReg(
void)
{
return ReadWordLittleEndian(soundConfigSpace, kI2SSerialFormatOffset);
}
INLINE void AudioI2SControl::I2SSetSerialFormatReg(
UInt32 value)
{
WriteWordLittleEndian(soundConfigSpace, kI2SSerialFormatOffset, value);
}
INLINE UInt32 AudioI2SControl::I2SGetCodecMsgOutReg(
void)
{
return ReadWordLittleEndian(soundConfigSpace, kI2SCodecMsgOutOffset);
}
INLINE void AudioI2SControl::I2SSetCodecMsgOutReg(
UInt32 value)
{
WriteWordLittleEndian(soundConfigSpace, kI2SCodecMsgOutOffset, value);
}
INLINE UInt32 AudioI2SControl::I2SGetCodecMsgInReg(
void)
{
return ReadWordLittleEndian(soundConfigSpace, kI2SCodecMsgInOffset);
}
INLINE void AudioI2SControl::I2SSetCodecMsgInReg(
UInt32 value)
{
WriteWordLittleEndian(soundConfigSpace, kI2SCodecMsgInOffset, value);
}
INLINE UInt32 AudioI2SControl::I2SGetFrameCountReg(
void)
{
return ReadWordLittleEndian(soundConfigSpace, kI2SFrameCountOffset);
}
INLINE void AudioI2SControl::I2SSetFrameCountReg(
UInt32 value)
{
WriteWordLittleEndian(soundConfigSpace, kI2SFrameCountOffset, value);
}
INLINE UInt32 AudioI2SControl::I2SGetFrameMatchReg(
void)
{
return ReadWordLittleEndian(soundConfigSpace, kI2SFrameMatchOffset);
}
INLINE void AudioI2SControl::I2SSetFrameMatchReg(
UInt32 value)
{
WriteWordLittleEndian(soundConfigSpace, kI2SFrameMatchOffset, value);
}
INLINE UInt32 AudioI2SControl::I2SGetDataWordSizesReg(
void)
{
return ReadWordLittleEndian(soundConfigSpace, kI2SDataWordSizesOffset);
}
INLINE void AudioI2SControl::I2SSetDataWordSizesReg(
UInt32 value)
{
WriteWordLittleEndian(soundConfigSpace, kI2SDataWordSizesOffset, value);
}
INLINE UInt32 AudioI2SControl::I2SGetPeakLevelSelReg(
void)
{
return ReadWordLittleEndian(soundConfigSpace, kI2SPeakLevelSelOffset);
}
INLINE void AudioI2SControl::I2SSetPeakLevelSelReg(
UInt32 value)
{
WriteWordLittleEndian(soundConfigSpace, kI2SPeakLevelSelOffset, value);
}
INLINE UInt32 AudioI2SControl::I2SGetPeakLevelIn0Reg(
void)
{
return ReadWordLittleEndian(soundConfigSpace, kI2SPeakLevelIn0Offset);
}
INLINE void AudioI2SControl::I2SSetPeakLevelIn0Reg(
UInt32 value)
{
WriteWordLittleEndian(soundConfigSpace, kI2SPeakLevelIn0Offset, value);
}
INLINE UInt32 AudioI2SControl::I2SGetPeakLevelIn1Reg(
void)
{
return ReadWordLittleEndian(soundConfigSpace, kI2SPeakLevelIn1Offset);
}
INLINE void AudioI2SControl::I2SSetPeakLevelIn1Reg(
UInt32 value)
{
WriteWordLittleEndian(soundConfigSpace, kI2SPeakLevelIn1Offset, value);
}
INLINE UInt32 AudioI2SControl::I2SCounterReg(
void )
{
return ((UInt32)(soundConfigSpace) + kI2SFrameCountOffset);
}
INLINE void AudioI2SControl::KLSetRegister(
void *klRegister,
UInt32 value)
{
UInt32 *reg = (UInt32*)klRegister;
*reg = value;
}
INLINE UInt32 AudioI2SControl::KLGetRegister(
void *klRegister)
{
UInt32 *reg = (UInt32*)klRegister;
return (*reg);
}
bool AudioI2SControl::clockRun(bool start)
{
bool success = true;
if (start)
{
KLSetRegister(ioClockBaseAddress, KLGetRegister(ioClockBaseAddress) | kI2S0ClockEnable);
}
else
{
UInt16 loop = 50;
KLSetRegister(ioClockBaseAddress, KLGetRegister(ioClockBaseAddress) & (~kI2S0ClockEnable));
while (((I2SGetIntCtlReg() & kClocksStoppedPending) == 0) && (loop--))
{
IOSleep(10);
}
success = ((I2SGetIntCtlReg() & 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;
}