omap3530/shared/tps65950/tps65950.cpp
changeset 0 6663340f3fc9
child 51 254b9435d75e
equal deleted inserted replaced
-1:000000000000 0:6663340f3fc9
       
     1 // Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // \omap3530\omap3530_assp\shared\tps65950\tps65950.cpp
       
    15 // Access driver for TPS65950
       
    16 // This file is part of the Beagle Base port
       
    17 //
       
    18 
       
    19 #include <e32cmn.h>
       
    20 #include <kernel.h>
       
    21 #include <nk_priv.h>
       
    22 //#include <e32atomics.h>
       
    23 #include <omap3530_i2c.h>
       
    24 #include <omap3530_i2creg.h>
       
    25 #include "tps65950.h"
       
    26 
       
    27 
       
    28 GLREF_C TInt InitInterrupts();
       
    29 
       
    30 
       
    31 const TUint KGroupCount = 5;
       
    32 
       
    33 // One handle per group on TPS65950
       
    34 static I2c::THandle	I2cHandle[ KGroupCount ];
       
    35 
       
    36 // One DCB per group
       
    37 static I2c::TConfigPb TheDcb[ KGroupCount ];
       
    38 
       
    39 // I2C transfer object
       
    40 enum TPhase
       
    41 	{
       
    42 	EAddressPb,
       
    43 	EDataPb
       
    44 	};
       
    45 static I2c::TTransferPb TheTransferPb[2];
       
    46 
       
    47 // Group index to Group number
       
    48 static const TUint8 KGroupIndexToGroupNumber[ KGroupCount ] =
       
    49 	{ 0x12, 0x48, 0x49, 0x4a, 0x4b };
       
    50 
       
    51 // Queue of requests
       
    52 static SDblQue TheQueue;
       
    53 
       
    54 // Current state
       
    55 enum TState
       
    56 	{
       
    57 	EIdle,
       
    58 	EPending,
       
    59 	EReading,
       
    60 	EWriting,
       
    61 	EUnprotectPhase0
       
    62 	};
       
    63 static TState CurrentState;
       
    64 TPS65950::TReq* CurrentPhaseReq;
       
    65 TPS65950::TReq* PreviousPhaseReq;
       
    66 
       
    67 LOCAL_D TUint8 IsInitialized;	// auto-cleared to EFalse
       
    68 
       
    69 const TUint8	KUnprotectPhase0Data	= 0xCE;
       
    70 const TUint8	KUnprotectPhase1Data	= 0xEC;
       
    71 
       
    72 static const TUint8 KUnprotectData[4] =
       
    73 	{
       
    74 	TPS65950::Register::PROTECT_KEY bitand TPS65950::Register::KRegisterMask, KUnprotectPhase0Data,
       
    75 	TPS65950::Register::PROTECT_KEY bitand TPS65950::Register::KRegisterMask, KUnprotectPhase1Data,
       
    76 	};
       
    77 
       
    78 static const TUint8 KProtectData[2] =
       
    79 	{
       
    80 	TPS65950::Register::PROTECT_KEY bitand TPS65950::Register::KRegisterMask, 0
       
    81 	};
       
    82 
       
    83 static TUint8 TempWriteBuf[2];
       
    84 
       
    85 // Spinlock to protect queue when adding or removing items
       
    86 //static TSpinLock QueueLock(TSpinLock::EOrderGenericIrqLow1+1);
       
    87 static TSpinLock QueueLock();
       
    88 
       
    89 GLDEF_D TDfcQue*	TheDfcQue;
       
    90 
       
    91 const TInt KDfcQuePriority	= 27;
       
    92 _LIT( KDriverNameDes, "tps65950" );
       
    93 
       
    94 TInt TheProtectionUsageCount = 0;
       
    95 
       
    96 
       
    97 
       
    98 LOCAL_C void InternalPanic( TInt aLine )
       
    99 	{
       
   100 	Kern::Fault( "tps65950", aLine );
       
   101 	}
       
   102 
       
   103 LOCAL_C void PanicClient( TPS65950::TPanic aPanic )
       
   104 	{
       
   105 	Kern::PanicCurrentThread( KDriverNameDes, aPanic );
       
   106 	}
       
   107 
       
   108 namespace TPS65950
       
   109 {
       
   110 void CompletionDfcFunction( TAny* aParam );
       
   111 void SyncDfcFunction( TAny* aParam );
       
   112 void DummyDfcFunction( TAny* aParam );
       
   113 static TDfc CompletionDfc( CompletionDfcFunction, NULL, 1 );
       
   114 static TDfc DummyDfc( CompletionDfcFunction, NULL, 1 );
       
   115 
       
   116 FORCE_INLINE TReq& ReqFromLink( SDblQueLink* aLink )
       
   117 	{
       
   118 	return *_LOFF( aLink, TReq, iLink );
       
   119 	}
       
   120 
       
   121 inline TBool AtomicSetPendingWasIdle()
       
   122 	{
       
   123 	// atomic if (CurrentState == idleState) {CurrentState=EPending, returns TRUE} else {idleState=CurrentState, CurrentState unchanged, return FALSE}
       
   124 	TState idleState = EIdle;	// required for atomic comparison
       
   125 	//TBool wasIdle = __e32_atomic_cas_ord32( (TUint32*)&CurrentState, (TUint32*)&idleState, EPending );
       
   126 	//return wasIdle;
       
   127 	
       
   128 	if (CurrentState == idleState)
       
   129 		{
       
   130 		CurrentState = EPending;
       
   131 		return ETrue;
       
   132 		}
       
   133 	else
       
   134 		{
       
   135 		idleState = CurrentState;
       
   136 		return EFalse;
       
   137 		}
       
   138 	
       
   139 	}
       
   140 
       
   141 
       
   142 void StartRead( TReq& aReq )
       
   143 	{
       
   144 	__KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:StartRead(@%x) [%x:%x]",
       
   145 												&aReq,
       
   146 												KGroupIndexToGroupNumber[ aReq.iRegister >> Register::KGroupShift ],
       
   147 												aReq.iRegister bitand Register::KRegisterMask ) );
       
   148 
       
   149 	//__e32_atomic_store_ord32( &CurrentState, EReading );
       
   150 	CurrentState = EReading;
       
   151 	
       
   152 	TheTransferPb[ EAddressPb ].iData = (TUint8*)&aReq.iRegister;	// low byte is register address
       
   153 	TheTransferPb[ EDataPb ].iType = I2c::TTransferPb::ERead;
       
   154 	TheTransferPb[ EDataPb ].iData = &aReq.iReadValue;
       
   155 	__DEBUG_ONLY( aReq.iReadValue = 0xEE );
       
   156 	TheTransferPb[ EDataPb ].iLength = 1;
       
   157 	TheTransferPb[ EAddressPb ].iResult = KErrNone;
       
   158 	TheTransferPb[ EDataPb ].iResult = KErrNone;
       
   159 
       
   160 	TUint groupIndex = aReq.iRegister >> Register::KGroupShift;
       
   161 	I2c::TransferA( I2cHandle[ groupIndex ], TheTransferPb[ EAddressPb ] );
       
   162 
       
   163 	__KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:StartRead(@%x)", &aReq ) );
       
   164 	}
       
   165 
       
   166 void StartWrite( TReq& aReq )
       
   167 	{
       
   168 	__KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:StartWrite(@%x) [%x:%x]<-%x",
       
   169 												&aReq,
       
   170 												KGroupIndexToGroupNumber[ aReq.iRegister >> Register::KGroupShift ],
       
   171 												aReq.iRegister bitand Register::KRegisterMask,
       
   172 												aReq.iWriteValue ) );
       
   173 
       
   174 	//__e32_atomic_store_ord32( &CurrentState, EWriting );
       
   175 	CurrentState = EWriting;
       
   176 	
       
   177 	TempWriteBuf[0] = aReq.iRegister bitand Register::KRegisterMask;
       
   178 	TempWriteBuf[1] = aReq.iWriteValue;
       
   179 	TheTransferPb[ EDataPb ].iType = I2c::TTransferPb::EWrite;
       
   180 	TheTransferPb[ EDataPb ].iData = &TempWriteBuf[0];
       
   181 	TheTransferPb[ EDataPb ].iLength = 2;
       
   182 	TheTransferPb[ EDataPb ].iResult = KErrNone;
       
   183 
       
   184 	TUint groupIndex = aReq.iRegister >> Register::KGroupShift;
       
   185 	I2c::TransferA( I2cHandle[ groupIndex ], TheTransferPb[ EDataPb ] );
       
   186 
       
   187 	__KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:StartWrite(@%x)", &aReq ) );
       
   188 	}
       
   189 
       
   190 void StartUnprotectPhase0( TReq& aReq )
       
   191 	{
       
   192 	__KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:StartUnprotectPhase0(@%x)", &aReq ) );
       
   193 
       
   194 	//__e32_atomic_store_ord32( &CurrentState, EUnprotectPhase0 );
       
   195 	CurrentState = EUnprotectPhase0;
       
   196 	
       
   197 	TheTransferPb[ EDataPb ].iType = I2c::TTransferPb::EWrite;
       
   198 	TheTransferPb[ EDataPb ].iData = &KUnprotectData[0];
       
   199 	TheTransferPb[ EDataPb ].iLength = 2;
       
   200 	TheTransferPb[ EDataPb ].iResult = KErrNone;
       
   201 
       
   202 	const TUint groupIndex = Register::PROTECT_KEY >> Register::KGroupShift;
       
   203 	I2c::TransferA( I2cHandle[ groupIndex ], TheTransferPb[ EDataPb ] );
       
   204 
       
   205 	__KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:StartUnprotectPhase0(@%x)", &aReq ) );
       
   206 	}
       
   207 
       
   208 void StartUnprotectPhase1( TReq& aReq )
       
   209 	{
       
   210 	__KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:StartUnprotectPhase1(@%x)", &aReq ) );
       
   211 
       
   212 	// Set state to writing so that it will complete as a normal write
       
   213 	//__e32_atomic_store_ord32( &CurrentState, EWriting );
       
   214 	CurrentState = EWriting;
       
   215 	
       
   216 	TheTransferPb[ EDataPb ].iData = &KUnprotectData[2];
       
   217 	TheTransferPb[ EDataPb ].iResult = KErrNone;
       
   218 
       
   219 	const TUint groupIndex = Register::PROTECT_KEY >> Register::KGroupShift;
       
   220 	I2c::TransferA( I2cHandle[ groupIndex ], TheTransferPb[ EDataPb ] );
       
   221 
       
   222 	__KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:StartUnprotectPhase1(@%x)", &aReq ) );
       
   223 	}
       
   224 
       
   225 void StartProtect( TReq& aReq )
       
   226 	{
       
   227 	__KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:StartProtect(@%x)", &aReq ) );
       
   228 
       
   229 	//__e32_atomic_store_ord32( &CurrentState, EWriting );
       
   230 	CurrentState = EWriting;
       
   231 	
       
   232 	TheTransferPb[ EDataPb ].iType = I2c::TTransferPb::EWrite;
       
   233 	TheTransferPb[ EDataPb ].iData = &KProtectData[0];
       
   234 	TheTransferPb[ EDataPb ].iLength = 2;
       
   235 	TheTransferPb[ EDataPb ].iResult = KErrNone;
       
   236 
       
   237 	const TUint groupIndex = Register::PROTECT_KEY >> Register::KGroupShift;
       
   238 	I2c::TransferA( I2cHandle[ groupIndex ], TheTransferPb[ EDataPb ] );
       
   239 
       
   240 	__KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:StartWrite(@%x)", &aReq ) );
       
   241 	}
       
   242 
       
   243 
       
   244 void StartRequest()
       
   245 	{
       
   246 	__KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:StartRequest(%d)", CurrentState ) );
       
   247 	__ASSERT_DEBUG( EPending == CurrentState, InternalPanic( __LINE__ ) );
       
   248 
       
   249 	// We don't need to take lock here because we're currently idle so it's not possible
       
   250 	// for there to be a change in which item is queue head. The link pointers of the
       
   251 	// head item could change if another thread is queueing a new request, but that doesn't
       
   252 	// affect any of the fields we care about here
       
   253 	__ASSERT_DEBUG( !TheQueue.IsEmpty(), InternalPanic( __LINE__ ) );
       
   254 	
       
   255 	if( !CurrentPhaseReq )
       
   256 		{
       
   257 		PreviousPhaseReq = NULL;
       
   258 		CurrentPhaseReq = &ReqFromLink( TheQueue.First() );
       
   259 		}
       
   260 
       
   261 	FOREVER
       
   262 		{
       
   263 		if( !CurrentPhaseReq )
       
   264 			{
       
   265 			__ASSERT_DEBUG( PreviousPhaseReq, InternalPanic( __LINE__ ) );
       
   266 
       
   267 			// we didn't find any phases to execute, so complete request
       
   268 			// by faking a write completion on the previous phase
       
   269 			CurrentPhaseReq = PreviousPhaseReq;
       
   270 			//__e32_atomic_store_ord32( &CurrentState, EWriting );
       
   271 			CurrentState = EWriting;
       
   272 			
       
   273 			// Queue DFC instead of calling directly to avoid recursion if multiple items on queue
       
   274 			// complete without any action
       
   275 			CompletionDfc.Enque();
       
   276 			break;
       
   277 			}
       
   278 		else
       
   279 			{
       
   280 			TReq::TAction action = CurrentPhaseReq->iAction;
       
   281 
       
   282 			__KTRACE_OPT( KTPS65950, Kern::Printf( "=TPS65950:StartRequest:req@%x:a=%x", CurrentPhaseReq, action ) );
       
   283 
       
   284 			if( (TReq::ERead == action) || (TReq::EClearSet == action) )
       
   285 				{
       
   286 				StartRead( *CurrentPhaseReq );
       
   287 				break;
       
   288 				}
       
   289 			else if( TReq::EWrite == action )
       
   290 				{
       
   291 				StartWrite( *CurrentPhaseReq );
       
   292 				break;
       
   293 				}
       
   294 			else if( TReq::EDisableProtect == action )
       
   295 				{
       
   296 				if( ++TheProtectionUsageCount == 1 )
       
   297 					{
       
   298 					// Currently protected, start an unprotect sequence
       
   299 					StartUnprotectPhase0( *CurrentPhaseReq );
       
   300 					break;
       
   301 					}
       
   302 				else 
       
   303 					{
       
   304 					goto move_to_next_phase;
       
   305 					}
       
   306 				}
       
   307 			else if( TReq::ERestoreProtect == action )
       
   308 				{
       
   309 				if( --TheProtectionUsageCount == 0 )
       
   310 					{
       
   311 					StartProtect( *CurrentPhaseReq );
       
   312 					break;
       
   313 					}
       
   314 				else 
       
   315 					{
       
   316 	move_to_next_phase:
       
   317 					// already unprotected, skip to next phase
       
   318 					CurrentPhaseReq->iResult = KErrNone;
       
   319 					PreviousPhaseReq = CurrentPhaseReq;
       
   320 					CurrentPhaseReq = CurrentPhaseReq->iNextPhase;
       
   321 					}
       
   322 				}
       
   323 			else
       
   324 				{
       
   325 				InternalPanic( __LINE__ );
       
   326 				}
       
   327 			}
       
   328 		}
       
   329 
       
   330 
       
   331 	__KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:StartRequest(%d)", CurrentState ) );
       
   332 	}
       
   333 
       
   334 void DummyDfcFunction( TAny* /*aParam*/ )
       
   335 	{
       
   336 	__KTRACE_OPT( KTPS65950, Kern::Printf( "TPS65950:DummyDFC(%d)", CurrentState ) );
       
   337 	}
       
   338 
       
   339 void CompletionDfcFunction( TAny* /*aParam*/ )
       
   340 	{
       
   341 	__KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:DFC(%d)", CurrentState ) );
       
   342 	__ASSERT_DEBUG( EIdle != CurrentState, InternalPanic( __LINE__ ) );
       
   343 	__ASSERT_DEBUG( CurrentPhaseReq, InternalPanic( __LINE__ ) );
       
   344 
       
   345 	TInt result = TheTransferPb[ EDataPb ].iResult;
       
   346 	if( KErrNone != TheTransferPb[ EAddressPb ].iResult )
       
   347 		{
       
   348 		result = TheTransferPb[ EAddressPb ].iResult;
       
   349 		}
       
   350 
       
   351 	TReq& req = *CurrentPhaseReq;
       
   352 	TBool completed = ETrue;
       
   353 
       
   354 	if( KErrNone == result)
       
   355 		{
       
   356 		if( EReading == CurrentState )
       
   357 			{
       
   358 			__KTRACE_OPT( KTPS65950, Kern::Printf( "=TPS65950:DFC:Read [%x:%x]=%x",
       
   359 													KGroupIndexToGroupNumber[ req.iRegister >> Register::KGroupShift ],
       
   360 													req.iRegister bitand Register::KRegisterMask,
       
   361 													req.iReadValue ) );
       
   362 
       
   363 			if( TReq::EClearSet == req.iAction)
       
   364 				{
       
   365 				// Start write phase of a ClearSet
       
   366 				req.iWriteValue = (req.iReadValue bitand ~req.iClearMask) bitor req.iSetMask;
       
   367 				StartWrite( req );
       
   368 				completed = EFalse;
       
   369 				}
       
   370 			}
       
   371 		else if( EUnprotectPhase0 == CurrentState )
       
   372 			{
       
   373 			StartUnprotectPhase1( req );
       
   374 			completed = EFalse;
       
   375 			}
       
   376 		}
       
   377 
       
   378 	if( completed || (KErrNone != result) )
       
   379 		{
       
   380 		// Read or write, protect has completed, or final write stage of a ClearSet or unprotect, or error
       
   381 		PreviousPhaseReq = CurrentPhaseReq;
       
   382 		CurrentPhaseReq = req.iNextPhase;
       
   383 
       
   384 		if( CurrentPhaseReq )
       
   385 			{
       
   386 			// start next phase
       
   387 			//__e32_atomic_store_ord32( &CurrentState, EPending );
       
   388 			CurrentState = EPending;
       
   389 			StartRequest();
       
   390 			}
       
   391 		else
       
   392 			{
       
   393 			//__e32_atomic_store_ord32( &CurrentState, EIdle );
       
   394 			CurrentState = EIdle;
       
   395 			// From now a concurrent ExecAsync() can start a new request if it adds an item to the queue
       
   396 
       
   397 			// remove item from queue and complete
       
   398 			TUint irq = __SPIN_LOCK_IRQSAVE( QueueLock );
       
   399 			ReqFromLink( TheQueue.First() ).iLink.Deque();
       
   400 			TBool queueEmpty = TheQueue.IsEmpty();
       
   401 			__SPIN_UNLOCK_IRQRESTORE( QueueLock, irq );
       
   402 
       
   403 			// If queue was empty inside spinlock but an ExecAsync() adds an item before the if statement below,
       
   404 			// the ExecAsync() will start the new request
       
   405 			if( !queueEmpty )
       
   406 				{
       
   407 				if( AtomicSetPendingWasIdle() )
       
   408 					{
       
   409 					// ExecAsync didn't start a request
       
   410 					StartRequest();
       
   411 					}
       
   412 				}
       
   413 
       
   414 			// Notify client of completion
       
   415 			req.iResult = result;
       
   416 			if( req.iCompletionDfc )
       
   417 				{
       
   418 				req.iCompletionDfc->Enque();
       
   419 				}
       
   420 			}
       
   421 		}
       
   422 
       
   423 	__KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:DFC(%d)", CurrentState ) );
       
   424 	}
       
   425 
       
   426 // Used to complete synchronous operations
       
   427 void SyncDfcFunction( TAny* aParam )
       
   428 	{
       
   429 	NKern::FSSignal( reinterpret_cast<NFastSemaphore*>( aParam ) );
       
   430 	}
       
   431 
       
   432 
       
   433 EXPORT_C void ExecAsync( TReq& aRequest )
       
   434 	{
       
   435 	__KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:ExecAsync(@%x)", &aRequest ) );
       
   436 
       
   437 	__ASSERT_DEBUG( (TUint)aRequest.iAction <= TReq::ERestoreProtect, PanicClient( EBadAction ) );
       
   438 	__ASSERT_DEBUG( (TReq::EDisableProtect == aRequest.iAction) 
       
   439 					|| (TReq::ERestoreProtect == aRequest.iAction)
       
   440 					|| (((TUint)aRequest.iRegister >> Register::KGroupShift) < KGroupCount), PanicClient( EBadGroup ) );
       
   441 
       
   442 	TUint irq = __SPIN_LOCK_IRQSAVE( QueueLock );
       
   443 	TheQueue.Add( &aRequest.iLink );
       
   444 	__SPIN_UNLOCK_IRQRESTORE( QueueLock, irq );
       
   445 
       
   446 	if( AtomicSetPendingWasIdle() )
       
   447 		{
       
   448 		StartRequest();
       
   449 		}
       
   450 
       
   451 	__KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:ExecAsync" ) );
       
   452 	}
       
   453 
       
   454 EXPORT_C TInt WriteSync( TUint16 aRegister, TUint8 aValue )
       
   455 	{
       
   456 	__ASSERT_NO_FAST_MUTEX;
       
   457 
       
   458 	NFastSemaphore sem;
       
   459 	TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 );
       
   460 	TReq req;
       
   461 	req.iRegister = aRegister;
       
   462 	req.iAction = TReq::EWrite;
       
   463 	req.iCompletionDfc = &dfc;
       
   464 	req.iWriteValue = aValue;
       
   465 	req.iNextPhase = NULL;
       
   466 
       
   467 	NKern::FSSetOwner( &sem, NULL );
       
   468 	ExecAsync( req );
       
   469 	NKern::FSWait( &sem );
       
   470 
       
   471 	return req.iResult;
       
   472 	}
       
   473 
       
   474 EXPORT_C TInt ReadSync( TUint16 aRegister, TUint8& aValue )
       
   475 	{
       
   476 	__ASSERT_NO_FAST_MUTEX;
       
   477 
       
   478 	NFastSemaphore sem;
       
   479 	TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 );
       
   480 	TReq req;
       
   481 	req.iRegister = aRegister;
       
   482 	req.iAction = TReq::ERead;
       
   483 	req.iCompletionDfc = &dfc;
       
   484 	req.iNextPhase = NULL;
       
   485 
       
   486 	NKern::FSSetOwner( &sem, NULL );
       
   487 	ExecAsync( req );
       
   488 	NKern::FSWait( &sem );
       
   489 
       
   490 	aValue = req.iReadValue;
       
   491 	return req.iResult;
       
   492 	}
       
   493 
       
   494 EXPORT_C TInt ClearSetSync( TUint16 aRegister, TUint8 aClearMask, TUint8 aSetMask )
       
   495 	{
       
   496 	__ASSERT_NO_FAST_MUTEX;
       
   497 
       
   498 	NFastSemaphore sem;
       
   499 	TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 );
       
   500 	TReq req;
       
   501 	req.iRegister = aRegister;
       
   502 	req.iAction = TReq::EClearSet;
       
   503 	req.iCompletionDfc = &dfc;
       
   504 	req.iClearMask = aClearMask;
       
   505 	req.iSetMask = aSetMask;
       
   506 	req.iNextPhase = NULL;
       
   507 
       
   508 	NKern::FSSetOwner( &sem, NULL );
       
   509 	ExecAsync( req );
       
   510 	NKern::FSWait( &sem );
       
   511 
       
   512 	return req.iResult;
       
   513 	}
       
   514 
       
   515 EXPORT_C TInt DisableProtect()
       
   516 	{
       
   517 	__ASSERT_NO_FAST_MUTEX;
       
   518 
       
   519 	NFastSemaphore sem;
       
   520 	TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 );
       
   521 	TReq req;
       
   522 	req.iAction = TReq::EDisableProtect;
       
   523 	req.iCompletionDfc = &dfc;
       
   524 	req.iNextPhase = NULL;
       
   525 
       
   526 	NKern::FSSetOwner( &sem, NULL );
       
   527 	ExecAsync( req );
       
   528 	NKern::FSWait( &sem );
       
   529 
       
   530 	return req.iResult;
       
   531 	}
       
   532 
       
   533 EXPORT_C TInt RestoreProtect()
       
   534 	{
       
   535 	__ASSERT_NO_FAST_MUTEX;
       
   536 
       
   537 	NFastSemaphore sem;
       
   538 	TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 );
       
   539 	TReq req;
       
   540 	req.iAction = TReq::ERestoreProtect;
       
   541 	req.iCompletionDfc = &dfc;
       
   542 	req.iNextPhase = NULL;
       
   543 
       
   544 	NKern::FSSetOwner( &sem, NULL );
       
   545 	ExecAsync( req );
       
   546 	NKern::FSWait( &sem );
       
   547 
       
   548 	return req.iResult;
       
   549 	}
       
   550 
       
   551 
       
   552 TInt Init()
       
   553 	{
       
   554 	// Create DFC queue
       
   555 	TInt r = Kern::DfcQCreate( TheDfcQue, KDfcQuePriority, &KDriverNameDes );
       
   556 	if( KErrNone != r )
       
   557 		{
       
   558 		return r;
       
   559 		}
       
   560 
       
   561 	TPS65950::CompletionDfc.SetDfcQ( TheDfcQue );
       
   562 	TPS65950::DummyDfc.SetDfcQ( TheDfcQue );
       
   563 
       
   564 	// Open I2c handles
       
   565 	for( TInt i = 0; i < KGroupCount; ++i )
       
   566 		{
       
   567 		TheDcb[i].iUnit = I2c::E1; // Master / slave
       
   568 		TheDcb[i].iRole = I2c::EMaster;
       
   569 		TheDcb[i].iMode = I2c::E7Bit;
       
   570 		TheDcb[i].iExclusiveClient = NULL;
       
   571 		TheDcb[i].iRate = I2c::E400K;
       
   572 		TheDcb[i].iOwnAddress = 0x01;
       
   573 		TheDcb[i].iDfcQueue = TheDfcQue;
       
   574 		TheDcb[i].iDeviceAddress = KGroupIndexToGroupNumber[i];
       
   575 
       
   576 		I2cHandle[i] = I2c::Open( TheDcb[i] );
       
   577 		if( I2cHandle[i] < 0 )
       
   578 			{
       
   579 			return I2cHandle[i];
       
   580 			}
       
   581 		}
       
   582 
       
   583 	// Setup transfer linked list
       
   584 	TheTransferPb[ EAddressPb ].iType = I2c::TTransferPb::EWrite;	// address write
       
   585 	TheTransferPb[ EAddressPb ].iLength = 1;
       
   586 	TheTransferPb[ EAddressPb ].iCompletionDfc = &TPS65950::DummyDfc;
       
   587 	TheTransferPb[ EAddressPb ].iNextPhase = &TheTransferPb[ EDataPb ];
       
   588 	TheTransferPb[ EDataPb ].iCompletionDfc = &TPS65950::CompletionDfc;
       
   589 	TheTransferPb[ EDataPb ].iNextPhase = NULL;
       
   590 
       
   591 	return r;
       
   592 	}
       
   593 
       
   594 inline TInt BcdToDecimal( TUint8 aBcd )
       
   595 	{
       
   596 	return ( aBcd bitand 0xF ) + ( (aBcd >> 4) * 10);
       
   597 	}
       
   598 
       
   599 inline TUint8 DecimalToBcd( TInt aDecimal )
       
   600 	{
       
   601 	TUint tens = (aDecimal / 10);
       
   602 	return ( tens << 4 ) + ( aDecimal - tens );
       
   603 	}
       
   604 
       
   605 EXPORT_C TInt GetRtcData( TRtcTime& aTime )
       
   606 	{
       
   607 	__ASSERT_NO_FAST_MUTEX;
       
   608 
       
   609 	NFastSemaphore sem;
       
   610 	TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 );
       
   611 	TReq req[8];	// 9 stages to the operation
       
   612 	req[0].iRegister = RTC_CTRL_REG::Addr;
       
   613 	req[0].iAction = TReq::EClearSet;
       
   614 	req[0].iSetMask = RTC_CTRL_REG::GET_TIME;
       
   615 	req[0].iClearMask = 0;
       
   616 	req[0].iCompletionDfc = NULL;
       
   617 	req[0].iNextPhase = &req[1];
       
   618 
       
   619 	req[1].iRegister = Register::SECONDS_REG;
       
   620 	req[1].iAction = TReq::ERead;
       
   621 	req[1].iCompletionDfc = NULL;
       
   622 	req[1].iNextPhase = &req[2];
       
   623 
       
   624 	req[2].iRegister = Register::MINUTES_REG;
       
   625 	req[2].iAction = TReq::ERead;
       
   626 	req[2].iCompletionDfc = NULL;
       
   627 	req[2].iNextPhase = &req[3];
       
   628 	
       
   629 	req[3].iRegister = Register::HOURS_REG;
       
   630 	req[3].iAction = TReq::ERead;
       
   631 	req[3].iCompletionDfc = NULL;
       
   632 	req[3].iNextPhase = &req[4];
       
   633 
       
   634 	req[4].iRegister = Register::DAYS_REG;
       
   635 	req[4].iAction = TReq::ERead;
       
   636 	req[4].iCompletionDfc = NULL;
       
   637 	req[4].iNextPhase = &req[5];
       
   638 
       
   639 	req[5].iRegister = Register::MONTHS_REG;
       
   640 	req[5].iAction = TReq::ERead;
       
   641 	req[5].iCompletionDfc = NULL;
       
   642 	req[5].iNextPhase = &req[6];
       
   643 
       
   644 	req[6].iRegister = Register::YEARS_REG;
       
   645 	req[6].iAction = TReq::ERead;
       
   646 	req[6].iCompletionDfc = NULL;
       
   647 	req[6].iNextPhase = &req[7];
       
   648 
       
   649 	req[7].iRegister = RTC_CTRL_REG::Addr;
       
   650 	req[7].iAction = TReq::EClearSet;
       
   651 	req[7].iSetMask = 0;
       
   652 	req[7].iClearMask = RTC_CTRL_REG::GET_TIME;
       
   653 	req[7].iCompletionDfc = &dfc;
       
   654 	req[7].iNextPhase = NULL;
       
   655 
       
   656 	NKern::FSSetOwner( &sem, NULL );
       
   657 	ExecAsync( req[0] );
       
   658 	NKern::FSWait( &sem );
       
   659 
       
   660 	aTime.iSecond = BcdToDecimal( req[1].iReadValue );
       
   661 	aTime.iMinute = BcdToDecimal( req[2].iReadValue );
       
   662 	aTime.iHour = BcdToDecimal( req[3].iReadValue );
       
   663 	aTime.iDay = BcdToDecimal( req[4].iReadValue );
       
   664 	aTime.iMonth = BcdToDecimal( req[5].iReadValue );
       
   665 	aTime.iYear = BcdToDecimal( req[6].iReadValue );
       
   666 
       
   667 	return KErrNone;
       
   668 	}
       
   669 
       
   670 #define BCD0(a) ((a)%10)
       
   671 #define BCD1(a) (((a)/10)<<4)
       
   672 #define TOBCD(i) (BCD1(i)|BCD0(i))
       
   673 
       
   674 EXPORT_C TInt SetRtcData( const TRtcTime& aTime )
       
   675 	{	
       
   676 	__ASSERT_NO_FAST_MUTEX;
       
   677 
       
   678 	NFastSemaphore sem;
       
   679 	TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 );
       
   680 	TReq req[8];	// 9 stages to the operation
       
   681 	req[0].iRegister = RTC_CTRL_REG::Addr;
       
   682 	req[0].iAction = TReq::EClearSet;
       
   683 	req[0].iSetMask = 0;
       
   684 	req[0].iClearMask = RTC_CTRL_REG::STOP_RTC;
       
   685 	req[0].iCompletionDfc = NULL;
       
   686 	req[0].iNextPhase = &req[1];
       
   687 
       
   688 	req[1].iRegister = Register::SECONDS_REG;
       
   689 	req[1].iAction = TReq::EWrite;
       
   690 	req[1].iWriteValue = DecimalToBcd( aTime.iSecond );
       
   691 	req[1].iCompletionDfc = NULL;
       
   692 	req[1].iNextPhase = &req[2];
       
   693 
       
   694 	req[2].iRegister = Register::MINUTES_REG;
       
   695 	req[2].iAction = TReq::EWrite;
       
   696 	req[2].iWriteValue = DecimalToBcd( aTime.iMinute );
       
   697 	req[2].iCompletionDfc = NULL;
       
   698 	req[2].iNextPhase = &req[3];
       
   699 	
       
   700 	req[3].iRegister = Register::HOURS_REG;
       
   701 	req[3].iAction = TReq::EWrite;
       
   702 	req[3].iWriteValue = DecimalToBcd( aTime.iHour );
       
   703 	req[3].iCompletionDfc = NULL;
       
   704 	req[3].iNextPhase = &req[4];
       
   705 
       
   706 	req[4].iRegister = Register::DAYS_REG;
       
   707 	req[4].iAction = TReq::EWrite;
       
   708 	req[4].iWriteValue = DecimalToBcd( aTime.iDay );
       
   709 	req[4].iCompletionDfc = NULL;
       
   710 	req[4].iNextPhase = &req[5];
       
   711 
       
   712 	req[5].iRegister = Register::MONTHS_REG;
       
   713 	req[5].iAction = TReq::EWrite;
       
   714 	req[5].iWriteValue = DecimalToBcd( aTime.iMonth );
       
   715 	req[5].iCompletionDfc = NULL;
       
   716 	req[5].iNextPhase = &req[6];
       
   717 
       
   718 	req[6].iRegister = Register::YEARS_REG;
       
   719 	req[6].iAction = TReq::EWrite;
       
   720 	req[6].iWriteValue = DecimalToBcd( aTime.iYear );
       
   721 	req[6].iCompletionDfc = NULL;
       
   722 	req[6].iNextPhase = &req[7];
       
   723 
       
   724 	req[7].iRegister = RTC_CTRL_REG::Addr;
       
   725 	req[7].iAction = TReq::EClearSet;
       
   726 	req[7].iSetMask = RTC_CTRL_REG::STOP_RTC;
       
   727 	req[7].iClearMask = 0;
       
   728 	req[7].iCompletionDfc = &dfc;
       
   729 	req[7].iNextPhase = NULL;
       
   730 
       
   731 	NKern::FSSetOwner( &sem, NULL );
       
   732 	ExecAsync( req[0] );
       
   733 	NKern::FSWait( &sem );
       
   734 
       
   735 	return KErrNone;
       
   736 	}
       
   737 
       
   738 EXPORT_C TBool Initialized()
       
   739 	{
       
   740 	return IsInitialized;
       
   741 	}
       
   742 
       
   743 } // namespace TPS65950
       
   744 
       
   745 
       
   746 
       
   747 
       
   748 DECLARE_STANDARD_EXTENSION()
       
   749 	{
       
   750 	TInt r = TPS65950::Init();
       
   751 	if( KErrNone == r )
       
   752 		{
       
   753 		r = InitInterrupts();
       
   754 		}
       
   755 
       
   756 	IsInitialized = ( KErrNone == r );
       
   757 
       
   758 	return r;
       
   759 	}
       
   760