--- /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 <e32cmn.h>
+#include <kernel.h>
+#include <nk_priv.h>
+//#include <e32atomics.h>
+#include <omap3530_i2c.h>
+#include <omap3530_i2creg.h>
+#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<NFastSemaphore*>( 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;
+ }
+