| author | William Roberts <williamr@symbian.org> |
| Fri, 01 Oct 2010 12:45:26 +0100 | |
| changeset 3 | b41049883d87 |
| parent 0 | 5de814552237 |
| permissions | -rw-r--r-- |
/* * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * This component and the accompanying materials are made available * under the terms of "Eclipse Public License v1.0" * which accompanies this distribution, and is available * at the URL "http://www.eclipse.org/legal/epl-v10.html". * * Initial Contributors: * Nokia Corporation - initial contribution. * * Contributors: * * Description: * bsp\nwip_nec_naviengine\naviengine_assp\i2s\i2s_psl.cpp * */ #include "navi_i2s.h" #include <naviengine.h> #ifdef __SMP__ static TSpinLock I2sLock = TSpinLock(TSpinLock::EOrderGenericIrqLow2); #endif // All channels have the same configuration. // base for registers are shifted for each channel by 0x400 (1<<10) #define HW_CHAN_SHIFT 10 // Registers // these macros will return register address for a given interface #define KHwI2SControl(intefaceId) ((KHwBaseI2S0 + KHoI2SCtrl) + (intefaceId << HW_CHAN_SHIFT)) #define KHwI2SFifoControl(intefaceId) ((KHwBaseI2S0 + KHoI2SFifoCtrl) + (intefaceId << HW_CHAN_SHIFT)) #define KHwI2SFifoStatus(intefaceId) ((KHwBaseI2S0 + KHoI2SFifoSts) + (intefaceId << HW_CHAN_SHIFT)) #define KHwI2SInterruptFlag(intefaceId) ((KHwBaseI2S0 + KHoI2SIntFlg) + (intefaceId << HW_CHAN_SHIFT)) #define KHwI2SInterruptMask(intefaceId) ((KHwBaseI2S0 + KHoI2SIntMask) + (intefaceId << HW_CHAN_SHIFT)) #define KHwI2SDataIn(intefaceId) ((KHwBaseI2S0 + KHoI2SRx) + (intefaceId << HW_CHAN_SHIFT)) #define KHwI2SDataOut(intefaceId) ((KHwBaseI2S0 + KHoI2STx) + (intefaceId << HW_CHAN_SHIFT)) #define AsspIsBitSet(addr, bit) (AsspRegister::Read32(addr)& (bit)) #define CLEARMASK(shift,len) (((1 << len) - 1) << shift) #define AsspGetBits(w,shift,len) ((AsspRegister::Read32(w) >> shift) & ((1 << (len)) - 1)) #define AsspSetBits(w,set,shift,len) (AsspRegister::Modify32(w, (CLEARMASK(shift, len)) , (set << shift))) NONSHARABLE_CLASS(D2sChannelNE1_TB) : public DI2sChannelBase { public: D2sChannelNE1_TB(TInt aInterfaceId); virtual TInt ConfigureInterface(TDes8* aConfig); virtual TInt GetInterfaceConfiguration(TDes8& aConfig); virtual TInt SetSamplingRate(TInt aSamplingRate); virtual TInt GetSamplingRate(TInt& aSamplingRate); virtual TInt SetFrameLengthAndFormat(TInt aFrameLength, TInt aLeftFramePhaseLength); virtual TInt GetFrameFormat(TInt& aLeftFramePhaseLength, TInt& aRightFramePhaseLength); virtual TInt SetSampleLength(TInt aFramePhase, TInt aSampleLength); virtual TInt GetSampleLength(TInt aFramePhase, TInt& aSampleLength); virtual TInt SetDelayCycles(TInt aFramePhase, TInt aDelayCycles); virtual TInt GetDelayCycles(TInt aFramePhase, TInt& aDelayCycles); virtual TInt ReadReceiveRegister(TInt aFramePhase, TInt& aData); virtual TInt WriteTransmitRegister(TInt aFramePhase, TInt aData); virtual TInt ReadTransmitRegister(TInt aFramePhase, TInt& aData); virtual TInt ReadRegisterModeStatus(TInt aFramePhase, TInt& aFlags); virtual TInt EnableRegisterInterrupts(TInt aFramePhase, TInt aInterrupt); virtual TInt DisableRegisterInterrupts(TInt aFramePhase, TInt aInterrupt); virtual TInt IsRegisterInterruptEnabled(TInt aFramePhase, TInt& aEnabled); virtual TInt EnableFIFO(TInt aFramePhase, TInt aFifoMask); virtual TInt DisableFIFO(TInt aFramePhase, TInt aFifoMask); virtual TInt IsFIFOEnabled(TInt aFramePhase, TInt& aEnabled); virtual TInt SetFIFOThreshold(TInt aFramePhase, TInt aDirection, TInt aThreshold); virtual TInt ReadFIFOModeStatus(TInt aFramePhase, TInt& aFlags); virtual TInt EnableFIFOInterrupts(TInt aFramePhase, TInt aInterrupt); virtual TInt DisableFIFOInterrupts(TInt aFramePhase, TInt aInterrupt); virtual TInt IsFIFOInterruptEnabled(TInt aFramePhase, TInt& aEnabled); virtual TInt ReadFIFOLevel(TInt aFramePhase, TInt aDirection, TInt& aLevel); virtual TInt EnableDMA(TInt aFifoMask); virtual TInt DisableDMA(TInt aFifoMask); virtual TInt IsDMAEnabled(TInt& aEnabled); virtual TInt Start(TInt aDirection); virtual TInt Stop(TInt aDirection); virtual TInt IsStarted(TInt aDirection, TBool& aStarted); private: TBool iConfigured; TInt iLastPhaseInWriteFifo; TInt iLastPhaseInReadFifo; }; // this static method, creates the DI2sChannelBase corresponding // to the interfaceId passed and return the channel // NB: if each channel was implemented independently (e.g. on a separate file) // this function would have to be provided spearately and know how to map // the interface ID to the appropriate channel object to be created // (e.g. each channel would have a different implementation D2sChannelXXX // and this function call the appropriate constructor for each interface Id) TInt DI2sChannelBase::CreateChannels(DI2sChannelBase*& aChannel, TInt aInterfaceId) { DI2sChannelBase* chan = new D2sChannelNE1_TB(aInterfaceId); if (!chan) { return KErrNoMemory; } aChannel = chan; return KErrNone; } // Default constructor. D2sChannelNE1_TB::D2sChannelNE1_TB(TInt aInterfaceId): iConfigured(EFalse), iLastPhaseInWriteFifo(I2s::ERight), // the first phase in write fifo should be left, so initialize to right iLastPhaseInReadFifo(I2s::ERight) // the first phase in read fifo should be left, so initialize to right { iInterfaceId=aInterfaceId; } TInt D2sChannelNE1_TB::ConfigureInterface(TDes8 *aConfig) { __KTRACE_OPT(KDLL, Kern::Printf("DI2sChannelNE1_TB::ConfigureInterfaceInterface (Id: %d)", iInterfaceId)); if(AsspIsBitSet(KHwI2SControl(iInterfaceId), KHtI2SCtrl_TEN | KHtI2SCtrl_REN)) { return KErrInUse; } TI2sConfigBufV01 &conf = ((TI2sConfigBufV01&)*aConfig); // this interface doesn's support EController mode if (conf().iType == I2s::EController) { return KErrNotSupported; } if(conf().iRole == I2s::EMaster) { AsspRegister::Modify32(KHwI2SControl(iInterfaceId), 0, KHtI2SCtrl_MSMODE); } // copy configuration.. it will be used in Start/Stop iConfig = conf(); // ok, thread context only and one client thread per channel // select I2S format AsspSetBits(KHwI2SControl(iInterfaceId), 4, KHsI2SCtrl_FORMAT, 3); iConfigured = ETrue; // this API can only be called in thread context and we assume that a channel is for use of a single thread return KErrNone; } TInt D2sChannelNE1_TB::GetInterfaceConfiguration(TDes8 &aConfig) { if (!iConfigured) // this API can only be called in thread context and we assume that a channel is for use of a single thread { aConfig.SetLength(0); //no configuration present yet.. } else { TPckgBuf<TI2sConfigV01> conf(iConfig); aConfig.Copy(conf); } return KErrNone; } TInt D2sChannelNE1_TB::SetSamplingRate(TInt aSamplingRate) { if (iConfig.iRole == I2s::ESlave) { return KErrNotSupported; } if (AsspIsBitSet(KHwI2SControl(iInterfaceId), KHtI2SCtrl_TEN | KHtI2SCtrl_REN)) { return KErrInUse; } TUint32 val = 0, div = 0; switch(aSamplingRate) { case I2s::E8KHz: // 0000: 8 kHz div = 1; // MCLK = 24.5760 MHz(1*) break; case I2s::E11_025KHz: // 1000: 11.025 kHz val = 8; div = 4; // MCLK = 33.8688 MHz(4*) or 22.5792(5*) or 16.9344 MHz(6) break; case I2s::E12KHz: // 0001: 12 kHz val = 1; div = 1; // MCLK = 24.5760 MHz(1*) or 18.432MHz(2) break; case I2s::E16KHz: // 0010: 16 kHz val = 2; div = 1; // MCLK = 24.5760 MHz(1*) break; case I2s::E22_05KHz: // 1001: 22.05 kHz val = 9; div = 4; // MCLK = 33.8688 MHz(4*) or 22.5792(5*) or 16.9344 MHz(6) break; case I2s::E24KHz: // 0011: 24 kHz val = 3; div = 1; // MCLK = 24.5760 MHz(1*) or 18.432MHz(2) break; case I2s::E32KHz: // 0100: 32 kHz val = 4; div = 1; // MCLK = 24.5760 MHz break; case I2s::E44_1KHz: // 1010: 44.1 kHz val = 10; div = 4; // MCLK = 33.8688 MHz(4*) or 22.5792(5*) or 16.9344 MHz(6) break; case I2s::E48KHz: // 0101: 48 kHz val = 5; div = 2; // MCLK = 24.5760 MHz(1*) or 18.432MHz(2) break; default: return KErrNotSupported; } TInt irq=__SPIN_LOCK_IRQSAVE(I2sLock); // seems that we must guarantee the following sequence is uninterrupted... // before changing FSCLKSEL and/or FSMODE - mask I2S bit // MSK_I2Sx (x=0:3): bits 18:21 in MaskCtrl Register of the System Ctrl Unit AsspRegister::Modify32(KHwBaseSCU + KHoSCUClockMaskCtrl, 0, (1<<iInterfaceId)<<18); // change the divide I2SCLK ctrl value for this channel.. AsspRegister::Modify32(KHwSystemCtrlBase+KHoSCUDivideI2SCLKCtrl, 0xf<<(iInterfaceId<<3), div<<(iInterfaceId<<3)); // update the KHwI2SControl register AsspSetBits(KHwI2SControl(iInterfaceId), val, KHsI2SCtrl_FCKLKSEL, 4); // after changing FSCLKSEL and FSMODE - clear MSK_I2Sx mask bit AsspRegister::Modify32(KHwBaseSCU + KHoSCUClockMaskCtrl, (1<<iInterfaceId)<<18, 0); __SPIN_UNLOCK_IRQRESTORE(I2sLock,irq); return KErrNone; } TInt D2sChannelNE1_TB::GetSamplingRate(TInt& aSamplingRate) { if (iConfig.iRole == I2s::ESlave) { return KErrNotSupported; } TUint32 val = (AsspRegister::Read32(KHwI2SControl(iInterfaceId))>>KHsI2SCtrl_FCKLKSEL) & 0xf; switch(val) { case 0: aSamplingRate = I2s::E8KHz; // 0000: 8 kHz break; case 8: aSamplingRate = I2s::E11_025KHz; // 1000: 11.025 kHz break; case 1: aSamplingRate = I2s::E12KHz; // 0001: 12 kHz break; case 2: aSamplingRate = I2s::E16KHz; // 0010: 16 kHz break; case 9: aSamplingRate = I2s::E22_05KHz; // 1001: 22.05 kHz break; case 3: aSamplingRate = I2s::E24KHz; // 0011: 24 kHz break; case 4: aSamplingRate = I2s::E32KHz; // 0100: 32 kHz break; case 10: aSamplingRate = I2s::E44_1KHz; // 1010: 44.1 kHz break; case 5: aSamplingRate = I2s::E48KHz; // 0101: 48 kHz break; } return KErrNone; } TInt D2sChannelNE1_TB::SetFrameLengthAndFormat(TInt aFrameLength, TInt /*aLeftFramePhaseLength*/) { if (AsspIsBitSet(KHwI2SControl(iInterfaceId), KHtI2SCtrl_TEN | KHtI2SCtrl_REN)) { return KErrInUse; } TUint32 val=0; switch(aFrameLength) { case I2s::EFrame32Bit: val = 0; break; case I2s::EFrame48Bit: val = 1; break; case I2s::EFrame64Bit: val = 2; break; case I2s::EFrame128Bit: val = 3; break; default: return KErrNotSupported; }; TInt irq=__SPIN_LOCK_IRQSAVE(I2sLock); // seems that we must guarantee the following sequence is uninterrupted // before changing FSCLKSEL and/or FSMODE - mask I2S bit // MSK_I2Sx (x=0:3): bits 18:21 in MaskCtrl Register of the System Ctrl Unit AsspRegister::Modify32(KHwBaseSCU + KHoSCUClockMaskCtrl, 0, (1<<iInterfaceId)<<18); // update the register (3 bits at KHsI2SCtrl_FSMODE) AsspSetBits(KHwI2SControl(iInterfaceId), val, KHsI2SCtrl_FSMODE, 3); // after changing FSCLKSEL and FSMODE - clear MSK_I2Sx mask bit AsspRegister::Modify32(KHwBaseSCU + KHoSCUClockMaskCtrl, (1<<iInterfaceId)<<18, 0); __SPIN_UNLOCK_IRQRESTORE(I2sLock,irq); return KErrNone; } TInt D2sChannelNE1_TB::GetFrameFormat(TInt& aLeftFramePhaseLength, TInt& aRightFramePhaseLength) { TInt frameLength=0; switch(AsspGetBits(KHwI2SControl(iInterfaceId), KHsI2SCtrl_FSMODE, 3)) { case 0: frameLength = I2s::EFrame32Bit; break; case 1: frameLength = I2s::EFrame48Bit; break; case 2: frameLength = I2s::EFrame64Bit; break; case 3: frameLength = I2s::EFrame128Bit; break; default: return KErrGeneral; //unexpected value?? }; aLeftFramePhaseLength=aRightFramePhaseLength=frameLength/2; // on NaviEngine frames are symmetrical return KErrNone; } TInt D2sChannelNE1_TB::SetSampleLength(TInt /*aFramePhase*/, TInt aSampleLength) { if (AsspIsBitSet(KHwI2SControl(iInterfaceId), KHtI2SCtrl_TEN | KHtI2SCtrl_REN)) { return KErrInUse; } TUint32 val=0; switch(aSampleLength) { case I2s::ESample8Bit: val = 0x8; break; case I2s::ESample16Bit: val = 0x10; break; case I2s::ESample24Bit: val = 0x18; break; case I2s::ESample12Bit: case I2s::ESample32Bit: return KErrNotSupported; } // update the register.. AsspSetBits(KHwI2SControl(iInterfaceId), val, KHsI2SCtrl_DLENGTH,5); // [4:0] sampling data length); return KErrNone; } TInt D2sChannelNE1_TB::GetSampleLength(TInt /*aFramePhase*/, TInt& aSampleLength) { // sample length can't be configured separately for left/right channels.. // .. in this chip, so aFramePhase is ignored TUint32 val=AsspRegister::Read32(KHwI2SControl(iInterfaceId)) & 0x1F; switch(val) { case 0x8: aSampleLength = I2s::ESample8Bit; break; case 0x10: aSampleLength = I2s::ESample16Bit; break; case 0x18: aSampleLength = I2s::ESample24Bit; break; } return KErrNone; } TInt D2sChannelNE1_TB::SetDelayCycles(TInt aFramePhase, TInt aDelayCycles) { return KErrNotSupported; } TInt D2sChannelNE1_TB::GetDelayCycles(TInt aFramePhase, TInt& aDelayCycles) { return KErrNotSupported; } TInt D2sChannelNE1_TB::ReadReceiveRegister(TInt aFramePhase, TInt& aData) { // should check here, if sample length was configured, // but once the interface is properly configured, this check would add unnecessary overhead. // since there is only one fifo for both channels in this chip, // we need to read Left and then Right channel data in sequence. TInt oldFP=__e32_atomic_swp_ord32(&iLastPhaseInReadFifo,aFramePhase); // atomic as this may be used in ISR too if(aFramePhase == oldFP) { return KErrNotSupported; } // and get the current data from the fifo register aData = AsspRegister::Read32(KHwI2SDataIn(iInterfaceId)); return KErrNone; } TInt D2sChannelNE1_TB::WriteTransmitRegister(TInt aFramePhase, TInt aData) { // should check here, if sample length was configured, // but once the interface is properly configured, this check would add unnecessary overhead. // since there is only one fifo for both channels in this chip, // we need to write Left and then right channel data in sequence. TInt oldFP=__e32_atomic_swp_ord32(&iLastPhaseInWriteFifo,aFramePhase); // atomic as this may be used in ISR too if(aFramePhase == oldFP) { return KErrNotSupported; } // and update the fifo register AsspRegister::Write32(KHwI2SDataOut(iInterfaceId), aData); return KErrNone; } TInt D2sChannelNE1_TB::ReadTransmitRegister(TInt aFramePhase, TInt& aData) { // since there is only one fifo for both channels in this chip, // we can only read the data for the last written phase (either left or right) TInt curFp=__e32_atomic_load_acq32(&iLastPhaseInWriteFifo); if(aFramePhase != curFp) { return KErrArgument; } // read the register aData = AsspRegister::Read32(KHwI2SDataOut(iInterfaceId)); return KErrNone; } TInt D2sChannelNE1_TB::ReadRegisterModeStatus(TInt aFramePhase, TInt& aFlags) { return KErrNotSupported; // register PIO mode not supported (FIFO always present) } TInt D2sChannelNE1_TB::EnableRegisterInterrupts(TInt aFramePhase, TInt aInterrupt) { return KErrNotSupported; // register PIO mode not supported (FIFO always present) } TInt D2sChannelNE1_TB::DisableRegisterInterrupts(TInt aFramePhase, TInt aInterrupt) { return KErrNotSupported; // register PIO mode not supported (FIFO always present) } TInt D2sChannelNE1_TB::IsRegisterInterruptEnabled(TInt aFramePhase, TInt& aEnabled) { return KErrNotSupported; // register PIO mode not supported (FIFO always present) } TInt D2sChannelNE1_TB::EnableFIFO(TInt /*aFramePhase*/, TInt aFifoMask) { TInt val=0; // Set and clear fifo init bits for transmit/receive // tere are only two FIFOs - not separated to phases.. if(aFifoMask & I2s::ETx) val = KHtI2SFifoCtrl_TFIFOCLR; if(aFifoMask & I2s::ERx) val |= KHtI2SFifoCtrl_RFIFOCLR; AsspRegister::Modify32(KHwI2SFifoControl(iInterfaceId), 0, val); AsspRegister::Modify32(KHwI2SFifoControl(iInterfaceId), val, 0); return KErrNone; } TInt D2sChannelNE1_TB::DisableFIFO(TInt aFramePhase, TInt aFifoMask) { // fifo is always enabled in this chip.. return KErrNotSupported; } TInt D2sChannelNE1_TB::IsFIFOEnabled(TInt /*aFramePhase*/, TInt& aEnabled) { // fifo is always enabled in this chip.. aEnabled = I2s::ERx|I2s::ETx; return KErrNone; } TInt D2sChannelNE1_TB::SetFIFOThreshold(TInt aFramePhase, TInt aDirection, TInt aThreshold) { // supported threshold values for this chip: // 011b - 16-word space available // 010b - 8-word space available // 001b - 4-word space available // 000b - 2-word space available if (aThreshold < 0) { return KErrNotSupported; } // Determine, what value was specified, and adjust it down to one // of the possible values TInt i=15; while(i>1) { if ( aThreshold!=(aThreshold & i)) break; i>>=1; } aThreshold = i+1; //this will now contain one of possible values (2-16); // now any of 16/8/4/2, shifted right until == 0 will give us requested register_value+2 // (instead of using 'switch(aThreshold)') i=0; while(aThreshold) { aThreshold>>=1; ++i; } aThreshold = i-2 >= 0 ? i-2 : 0; //if i-2 gives <0 (e.g.for aThreshold<4) -adjust to 0; if (AsspIsBitSet(KHwI2SControl(iInterfaceId), KHtI2SCtrl_TEN | KHtI2SCtrl_REN)) { return KErrInUse; } TUint32 clr, set; if(aDirection & I2s::ERx) // receive fifo.. { if (aFramePhase == I2s::ELeft) { clr = CLEARMASK(KHsI2SFifoCtrl_RFIFOLT, 3); set = (aThreshold << KHsI2SFifoCtrl_RFIFOLT); } else //if (aFramePhase == I2s::ERight) { clr = CLEARMASK(KHsI2SFifoCtrl_RFIFORT, 3); set = (aThreshold << KHsI2SFifoCtrl_RFIFORT); } } else // transmit fifo.. { if (aFramePhase == I2s::ELeft) { clr = CLEARMASK(KHsI2SFifoCtrl_TFIFOLT, 3); set = (aThreshold << KHsI2SFifoCtrl_TFIFOLT); } else // if (aFramePhase == I2s::ERight) { clr = CLEARMASK(KHsI2SFifoCtrl_TFIFORT, 3); set = (aThreshold << KHsI2SFifoCtrl_TFIFORT); } } // updating register with value will also clear FIFO initialization bits.. AsspRegister::Modify32(KHwI2SFifoControl(iInterfaceId), clr, set); return KErrNone; } TInt D2sChannelNE1_TB::ReadFIFOModeStatus(TInt aFramePhase, TInt& aFlags) { aFlags = 0; TInt irq=__SPIN_LOCK_IRQSAVE(I2sLock); // (read and clear), can be used in ISR TUint32 flags = AsspRegister::Read32(KHwI2SInterruptFlag(iInterfaceId)); AsspRegister::Write32(KHwI2SInterruptFlag(iInterfaceId), flags); // clear the status flags (after reading) __SPIN_UNLOCK_IRQRESTORE(I2sLock,irq); if (aFramePhase == I2s::ELeft) { if(flags & KHtI2SIntFlg_TFLURINT) // L-ch transmit FIFO underrun aFlags |= I2s::ETxUnderrun; if(flags & KHtI2SIntFlg_TFLEINT) // L-ch transmit FIFO reached the empty trigger level aFlags |= I2s::ETxEmpty; if(flags & KHtI2SIntFlg_RFLORINT) // L-ch receive FIFO overrun aFlags |= I2s::ERxOverrun; if(flags & KHtI2SIntFlg_RFLFINT) // L-ch receive FIFO reached the full trigger level aFlags |= I2s::ERxFull; } else { if(flags & KHtI2SIntFlg_TFRURINT) // R-ch transmit FIFO underrun aFlags |= I2s::ETxUnderrun; if(flags & KHtI2SIntFlg_TFREINT) // R-ch transmit FIFO reached the empty trigger level aFlags |= I2s::ETxEmpty; if(flags & KHtI2SIntFlg_RFRORINT) // R-ch receive FIFO overrun aFlags |= I2s::ERxOverrun; if(flags & KHtI2SIntFlg_RFRFINT) // R-ch receive FIFO reached the full trigger level aFlags |= I2s::ERxFull; } return KErrNone; } TInt D2sChannelNE1_TB::EnableFIFOInterrupts(TInt aFramePhase, TInt aInterrupt) { TUint32 val=0; if(aInterrupt & I2s::ERxFull) { if (aFramePhase == I2s::ELeft) val |= KHtI2SIntMask_RFLFINT; if (aFramePhase == I2s::ERight) val |= KHtI2SIntMask_RFRFINT; } if(aInterrupt & I2s::ETxEmpty) { if (aFramePhase == I2s::ELeft) val |= KHtI2SIntMask_TFLEINT; if (aFramePhase == I2s::ERight) val |= KHtI2SIntMask_TFREINT; } if(aInterrupt & I2s::ERxOverrun) { if (aFramePhase == I2s::ELeft) val |= KHtI2SIntMask_RFLORINT; if (aFramePhase == I2s::ERight) val |= KHtI2SIntMask_RFRORINT; } if(aInterrupt & I2s::ETxUnderrun) { if (aFramePhase == I2s::ELeft) val |= KHtI2SIntMask_TFLURINT; if (aFramePhase == I2s::ERight) val |= KHtI2SIntMask_TFRURINT; } if(aInterrupt & I2s::EFramingError) { // not supported, do nothing } if (val) { // update the register AsspRegister::Write32(KHwI2SInterruptMask(iInterfaceId), val); } return KErrNone; } TInt D2sChannelNE1_TB::DisableFIFOInterrupts(TInt aFramePhase, TInt aInterrupt) { TUint32 val = KHmI2SIntMask_ALL; if(aInterrupt & I2s::ERxFull) { if (aFramePhase == I2s::ELeft) val &= ~KHtI2SIntMask_RFLFINT; if (aFramePhase == I2s::ERight) val &= ~KHtI2SIntMask_RFRFINT; } if(aInterrupt & I2s::ETxEmpty) { if (aFramePhase == I2s::ELeft) val &= ~KHtI2SIntMask_TFLEINT; if (aFramePhase == I2s::ERight) val &= ~KHtI2SIntMask_TFREINT; } if(aInterrupt & I2s::ERxOverrun) { if (aFramePhase == I2s::ELeft) val &= ~KHtI2SIntMask_RFLORINT; if (aFramePhase == I2s::ERight) val &= ~KHtI2SIntMask_RFRORINT; } if(aInterrupt & I2s::ETxUnderrun) { if (aFramePhase == I2s::ELeft) val &= ~KHtI2SIntMask_TFLURINT; if (aFramePhase == I2s::ERight) val &= ~KHtI2SIntMask_TFRURINT; } if(aInterrupt & I2s::EFramingError) { // not supported, do nothing } TInt irq=__SPIN_LOCK_IRQSAVE(I2sLock); // (read and clear), not used from ISR but made safe nevertheless... TUint32 oldVal = AsspRegister::Read32(KHwI2SInterruptMask(iInterfaceId)); if (val!=oldVal) { // update the register AsspRegister::Write32(KHwI2SInterruptMask(iInterfaceId), val); } __SPIN_UNLOCK_IRQRESTORE(I2sLock,irq); return KErrNone; } TInt D2sChannelNE1_TB::IsFIFOInterruptEnabled(TInt aFramePhase, TInt& aEnabled) { // check, if any interrupt is enabled.. TUint32 val = AsspRegister::Read32(KHwI2SInterruptMask(iInterfaceId)); aEnabled=0; if(aFramePhase== I2s::ELeft) { if(val & KHtI2SIntMask_TFLURINT)// L-ch transmit FIFO underrun int enable aEnabled |= I2s::ETxUnderrun; if(val & KHtI2SIntMask_TFLEINT)// L-ch transmit FIFO reached the empty trigger level int enable aEnabled |= I2s::ETxEmpty; if(val & KHtI2SIntMask_RFLORINT)// L-ch receive FIFO overrun int enable aEnabled |= I2s::ERxOverrun; if(val & KHtI2SIntMask_RFLFINT)// L-ch receive FIFO reached the full trigger level int enable aEnabled |= I2s::ERxFull; } else { if(val & KHtI2SIntMask_TFRURINT)// R-ch transmit FIFO underrun int enable aEnabled |= I2s::ETxUnderrun; if(val & KHtI2SIntMask_TFREINT)// R-ch transmit FIFO reached the empty trigger level int enable aEnabled |= I2s::ETxEmpty; if(val & KHtI2SIntMask_RFRORINT)// R-ch receive FIFO overrun int enable aEnabled |= I2s::ERxOverrun; if(val & KHtI2SIntMask_RFRFINT)// R-ch receive FIFO reached the full trigger level int enable aEnabled |= I2s::ERxFull; } return KErrNone; } TInt D2sChannelNE1_TB::ReadFIFOLevel(TInt aFramePhase, TInt aDirection, TInt& aLevel) { // This device only allows us to see, if the receive FIFO or transmit FIFO is either // empty or full, so return: // TX FIFO: 1-FULL, 0-EMPTY, // RX FIFO: 1-EMPTY, 0-FULL TUint32 val = AsspRegister::Read32(KHwI2SFifoStatus(iInterfaceId)); if(aDirection & I2s::ETx) { if (aFramePhase == I2s::ELeft) { aLevel = (val & KHtI2SFifoSts_TFL_FULL) >> 17; // L-ch transmit FIFO full (bit 17) } else // I2s::ERight { aLevel = (val & KHtI2SFifoSts_TFR_FULL) >> 16; // R-ch transmit FIFO full (bit 16) } } else // I2s::ERx { if (aFramePhase == I2s::ELeft) { aLevel = (val & KHtI2SFifoSts_RFL_EMPTY) >> 1; // L-ch receive FIFO empty (bit 1) } else // I2s::ERight { aLevel = val & KHtI2SFifoSts_RFR_EMPTY; // R-ch receive FIFO empty (bit 0) } } return KErrNone; } TInt D2sChannelNE1_TB::EnableDMA(TInt aFifoMask) { TUint32 val=0; if(aFifoMask & I2s::ETx) val |= KHtI2SFifoCtrl_TDMAEN; if(aFifoMask & I2s::ERx) val |= KHtI2SFifoCtrl_RDMAEN; AsspRegister::Modify32(KHwI2SFifoControl(iInterfaceId), 0, val); return KErrNone; } TInt D2sChannelNE1_TB::DisableDMA(TInt aFifoMask) { TUint32 val=0; if(aFifoMask & I2s::ETx) val |= KHtI2SFifoCtrl_TDMAEN; if(aFifoMask & I2s::ERx) val |= KHtI2SFifoCtrl_RDMAEN; AsspRegister::Modify32(KHwI2SFifoControl(iInterfaceId), val, 0); return KErrNone; } TInt D2sChannelNE1_TB::IsDMAEnabled(TInt& aEnabled) { TUint32 val = AsspRegister::Read32(KHwI2SFifoControl(iInterfaceId)); aEnabled = 0; if(val & KHtI2SFifoCtrl_TDMAEN) aEnabled |= I2s::ETx; if(val & KHtI2SFifoCtrl_RDMAEN) aEnabled |= I2s::ERx; return KErrNone; } TInt D2sChannelNE1_TB::Start(TInt aDirection) { TUint32 val=0; if(aDirection & I2s::ERx) { // check, if the interface was configured for reception.. if (iConfig.iType != I2s::EReceiver && iConfig.iType != I2s::EBidirectional) { return KErrNotSupported; } __KTRACE_OPT(KDLL, Kern::Printf("I2S channel %d: Start Rx", iInterfaceId)); val |= KHtI2SCtrl_REN; } else { // check, if the interface was configured for transmission.. if (iConfig.iType != I2s::ETransmitter && iConfig.iType != I2s::EBidirectional) { return KErrNotSupported; } __KTRACE_OPT(KDLL, Kern::Printf("I2S channel %d: Start Tx", iInterfaceId)); val |= KHtI2SCtrl_TEN; } // update the register AsspRegister::Modify32(KHwI2SControl(iInterfaceId), 0, val); return KErrNone; } TInt D2sChannelNE1_TB::Stop(TInt aDirection) { TUint32 val=0; if(aDirection & I2s::ERx) { __KTRACE_OPT(KDLL, Kern::Printf("I2S channel %d: Stop Rx", iInterfaceId)); val = KHtI2SCtrl_REN; } else { __KTRACE_OPT(KDLL, Kern::Printf("I2S channel %d: Stop Rx", iInterfaceId)); val = KHtI2SCtrl_TEN; } // update the register AsspRegister::Modify32(KHwI2SControl(iInterfaceId), val, 0); return KErrNone; } TInt D2sChannelNE1_TB::IsStarted(TInt aDirection, TBool& aStarted) { TUint32 val=AsspRegister::Read32(KHwI2SControl(iInterfaceId)); if(aDirection & I2s::ERx) { aStarted = (val & KHtI2SCtrl_REN) >> 24; // bit 24 } else { aStarted = (val & KHtI2SCtrl_TEN) >> 25; // bit 25 } return KErrNone; }