diff -r 000000000000 -r 6663340f3fc9 omap3530/shared/tps65950/tps65950.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omap3530/shared/tps65950/tps65950.cpp Thu Oct 15 12:59:54 2009 +0100 @@ -0,0 +1,760 @@ +// Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "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: +// \omap3530\omap3530_assp\shared\tps65950\tps65950.cpp +// Access driver for TPS65950 +// This file is part of the Beagle Base port +// + +#include +#include +#include +//#include +#include +#include +#include "tps65950.h" + + +GLREF_C TInt InitInterrupts(); + + +const TUint KGroupCount = 5; + +// One handle per group on TPS65950 +static I2c::THandle I2cHandle[ KGroupCount ]; + +// One DCB per group +static I2c::TConfigPb TheDcb[ KGroupCount ]; + +// I2C transfer object +enum TPhase + { + EAddressPb, + EDataPb + }; +static I2c::TTransferPb TheTransferPb[2]; + +// Group index to Group number +static const TUint8 KGroupIndexToGroupNumber[ KGroupCount ] = + { 0x12, 0x48, 0x49, 0x4a, 0x4b }; + +// Queue of requests +static SDblQue TheQueue; + +// Current state +enum TState + { + EIdle, + EPending, + EReading, + EWriting, + EUnprotectPhase0 + }; +static TState CurrentState; +TPS65950::TReq* CurrentPhaseReq; +TPS65950::TReq* PreviousPhaseReq; + +LOCAL_D TUint8 IsInitialized; // auto-cleared to EFalse + +const TUint8 KUnprotectPhase0Data = 0xCE; +const TUint8 KUnprotectPhase1Data = 0xEC; + +static const TUint8 KUnprotectData[4] = + { + TPS65950::Register::PROTECT_KEY bitand TPS65950::Register::KRegisterMask, KUnprotectPhase0Data, + TPS65950::Register::PROTECT_KEY bitand TPS65950::Register::KRegisterMask, KUnprotectPhase1Data, + }; + +static const TUint8 KProtectData[2] = + { + TPS65950::Register::PROTECT_KEY bitand TPS65950::Register::KRegisterMask, 0 + }; + +static TUint8 TempWriteBuf[2]; + +// Spinlock to protect queue when adding or removing items +//static TSpinLock QueueLock(TSpinLock::EOrderGenericIrqLow1+1); +static TSpinLock QueueLock(); + +GLDEF_D TDfcQue* TheDfcQue; + +const TInt KDfcQuePriority = 27; +_LIT( KDriverNameDes, "tps65950" ); + +TInt TheProtectionUsageCount = 0; + + + +LOCAL_C void InternalPanic( TInt aLine ) + { + Kern::Fault( "tps65950", aLine ); + } + +LOCAL_C void PanicClient( TPS65950::TPanic aPanic ) + { + Kern::PanicCurrentThread( KDriverNameDes, aPanic ); + } + +namespace TPS65950 +{ +void CompletionDfcFunction( TAny* aParam ); +void SyncDfcFunction( TAny* aParam ); +void DummyDfcFunction( TAny* aParam ); +static TDfc CompletionDfc( CompletionDfcFunction, NULL, 1 ); +static TDfc DummyDfc( CompletionDfcFunction, NULL, 1 ); + +FORCE_INLINE TReq& ReqFromLink( SDblQueLink* aLink ) + { + return *_LOFF( aLink, TReq, iLink ); + } + +inline TBool AtomicSetPendingWasIdle() + { + // atomic if (CurrentState == idleState) {CurrentState=EPending, returns TRUE} else {idleState=CurrentState, CurrentState unchanged, return FALSE} + TState idleState = EIdle; // required for atomic comparison + //TBool wasIdle = __e32_atomic_cas_ord32( (TUint32*)&CurrentState, (TUint32*)&idleState, EPending ); + //return wasIdle; + + if (CurrentState == idleState) + { + CurrentState = EPending; + return ETrue; + } + else + { + idleState = CurrentState; + return EFalse; + } + + } + + +void StartRead( TReq& aReq ) + { + __KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:StartRead(@%x) [%x:%x]", + &aReq, + KGroupIndexToGroupNumber[ aReq.iRegister >> Register::KGroupShift ], + aReq.iRegister bitand Register::KRegisterMask ) ); + + //__e32_atomic_store_ord32( &CurrentState, EReading ); + CurrentState = EReading; + + TheTransferPb[ EAddressPb ].iData = (TUint8*)&aReq.iRegister; // low byte is register address + TheTransferPb[ EDataPb ].iType = I2c::TTransferPb::ERead; + TheTransferPb[ EDataPb ].iData = &aReq.iReadValue; + __DEBUG_ONLY( aReq.iReadValue = 0xEE ); + TheTransferPb[ EDataPb ].iLength = 1; + TheTransferPb[ EAddressPb ].iResult = KErrNone; + TheTransferPb[ EDataPb ].iResult = KErrNone; + + TUint groupIndex = aReq.iRegister >> Register::KGroupShift; + I2c::TransferA( I2cHandle[ groupIndex ], TheTransferPb[ EAddressPb ] ); + + __KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:StartRead(@%x)", &aReq ) ); + } + +void StartWrite( TReq& aReq ) + { + __KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:StartWrite(@%x) [%x:%x]<-%x", + &aReq, + KGroupIndexToGroupNumber[ aReq.iRegister >> Register::KGroupShift ], + aReq.iRegister bitand Register::KRegisterMask, + aReq.iWriteValue ) ); + + //__e32_atomic_store_ord32( &CurrentState, EWriting ); + CurrentState = EWriting; + + TempWriteBuf[0] = aReq.iRegister bitand Register::KRegisterMask; + TempWriteBuf[1] = aReq.iWriteValue; + TheTransferPb[ EDataPb ].iType = I2c::TTransferPb::EWrite; + TheTransferPb[ EDataPb ].iData = &TempWriteBuf[0]; + TheTransferPb[ EDataPb ].iLength = 2; + TheTransferPb[ EDataPb ].iResult = KErrNone; + + TUint groupIndex = aReq.iRegister >> Register::KGroupShift; + I2c::TransferA( I2cHandle[ groupIndex ], TheTransferPb[ EDataPb ] ); + + __KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:StartWrite(@%x)", &aReq ) ); + } + +void StartUnprotectPhase0( TReq& aReq ) + { + __KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:StartUnprotectPhase0(@%x)", &aReq ) ); + + //__e32_atomic_store_ord32( &CurrentState, EUnprotectPhase0 ); + CurrentState = EUnprotectPhase0; + + TheTransferPb[ EDataPb ].iType = I2c::TTransferPb::EWrite; + TheTransferPb[ EDataPb ].iData = &KUnprotectData[0]; + TheTransferPb[ EDataPb ].iLength = 2; + TheTransferPb[ EDataPb ].iResult = KErrNone; + + const TUint groupIndex = Register::PROTECT_KEY >> Register::KGroupShift; + I2c::TransferA( I2cHandle[ groupIndex ], TheTransferPb[ EDataPb ] ); + + __KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:StartUnprotectPhase0(@%x)", &aReq ) ); + } + +void StartUnprotectPhase1( TReq& aReq ) + { + __KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:StartUnprotectPhase1(@%x)", &aReq ) ); + + // Set state to writing so that it will complete as a normal write + //__e32_atomic_store_ord32( &CurrentState, EWriting ); + CurrentState = EWriting; + + TheTransferPb[ EDataPb ].iData = &KUnprotectData[2]; + TheTransferPb[ EDataPb ].iResult = KErrNone; + + const TUint groupIndex = Register::PROTECT_KEY >> Register::KGroupShift; + I2c::TransferA( I2cHandle[ groupIndex ], TheTransferPb[ EDataPb ] ); + + __KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:StartUnprotectPhase1(@%x)", &aReq ) ); + } + +void StartProtect( TReq& aReq ) + { + __KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:StartProtect(@%x)", &aReq ) ); + + //__e32_atomic_store_ord32( &CurrentState, EWriting ); + CurrentState = EWriting; + + TheTransferPb[ EDataPb ].iType = I2c::TTransferPb::EWrite; + TheTransferPb[ EDataPb ].iData = &KProtectData[0]; + TheTransferPb[ EDataPb ].iLength = 2; + TheTransferPb[ EDataPb ].iResult = KErrNone; + + const TUint groupIndex = Register::PROTECT_KEY >> Register::KGroupShift; + I2c::TransferA( I2cHandle[ groupIndex ], TheTransferPb[ EDataPb ] ); + + __KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:StartWrite(@%x)", &aReq ) ); + } + + +void StartRequest() + { + __KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:StartRequest(%d)", CurrentState ) ); + __ASSERT_DEBUG( EPending == CurrentState, InternalPanic( __LINE__ ) ); + + // We don't need to take lock here because we're currently idle so it's not possible + // for there to be a change in which item is queue head. The link pointers of the + // head item could change if another thread is queueing a new request, but that doesn't + // affect any of the fields we care about here + __ASSERT_DEBUG( !TheQueue.IsEmpty(), InternalPanic( __LINE__ ) ); + + if( !CurrentPhaseReq ) + { + PreviousPhaseReq = NULL; + CurrentPhaseReq = &ReqFromLink( TheQueue.First() ); + } + + FOREVER + { + if( !CurrentPhaseReq ) + { + __ASSERT_DEBUG( PreviousPhaseReq, InternalPanic( __LINE__ ) ); + + // we didn't find any phases to execute, so complete request + // by faking a write completion on the previous phase + CurrentPhaseReq = PreviousPhaseReq; + //__e32_atomic_store_ord32( &CurrentState, EWriting ); + CurrentState = EWriting; + + // Queue DFC instead of calling directly to avoid recursion if multiple items on queue + // complete without any action + CompletionDfc.Enque(); + break; + } + else + { + TReq::TAction action = CurrentPhaseReq->iAction; + + __KTRACE_OPT( KTPS65950, Kern::Printf( "=TPS65950:StartRequest:req@%x:a=%x", CurrentPhaseReq, action ) ); + + if( (TReq::ERead == action) || (TReq::EClearSet == action) ) + { + StartRead( *CurrentPhaseReq ); + break; + } + else if( TReq::EWrite == action ) + { + StartWrite( *CurrentPhaseReq ); + break; + } + else if( TReq::EDisableProtect == action ) + { + if( ++TheProtectionUsageCount == 1 ) + { + // Currently protected, start an unprotect sequence + StartUnprotectPhase0( *CurrentPhaseReq ); + break; + } + else + { + goto move_to_next_phase; + } + } + else if( TReq::ERestoreProtect == action ) + { + if( --TheProtectionUsageCount == 0 ) + { + StartProtect( *CurrentPhaseReq ); + break; + } + else + { + move_to_next_phase: + // already unprotected, skip to next phase + CurrentPhaseReq->iResult = KErrNone; + PreviousPhaseReq = CurrentPhaseReq; + CurrentPhaseReq = CurrentPhaseReq->iNextPhase; + } + } + else + { + InternalPanic( __LINE__ ); + } + } + } + + + __KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:StartRequest(%d)", CurrentState ) ); + } + +void DummyDfcFunction( TAny* /*aParam*/ ) + { + __KTRACE_OPT( KTPS65950, Kern::Printf( "TPS65950:DummyDFC(%d)", CurrentState ) ); + } + +void CompletionDfcFunction( TAny* /*aParam*/ ) + { + __KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:DFC(%d)", CurrentState ) ); + __ASSERT_DEBUG( EIdle != CurrentState, InternalPanic( __LINE__ ) ); + __ASSERT_DEBUG( CurrentPhaseReq, InternalPanic( __LINE__ ) ); + + TInt result = TheTransferPb[ EDataPb ].iResult; + if( KErrNone != TheTransferPb[ EAddressPb ].iResult ) + { + result = TheTransferPb[ EAddressPb ].iResult; + } + + TReq& req = *CurrentPhaseReq; + TBool completed = ETrue; + + if( KErrNone == result) + { + if( EReading == CurrentState ) + { + __KTRACE_OPT( KTPS65950, Kern::Printf( "=TPS65950:DFC:Read [%x:%x]=%x", + KGroupIndexToGroupNumber[ req.iRegister >> Register::KGroupShift ], + req.iRegister bitand Register::KRegisterMask, + req.iReadValue ) ); + + if( TReq::EClearSet == req.iAction) + { + // Start write phase of a ClearSet + req.iWriteValue = (req.iReadValue bitand ~req.iClearMask) bitor req.iSetMask; + StartWrite( req ); + completed = EFalse; + } + } + else if( EUnprotectPhase0 == CurrentState ) + { + StartUnprotectPhase1( req ); + completed = EFalse; + } + } + + if( completed || (KErrNone != result) ) + { + // Read or write, protect has completed, or final write stage of a ClearSet or unprotect, or error + PreviousPhaseReq = CurrentPhaseReq; + CurrentPhaseReq = req.iNextPhase; + + if( CurrentPhaseReq ) + { + // start next phase + //__e32_atomic_store_ord32( &CurrentState, EPending ); + CurrentState = EPending; + StartRequest(); + } + else + { + //__e32_atomic_store_ord32( &CurrentState, EIdle ); + CurrentState = EIdle; + // From now a concurrent ExecAsync() can start a new request if it adds an item to the queue + + // remove item from queue and complete + TUint irq = __SPIN_LOCK_IRQSAVE( QueueLock ); + ReqFromLink( TheQueue.First() ).iLink.Deque(); + TBool queueEmpty = TheQueue.IsEmpty(); + __SPIN_UNLOCK_IRQRESTORE( QueueLock, irq ); + + // If queue was empty inside spinlock but an ExecAsync() adds an item before the if statement below, + // the ExecAsync() will start the new request + if( !queueEmpty ) + { + if( AtomicSetPendingWasIdle() ) + { + // ExecAsync didn't start a request + StartRequest(); + } + } + + // Notify client of completion + req.iResult = result; + if( req.iCompletionDfc ) + { + req.iCompletionDfc->Enque(); + } + } + } + + __KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:DFC(%d)", CurrentState ) ); + } + +// Used to complete synchronous operations +void SyncDfcFunction( TAny* aParam ) + { + NKern::FSSignal( reinterpret_cast( aParam ) ); + } + + +EXPORT_C void ExecAsync( TReq& aRequest ) + { + __KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:ExecAsync(@%x)", &aRequest ) ); + + __ASSERT_DEBUG( (TUint)aRequest.iAction <= TReq::ERestoreProtect, PanicClient( EBadAction ) ); + __ASSERT_DEBUG( (TReq::EDisableProtect == aRequest.iAction) + || (TReq::ERestoreProtect == aRequest.iAction) + || (((TUint)aRequest.iRegister >> Register::KGroupShift) < KGroupCount), PanicClient( EBadGroup ) ); + + TUint irq = __SPIN_LOCK_IRQSAVE( QueueLock ); + TheQueue.Add( &aRequest.iLink ); + __SPIN_UNLOCK_IRQRESTORE( QueueLock, irq ); + + if( AtomicSetPendingWasIdle() ) + { + StartRequest(); + } + + __KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:ExecAsync" ) ); + } + +EXPORT_C TInt WriteSync( TUint16 aRegister, TUint8 aValue ) + { + __ASSERT_NO_FAST_MUTEX; + + NFastSemaphore sem; + TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 ); + TReq req; + req.iRegister = aRegister; + req.iAction = TReq::EWrite; + req.iCompletionDfc = &dfc; + req.iWriteValue = aValue; + req.iNextPhase = NULL; + + NKern::FSSetOwner( &sem, NULL ); + ExecAsync( req ); + NKern::FSWait( &sem ); + + return req.iResult; + } + +EXPORT_C TInt ReadSync( TUint16 aRegister, TUint8& aValue ) + { + __ASSERT_NO_FAST_MUTEX; + + NFastSemaphore sem; + TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 ); + TReq req; + req.iRegister = aRegister; + req.iAction = TReq::ERead; + req.iCompletionDfc = &dfc; + req.iNextPhase = NULL; + + NKern::FSSetOwner( &sem, NULL ); + ExecAsync( req ); + NKern::FSWait( &sem ); + + aValue = req.iReadValue; + return req.iResult; + } + +EXPORT_C TInt ClearSetSync( TUint16 aRegister, TUint8 aClearMask, TUint8 aSetMask ) + { + __ASSERT_NO_FAST_MUTEX; + + NFastSemaphore sem; + TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 ); + TReq req; + req.iRegister = aRegister; + req.iAction = TReq::EClearSet; + req.iCompletionDfc = &dfc; + req.iClearMask = aClearMask; + req.iSetMask = aSetMask; + req.iNextPhase = NULL; + + NKern::FSSetOwner( &sem, NULL ); + ExecAsync( req ); + NKern::FSWait( &sem ); + + return req.iResult; + } + +EXPORT_C TInt DisableProtect() + { + __ASSERT_NO_FAST_MUTEX; + + NFastSemaphore sem; + TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 ); + TReq req; + req.iAction = TReq::EDisableProtect; + req.iCompletionDfc = &dfc; + req.iNextPhase = NULL; + + NKern::FSSetOwner( &sem, NULL ); + ExecAsync( req ); + NKern::FSWait( &sem ); + + return req.iResult; + } + +EXPORT_C TInt RestoreProtect() + { + __ASSERT_NO_FAST_MUTEX; + + NFastSemaphore sem; + TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 ); + TReq req; + req.iAction = TReq::ERestoreProtect; + req.iCompletionDfc = &dfc; + req.iNextPhase = NULL; + + NKern::FSSetOwner( &sem, NULL ); + ExecAsync( req ); + NKern::FSWait( &sem ); + + return req.iResult; + } + + +TInt Init() + { + // Create DFC queue + TInt r = Kern::DfcQCreate( TheDfcQue, KDfcQuePriority, &KDriverNameDes ); + if( KErrNone != r ) + { + return r; + } + + TPS65950::CompletionDfc.SetDfcQ( TheDfcQue ); + TPS65950::DummyDfc.SetDfcQ( TheDfcQue ); + + // Open I2c handles + for( TInt i = 0; i < KGroupCount; ++i ) + { + TheDcb[i].iUnit = I2c::E1; // Master / slave + TheDcb[i].iRole = I2c::EMaster; + TheDcb[i].iMode = I2c::E7Bit; + TheDcb[i].iExclusiveClient = NULL; + TheDcb[i].iRate = I2c::E400K; + TheDcb[i].iOwnAddress = 0x01; + TheDcb[i].iDfcQueue = TheDfcQue; + TheDcb[i].iDeviceAddress = KGroupIndexToGroupNumber[i]; + + I2cHandle[i] = I2c::Open( TheDcb[i] ); + if( I2cHandle[i] < 0 ) + { + return I2cHandle[i]; + } + } + + // Setup transfer linked list + TheTransferPb[ EAddressPb ].iType = I2c::TTransferPb::EWrite; // address write + TheTransferPb[ EAddressPb ].iLength = 1; + TheTransferPb[ EAddressPb ].iCompletionDfc = &TPS65950::DummyDfc; + TheTransferPb[ EAddressPb ].iNextPhase = &TheTransferPb[ EDataPb ]; + TheTransferPb[ EDataPb ].iCompletionDfc = &TPS65950::CompletionDfc; + TheTransferPb[ EDataPb ].iNextPhase = NULL; + + return r; + } + +inline TInt BcdToDecimal( TUint8 aBcd ) + { + return ( aBcd bitand 0xF ) + ( (aBcd >> 4) * 10); + } + +inline TUint8 DecimalToBcd( TInt aDecimal ) + { + TUint tens = (aDecimal / 10); + return ( tens << 4 ) + ( aDecimal - tens ); + } + +EXPORT_C TInt GetRtcData( TRtcTime& aTime ) + { + __ASSERT_NO_FAST_MUTEX; + + NFastSemaphore sem; + TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 ); + TReq req[8]; // 9 stages to the operation + req[0].iRegister = RTC_CTRL_REG::Addr; + req[0].iAction = TReq::EClearSet; + req[0].iSetMask = RTC_CTRL_REG::GET_TIME; + req[0].iClearMask = 0; + req[0].iCompletionDfc = NULL; + req[0].iNextPhase = &req[1]; + + req[1].iRegister = Register::SECONDS_REG; + req[1].iAction = TReq::ERead; + req[1].iCompletionDfc = NULL; + req[1].iNextPhase = &req[2]; + + req[2].iRegister = Register::MINUTES_REG; + req[2].iAction = TReq::ERead; + req[2].iCompletionDfc = NULL; + req[2].iNextPhase = &req[3]; + + req[3].iRegister = Register::HOURS_REG; + req[3].iAction = TReq::ERead; + req[3].iCompletionDfc = NULL; + req[3].iNextPhase = &req[4]; + + req[4].iRegister = Register::DAYS_REG; + req[4].iAction = TReq::ERead; + req[4].iCompletionDfc = NULL; + req[4].iNextPhase = &req[5]; + + req[5].iRegister = Register::MONTHS_REG; + req[5].iAction = TReq::ERead; + req[5].iCompletionDfc = NULL; + req[5].iNextPhase = &req[6]; + + req[6].iRegister = Register::YEARS_REG; + req[6].iAction = TReq::ERead; + req[6].iCompletionDfc = NULL; + req[6].iNextPhase = &req[7]; + + req[7].iRegister = RTC_CTRL_REG::Addr; + req[7].iAction = TReq::EClearSet; + req[7].iSetMask = 0; + req[7].iClearMask = RTC_CTRL_REG::GET_TIME; + req[7].iCompletionDfc = &dfc; + req[7].iNextPhase = NULL; + + NKern::FSSetOwner( &sem, NULL ); + ExecAsync( req[0] ); + NKern::FSWait( &sem ); + + aTime.iSecond = BcdToDecimal( req[1].iReadValue ); + aTime.iMinute = BcdToDecimal( req[2].iReadValue ); + aTime.iHour = BcdToDecimal( req[3].iReadValue ); + aTime.iDay = BcdToDecimal( req[4].iReadValue ); + aTime.iMonth = BcdToDecimal( req[5].iReadValue ); + aTime.iYear = BcdToDecimal( req[6].iReadValue ); + + return KErrNone; + } + +#define BCD0(a) ((a)%10) +#define BCD1(a) (((a)/10)<<4) +#define TOBCD(i) (BCD1(i)|BCD0(i)) + +EXPORT_C TInt SetRtcData( const TRtcTime& aTime ) + { + __ASSERT_NO_FAST_MUTEX; + + NFastSemaphore sem; + TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 ); + TReq req[8]; // 9 stages to the operation + req[0].iRegister = RTC_CTRL_REG::Addr; + req[0].iAction = TReq::EClearSet; + req[0].iSetMask = 0; + req[0].iClearMask = RTC_CTRL_REG::STOP_RTC; + req[0].iCompletionDfc = NULL; + req[0].iNextPhase = &req[1]; + + req[1].iRegister = Register::SECONDS_REG; + req[1].iAction = TReq::EWrite; + req[1].iWriteValue = DecimalToBcd( aTime.iSecond ); + req[1].iCompletionDfc = NULL; + req[1].iNextPhase = &req[2]; + + req[2].iRegister = Register::MINUTES_REG; + req[2].iAction = TReq::EWrite; + req[2].iWriteValue = DecimalToBcd( aTime.iMinute ); + req[2].iCompletionDfc = NULL; + req[2].iNextPhase = &req[3]; + + req[3].iRegister = Register::HOURS_REG; + req[3].iAction = TReq::EWrite; + req[3].iWriteValue = DecimalToBcd( aTime.iHour ); + req[3].iCompletionDfc = NULL; + req[3].iNextPhase = &req[4]; + + req[4].iRegister = Register::DAYS_REG; + req[4].iAction = TReq::EWrite; + req[4].iWriteValue = DecimalToBcd( aTime.iDay ); + req[4].iCompletionDfc = NULL; + req[4].iNextPhase = &req[5]; + + req[5].iRegister = Register::MONTHS_REG; + req[5].iAction = TReq::EWrite; + req[5].iWriteValue = DecimalToBcd( aTime.iMonth ); + req[5].iCompletionDfc = NULL; + req[5].iNextPhase = &req[6]; + + req[6].iRegister = Register::YEARS_REG; + req[6].iAction = TReq::EWrite; + req[6].iWriteValue = DecimalToBcd( aTime.iYear ); + req[6].iCompletionDfc = NULL; + req[6].iNextPhase = &req[7]; + + req[7].iRegister = RTC_CTRL_REG::Addr; + req[7].iAction = TReq::EClearSet; + req[7].iSetMask = RTC_CTRL_REG::STOP_RTC; + req[7].iClearMask = 0; + req[7].iCompletionDfc = &dfc; + req[7].iNextPhase = NULL; + + NKern::FSSetOwner( &sem, NULL ); + ExecAsync( req[0] ); + NKern::FSWait( &sem ); + + return KErrNone; + } + +EXPORT_C TBool Initialized() + { + return IsInitialized; + } + +} // namespace TPS65950 + + + + +DECLARE_STANDARD_EXTENSION() + { + TInt r = TPS65950::Init(); + if( KErrNone == r ) + { + r = InitInterrupts(); + } + + IsInitialized = ( KErrNone == r ); + + return r; + } +