omap3530/shared/tps65950/tps65950.cpp
author Pat Downey <patd@symbian.org>
Thu, 15 Oct 2009 12:59:54 +0100
changeset 0 6663340f3fc9
child 51 254b9435d75e
permissions -rwxr-xr-x
Add EPL'd beagleboard code

// 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;
	}