navienginebsp/naviengine_assp/csi/csi_master.cpp
changeset 0 5de814552237
equal deleted inserted replaced
-1:000000000000 0:5de814552237
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 #include <drivers/iic.h>
       
    21 #include <drivers/iic_channel.h>
       
    22 #include <assp/naviengine/naviengine_priv.h>
       
    23 #include <drivers/gpio.h>
       
    24 #include "csi_psl.h"
       
    25 #include "csi_master.h"
       
    26 
       
    27 #include "hcrconfig.h"
       
    28 #include "hcrconfig_csi.h"
       
    29 
       
    30 // This method ensures, that all Timers have been canceled..
       
    31 // interrupts disabled prior to completing the request.
       
    32 // This method is used to complete request and notify PIL in various situations.
       
    33 void DCsiChannelMaster::ExitComplete(TInt aErr, TBool aComplete /*= ETrue*/)
       
    34 	{
       
    35 	__KTRACE_OPT(KIIC, Kern::Printf("ExitComplete, r %d, complete %d", aErr, aComplete));
       
    36 
       
    37 	// make sure we've disabled ints and canceled dfcs/timers..
       
    38 	// Disable interrupts for CSI
       
    39 	Interrupt::Disable(iInterruptId);
       
    40 
       
    41 	// cancel timers and DFCs..
       
    42 	CancelTimeOut();
       
    43 	iHwGuardTimer.Cancel();
       
    44 	iTransferEndDfc.Cancel();
       
    45 
       
    46 	// change state to EIdle..
       
    47 	iState = EIdle;
       
    48 
       
    49 	// complete the request..calling the PIL method
       
    50 	if(aComplete)
       
    51 		{
       
    52 		CompleteRequest(aErr);
       
    53 		}
       
    54 	}
       
    55 
       
    56 // this is call-back for iHwGuard timer. It is called in the ISR context
       
    57 // if the iHwGuardTimer expires.
       
    58 // It will change the iTransactionStatus to KErrTimedOut to allow exiting from the while-loop..
       
    59 void DCsiChannelMaster::TimeoutCallback(TAny* aPtr)
       
    60 	{
       
    61 	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelMaster::TimeoutCallback"));
       
    62 	DCsiChannelMaster *a = (DCsiChannelMaster*) aPtr;
       
    63 	a->iTransactionStatus = KErrTimedOut;
       
    64 	}
       
    65 
       
    66 // This method is called by the PIL in the case of timeout for the transaction expiration.
       
    67 // The PIL will call CompleteRequest() after this function returns, so we need only to clean-up
       
    68 // and de-assert the SS line.
       
    69 TInt DCsiChannelMaster::HandleSlaveTimeout()
       
    70 	{
       
    71 	__KTRACE_OPT(KIIC, Kern::Printf("HandleSlaveTimeout"));
       
    72 
       
    73 	// make sure, that CSIE bit is cleared (disable the interface)
       
    74 	AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, KHtCSIModeEnable, 0);
       
    75 
       
    76 	// stop the driver's operation..
       
    77 	ExitComplete(KErrTimedOut, EFalse);
       
    78 
       
    79 	// bring the CS signal pin back to inactive state..
       
    80 	GPIO::SetOutputState(iSSPin, iSSPinActiveStateOff);
       
    81 
       
    82 	return KErrTimedOut;
       
    83 	}
       
    84 
       
    85 //DFC for TransferComplete
       
    86 void DCsiChannelMaster::TransferEndDfc(TAny* aPtr)
       
    87 	{
       
    88 	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelMaster::TransferEndDfc"));
       
    89 	DCsiChannelMaster *a = (DCsiChannelMaster*) aPtr;
       
    90 
       
    91 	// we are still receiving the data, so must wait until the end of the transmission
       
    92 	// start the guard timer, which - in case of the following while got stucked - will
       
    93 	// unblock this dfc by changing iTransactionStatus
       
    94 	a->iTransactionStatus = KErrNone;
       
    95 
       
    96 	a->iHwGuardTimer.OneShot(NKern::TimerTicks(a->iHwTimeoutValue));
       
    97 
       
    98 	// active wait until the transfer has finished
       
    99 	while((AsspRegister::Read32(a->iChannelBase + KHoCSIModeControl) & KHtCSIModeTransferState) &&
       
   100 	      (a->iTransactionStatus == KErrNone));
       
   101 
       
   102 	// bring the CS signal pin back to inactive state, but only if this is not an extended transaction,
       
   103 	// in which case we want to leave the bus alone so that the multiple transactions making up the
       
   104 	// extended transaction become one big transaction as far as the bus is concerned
       
   105 	if (!(a->iCurrTransaction->Flags() & KTransactionWithMultiTransc))
       
   106 		{
       
   107 		GPIO::SetOutputState(a->iSSPin, a->iSSPinActiveStateOff);
       
   108 		}
       
   109 
       
   110 	// clear CSIE bit..
       
   111 	AsspRegister::Modify32(a->iChannelBase + KHoCSIModeControl, KHtCSIModeEnable, 0);
       
   112 
       
   113 	// check if the the guard timer or transaction timer hasn't expired..
       
   114 	if(a->iTransactionStatus != KErrNone)
       
   115 		{
       
   116 		__KTRACE_OPT(KIIC, Kern::Printf("CsiChannelMaster::TransferEndDfc(): Transaction timed-out"));
       
   117 		a->ExitComplete(a->iTransactionStatus); // report the error situation..
       
   118 		return;
       
   119 		}
       
   120 	else
       
   121 		{
       
   122 		a->iHwGuardTimer.Cancel();
       
   123 		}
       
   124 
       
   125 	// drain the Rx FIFO buffer (there might be one item left)
       
   126 	if(a->iOperation.iOp.iIsReceiving)
       
   127 		{
       
   128 		if(AsspRegister::Read32(a->iChannelBase + KHoCSIIFifoL) &&
       
   129 		  (a->iRxDataEnd - a->iRxData >= a->iWordSize))
       
   130 			{
       
   131 			TUint16 val = AsspRegister::Read32(a->iChannelBase + KHoCSIIFifo);
       
   132 
       
   133 			// we're big-endian.. (AB)..
       
   134 			// so in 16bit mode we need to read MSB first..
       
   135 			if(a->iWordSize > 1)
       
   136 				{
       
   137 				*a->iRxData = val >> 8; // MSB shifted down..
       
   138 				*(a->iRxData + 1) = val & 0xff; // LSB..
       
   139 				}
       
   140 			else
       
   141 				{
       
   142 				*a->iRxData = val;
       
   143 				}
       
   144 
       
   145 			// increment the pointer..
       
   146 			a->iRxData += a->iWordSize;
       
   147 			}
       
   148 		}
       
   149 	// else - we don't care about the read data, it will be flushed before the next transfer..
       
   150 
       
   151 	// check, if there are more transfers in this transaction
       
   152 	if(a->iState == EBusy)
       
   153 		{
       
   154 		TInt err = a->ProcessNextTransfers();
       
   155 
       
   156 		// if for any reason coudln't start next transfer-complete the transaction with err..
       
   157 		if(err != KErrNone)
       
   158 			{
       
   159 			a->ExitComplete(err);
       
   160 			}
       
   161 		}
       
   162 	}
       
   163 
       
   164 // ISR Handler
       
   165 void DCsiChannelMaster::CsiIsr(TAny* aPtr)
       
   166 	{
       
   167 	DCsiChannelMaster *a = (DCsiChannelMaster*) aPtr;
       
   168 
       
   169 	// read the interrupt flags - to see, what was causing the interrupt..
       
   170 	TUint32 status = AsspRegister::Read32(a->iChannelBase + KHoCSIIntStatus);
       
   171 
       
   172 	// process TEND end interrupts
       
   173 	// this ISR happens every time ONE unit has been transfered..
       
   174 	if(status & KHtCSIIntStatusTEnd)
       
   175 		{
       
   176 		// clear TxEnd interrupt..
       
   177 		AsspRegister::Write32(a->iChannelBase + KHoCSIIntStatus, KHtCSIIntStatusTEnd);
       
   178 
       
   179 		if(a->iTxData == a->iTxDataEnd)
       
   180 			{
       
   181 			// if the Tx FIFO is empty (this was the last item transferred)
       
   182 			// confirm that the transfer was completed successfully:
       
   183 			// - set the transfer status as KErrNone
       
   184 			// - disable interrupts..
       
   185 			// - queue a DFC, which will finish the Tx-asserting/de-asserting CS line
       
   186 			// and start another transfer in the transaction or complete transaction
       
   187 			if(!AsspRegister::Read32(a->iChannelBase + KHoCSIOFifoL))
       
   188 				{
       
   189 				Interrupt::Disable(a->iInterruptId);
       
   190 				a->iTransferEndDfc.Add();
       
   191 				}
       
   192 			}
       
   193 		else
       
   194 			{
       
   195 			// if tere's more data to be sent - copy next item to the FIFO window register.
       
   196 			// if we are in 'receive-only' mode - (e.g. simple read request) we're only
       
   197 			// sending '0' (or other value defined as KValueSentOnRead) - to generate a clock for the slave.
       
   198 			if(a->iOperation.iOp.iIsTransmitting)
       
   199 				{
       
   200 				// copy data to the FIFO..
       
   201 				TUint16 val;
       
   202 
       
   203 				// in 16bit mode we need to write two bytes as once MSB first..
       
   204 				if(a->iWordSize > 1)
       
   205 					{
       
   206 					val = (*a->iTxData) << 8; // MSB shifted up..
       
   207 					val |= *(a->iTxData + 1) & 0xff; // LSB..
       
   208 					}
       
   209 				else
       
   210 					{
       
   211 					val = *a->iTxData;
       
   212 					}
       
   213 
       
   214 				// write this value to the register..
       
   215 				AsspRegister::Write32(a->iChannelBase + KHoCSIOFifo, val);
       
   216 
       
   217 				// increment the pointer..
       
   218 				a->iTxData += a->iWordSize;
       
   219 				}
       
   220 			}
       
   221 		} //end of TXEnd processing
       
   222 
       
   223 	// process receive threshold interrupt
       
   224 	if(status & KHtCSIIntStatusRxTrgIE)
       
   225 		{
       
   226 		// read data from the FIFO ..
       
   227 		if(a->iOperation.iOp.iIsReceiving)
       
   228 			{
       
   229 			while(AsspRegister::Read32(a->iChannelBase + KHoCSIIFifoL))
       
   230 				{
       
   231 				// if there's still some place in the buffer - put it into buffer..
       
   232 				if((a->iRxDataEnd - a->iRxData) >= a->iWordSize)
       
   233 					{
       
   234 					// copy data from the FIFO if tere's more space in the buffer
       
   235 					TUint16 val = AsspRegister::Read32(a->iChannelBase + KHoCSIIFifo);
       
   236 
       
   237 					// we're big-endian.. (AB)..
       
   238 					// so in 16bit mode we need to read MSB first..
       
   239 					if(a->iWordSize > 1)
       
   240 						{
       
   241 						*a->iRxData = val >> 8; // MSB shifted down..
       
   242 						*(a->iRxData + 1) = val & 0xff; // LSB..
       
   243 						}
       
   244 					else
       
   245 						{
       
   246 						*a->iRxData = val;
       
   247 						}
       
   248 					}
       
   249 				else
       
   250 					{
       
   251 					// overrun, i.e Slave has sent more data than expected by the client
       
   252 					// (e.g. too small buffer size for the transmission)
       
   253 					a->iTransactionStatus = KErrOverflow;
       
   254 					break;
       
   255 					}
       
   256 
       
   257 				// increment the pointer..
       
   258 				a->iRxData += a->iWordSize;
       
   259 				}
       
   260 			}
       
   261 		else
       
   262 			{
       
   263 			// or drop the data, writing 0 to the FIFOL register
       
   264 			AsspRegister::Write32(a->iChannelBase + KHoCSIIFifoL, 0);
       
   265 			}
       
   266 
       
   267 		// if we are in the 'half-duplex' 'receive only' mode,
       
   268 		// once the receive buffer is full we are to finish the transmission..
       
   269 		if((a->iOperation.iValue == TCsiOperationType::EReceiveOnly) &&
       
   270 		   (a->iRxDataEnd == a->iRxData))
       
   271 			{
       
   272 			Interrupt::Disable(a->iInterruptId);
       
   273 			a->iTransferEndDfc.Add();
       
   274 			}
       
   275 
       
   276 		// Clear the  RxThreshold interrupt
       
   277 		AsspRegister::Write32(a->iChannelBase + KHoCSIIntStatus, KHtCSIIntStatusRxTrgIE);
       
   278 
       
   279 		} // end of reception processing..
       
   280 	}
       
   281 
       
   282 // constructor 1-st stage
       
   283 DCsiChannelMaster::DCsiChannelMaster(TInt aChannelNumber, TBusType aBusType, TChannelDuplex aChanDuplex) :
       
   284 	DIicBusChannelMaster(aBusType, aChanDuplex), // !!call overloaded base class constructor..
       
   285 	iTransferEndDfc(TransferEndDfc, this, KCsiDfcPriority),
       
   286 	iHwGuardTimer(TimeoutCallback, this)
       
   287 	{
       
   288     iHwTimeoutValue = -1;
       
   289 	iSSPin = 0;
       
   290 	iChannelNumber = aChannelNumber; //Set the iChannelNumber of the Base Class
       
   291 	iState = EIdle;
       
   292 	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelMaster::DCsiChannelMaster: iChannelNumber = %d", iChannelNumber));
       
   293 	}
       
   294 
       
   295 // 2nd stage construction..
       
   296 TInt DCsiChannelMaster::DoCreate()
       
   297 	{
       
   298 	__KTRACE_OPT(KIIC, Kern::Printf("\nDCsiChannelMaster::DoCreate() ch: %d \n", iChannelNumber)); //__THREAD_AND_CPU;
       
   299 
       
   300 	TInt32 interruptId;
       
   301 	TUint32 channelBase;
       
   302 	
       
   303 	HCR::TSettingId settingId;
       
   304 	settingId.iCat = KHcrCat_MHA_Interrupt;
       
   305 
       
   306 	HCR::TSettingId channelBaseId;
       
   307 	channelBaseId.iCat = KHcrCat_MHA_HWBASE;
       
   308 
       
   309 	TInt r = KErrNone;
       
   310 	switch(iChannelNumber)
       
   311 		{
       
   312 		case 0:
       
   313 			settingId.iKey = KHcrKey_Interrupt_CSI0;
       
   314 			channelBaseId.iKey = KHcrKey_HwBase_CSI0;
       
   315 			break;
       
   316 		case 1:
       
   317 			settingId.iKey = KHcrKey_Interrupt_CSI1;
       
   318 			channelBaseId.iKey = KHcrKey_HwBase_CSI1;
       
   319 			break;
       
   320 		default:
       
   321 			__KTRACE_OPT(KIIC, Kern::Printf("Wrong ChannelNumber specified (%d)", iChannelNumber));
       
   322 			return KErrArgument;
       
   323 		}
       
   324 
       
   325 	r = HCR::GetUInt(channelBaseId, channelBase);
       
   326 	iChannelBase = channelBase;
       
   327 
       
   328 	if(r != KErrNone)
       
   329 		{
       
   330 		__KTRACE_OPT(KIIC, Kern::Printf("Failed to read HCR setting for category = %d and key = %d\n", channelBaseId.iCat, channelBaseId.iKey));
       
   331 		return r;
       
   332 		}
       
   333 
       
   334 	r = HCR::GetInt(settingId, interruptId);
       
   335 	if(r != KErrNone)
       
   336 		{
       
   337 		__KTRACE_OPT(KIIC, Kern::Printf("Failed to read HCR setting for category = %d and key = %d\n", settingId.iCat, settingId.iKey));
       
   338 		return r;
       
   339 		}
       
   340 	
       
   341 	//Read the timeout value from HCR
       
   342 	//The value will not be changed during transaction, so it needs to be read only once from HCR
       
   343 	if(iHwTimeoutValue == -1) 
       
   344         {
       
   345         // csiTimeout values was not yet read from HCR; read it
       
   346         HCR::TSettingId settingId;
       
   347         settingId.iCat = KHcrCat_HWServ_CSI;
       
   348         settingId.iKey = KHcrKey_CSI_Timeout;
       
   349         r = HCR::GetInt(settingId, iHwTimeoutValue);
       
   350         if(r != KErrNone) 
       
   351             {
       
   352             __KTRACE_OPT(KIIC, Kern::Printf("Failed to read HCR setting for category = %d and key = %d\n", settingId.iCat, settingId.iKey));
       
   353             return r;
       
   354             }
       
   355         }
       
   356 
       
   357 
       
   358 	// Create kernel DFCQ (thread) for the driver..
       
   359 	if(!iDfcQ)
       
   360 		{
       
   361 		TBuf8<KMaxName> threadName (KSpiThreadName);
       
   362 		threadName.AppendNum(iChannelNumber);
       
   363 		TDynamicDfcQue* dynamicDfcQ;
       
   364 		r = Kern::DynamicDfcQCreate(dynamicDfcQ, KSpiThreadPriority, threadName);
       
   365 		if(r != KErrNone)
       
   366 			{
       
   367 			__KTRACE_OPT(KIIC, Kern::Printf("DFC Queue creation failed, ch: %d, r = %d\n", iChannelNumber, r));
       
   368 			return r;
       
   369 			}
       
   370 		iDfcQ = dynamicDfcQ;
       
   371 		}
       
   372 	
       
   373 	// PIL Base class initialization. This must!! be called prior to SetDfcQ(iDfcQ) ..
       
   374 	r = Init();
       
   375 	if(r == KErrNone)
       
   376 		{
       
   377 		// set iDFCQ
       
   378 		SetDfcQ(iDfcQ); // base class..
       
   379 		iTransferEndDfc.SetDfcQ(iDfcQ); // transfer-end DFC
       
   380 		
       
   381 #ifdef CPU_AFFINITY_ANY
       
   382 		NKern::ThreadSetCpuAffinity((NThread*)(iDfcQ->iThread), KCpuAffinityAny);
       
   383 #endif
       
   384 
       
   385 		// Bind the Interrupt.
       
   386 
       
   387 		iInterruptId = Interrupt::Bind(interruptId, CsiIsr, this);
       
   388 
       
   389 		// this returns interruptId or error code(err < 0)
       
   390 		if(iInterruptId < KErrNone)
       
   391 			{
       
   392 			__KTRACE_OPT(KIIC, Kern::Printf("ERROR: InterruptBind error.. %d", r));
       
   393 			r = iInterruptId;
       
   394 			iInterruptId = 0;
       
   395 			}
       
   396 		}
       
   397 
       
   398 	return r;
       
   399 	}
       
   400 
       
   401 // static method used to construct the DCsiChannelMaster object.
       
   402 // Export the channel creating function for client use in controller-less mode
       
   403 #ifdef STANDALONE_CHANNEL
       
   404 EXPORT_C
       
   405 #endif
       
   406 DCsiChannelMaster* DCsiChannelMaster::New(TInt aChannelNumber, const TBusType aBusType, const TChannelDuplex aChanDuplex)
       
   407 	{
       
   408 	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelMaster::NewL(): aChannelNumber = %d, BusType =%d", aChannelNumber, aBusType));
       
   409 	DCsiChannelMaster *pChan = new DCsiChannelMaster(aChannelNumber, aBusType, aChanDuplex);
       
   410 
       
   411 	TInt r = KErrNoMemory;
       
   412 
       
   413 	if(pChan)
       
   414 		{
       
   415 		r = pChan->DoCreate();
       
   416 		}
       
   417 	if(r != KErrNone)
       
   418 		{
       
   419 		delete pChan;
       
   420 		pChan = NULL;
       
   421 		}
       
   422 	return pChan;
       
   423 	}
       
   424 
       
   425 #ifdef STANDALONE_CHANNEL
       
   426 DCsiChannelMaster::~DCsiChannelMaster()
       
   427 	{
       
   428 	// This destructor will only be called in controller-less mode, when iDfcQ is a TDynamicDfcQ,
       
   429 	// In here, detroy the dfc queue and unbind the interrupt for next channel creation 	
       
   430 	
       
   431 	// stop the Hardware
       
   432 	// clear CISE bit..(disables CSI)
       
   433 	AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, KHtCSIModeEnable, 0);
       
   434 
       
   435 	// set CSIRST bit..
       
   436 	AsspRegister::Modify32(iChannelBase + KHoCSIControl, 0, KHtCSIControlCSIRst);
       
   437 
       
   438 	if(iInterruptId)
       
   439 	    {
       
   440 	    Interrupt::Unbind(iInterruptId);
       
   441 	    }
       
   442 	if(iDfcQ)
       
   443 		{
       
   444 		((TDynamicDfcQue*)iDfcQ)->Destroy();
       
   445 		}
       
   446 	}
       
   447 #endif
       
   448 
       
   449 // this method compares if the previous transaction header and slave-select(chip-select) pin are different
       
   450 // If configuration is the same - HW will not be re-initialized. It also makes a copy of the new header
       
   451 // and new pin number used to configure the interface.
       
   452 TBool DCsiChannelMaster::TransConfigDiffersFromPrev()
       
   453 	{
       
   454 	TConfigSpiBufV01* headerBuf = (TConfigSpiBufV01*) (GetTransactionHeader(iCurrTransaction));
       
   455 	TConfigSpiV01 &spiHeader = (*headerBuf)();
       
   456 
       
   457 	// the busId - has a SlaveAddress which in the case of SPI is a SlaveSelect pin (GPIO pin number)
       
   458 	TUint32 busId = ((TIicBusTransaction*)iCurrTransaction)->GetBusId();
       
   459 
       
   460 	// get the slave address
       
   461 	TUint16 csPin;
       
   462 	csPin = GET_SLAVE_ADDR(busId);
       
   463 
       
   464 	// compare it to the previous configuration..
       
   465 	if(csPin                            != iSSPin ||
       
   466 	   spiHeader.iWordWidth             != iSpiHeader.iWordWidth ||
       
   467 	   spiHeader.iClkSpeedHz            != iSpiHeader.iClkSpeedHz ||
       
   468 	   spiHeader.iClkMode               != iSpiHeader.iClkMode ||
       
   469 	   spiHeader.iTimeoutPeriod         != iSpiHeader.iTimeoutPeriod ||
       
   470 	   spiHeader.iBitOrder              != iSpiHeader.iBitOrder ||
       
   471 	   spiHeader.iTransactionWaitCycles != iSpiHeader.iTransactionWaitCycles ||
       
   472 	   spiHeader.iSSPinActiveMode       != iSpiHeader.iSSPinActiveMode)
       
   473 		{
       
   474 		iSSPin = csPin; // copy CsPin number.
       
   475 		iSpiHeader = spiHeader; // copy the new config params
       
   476 #ifdef _DEBUG
       
   477 		DumpConfiguration(spiHeader, iSSPin);
       
   478 #endif
       
   479 		return ETrue;
       
   480 		}
       
   481 
       
   482 	return EFalse;
       
   483 	}
       
   484 
       
   485 // Validates various fields in the transaction header
       
   486 // this pure-virtual method is called by the PIL in the context of the
       
   487 // client's thread - whenever he makes a call to QueueTransaction().
       
   488 TInt DCsiChannelMaster::CheckHdr(TDes8* aHdrBuff)
       
   489 	{
       
   490 	TInt r = KErrNone;
       
   491 
       
   492 	if(!aHdrBuff)
       
   493 		{
       
   494 		r = KErrArgument;
       
   495 		}
       
   496 	else
       
   497 		{
       
   498 		TConfigSpiBufV01* headerBuf = (TConfigSpiBufV01*) aHdrBuff;
       
   499 		TConfigSpiV01 &spiHeader = (*headerBuf)();
       
   500 
       
   501 		if(spiHeader.iTransactionWaitCycles > 15) // (can be 0 - 15)
       
   502 			{
       
   503 			__KTRACE_OPT(KIIC, Kern::Printf("iTransactionWaitCycles not supported"));
       
   504 			r = KErrNotSupported;
       
   505 			}
       
   506 		else
       
   507 			{
       
   508 			if(spiHeader.iWordWidth != ESpiWordWidth_8 &&
       
   509 			spiHeader.iWordWidth != ESpiWordWidth_16)
       
   510 				{
       
   511 				__KTRACE_OPT(KIIC, Kern::Printf("iWordWidth not supported"));
       
   512 				r = KErrNotSupported;
       
   513 				}
       
   514 			else
       
   515 				{
       
   516 				if(spiHeader.iClkSpeedHz != 130000  &&
       
   517 				   spiHeader.iClkSpeedHz != 260000  &&
       
   518                    spiHeader.iClkSpeedHz != 521000  &&
       
   519                    spiHeader.iClkSpeedHz != 1040000 &&
       
   520                    spiHeader.iClkSpeedHz != 2080000 &&
       
   521                    spiHeader.iClkSpeedHz != 4170000 &&
       
   522                    spiHeader.iClkSpeedHz != 16670000)
       
   523 					{
       
   524 					__KTRACE_OPT(KIIC, Kern::Printf("iClock not supported"));
       
   525 					r = KErrNotSupported;
       
   526 					}
       
   527 				}
       
   528 			}
       
   529 		}
       
   530 	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelMaster::CheckHdr() r %d", r));
       
   531 	return r;
       
   532 	}
       
   533 
       
   534 // Initializes the hardware with the data provided in the transaction and slave-address field
       
   535 TInt DCsiChannelMaster::ConfigureInterface()
       
   536 	{
       
   537 	__KTRACE_OPT(KIIC, Kern::Printf("ConfigureInterface()"));
       
   538 
       
   539 	HCR::TSettingId settingId;
       
   540 
       
   541 	// CSI initialization procedure:
       
   542 	// 1. clear CISE bit..
       
   543 	AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, KHtCSIModeEnable, 0);
       
   544 
       
   545 	// 2. wait until CIS_MODE.bit0 (CSOT) changes to 0
       
   546 	// start the GuardTimer before while-loop..
       
   547 	iTransactionStatus = KErrNone;
       
   548 
       
   549 	iHwGuardTimer.OneShot(NKern::TimerTicks(iHwTimeoutValue));
       
   550 
       
   551 	while((iTransactionStatus == KErrNone) &&
       
   552 	       AsspRegister::Read32(iChannelBase + KHoCSIModeControl) & KHtCSIModeTransferState);
       
   553 
       
   554 	// check if the the guard timer or transaction timer hasn't expired..
       
   555 	if(iTransactionStatus != KErrNone)
       
   556 		{
       
   557 		return KErrGeneral;
       
   558 		}
       
   559 	else
       
   560 		{
       
   561 		iHwGuardTimer.Cancel();
       
   562 		}
       
   563 
       
   564 	// 3. set CSIRST bit..
       
   565 	AsspRegister::Modify32(iChannelBase + KHoCSIControl, 0, KHtCSIControlCSIRst);
       
   566 
       
   567 	// 4. set KHoCSIClockSelect register..
       
   568 	TUint32 val = 0;
       
   569 
       
   570 	// CKP - ClocK Polarity (bit 4) 0: initial value is high, 1: initial val is low
       
   571 	// DAP - Clock phase select (bit 3) 0: 180 degree delay, 1: 0 degree delay
       
   572 	// @** don't use DAP=1 when iClock set to KHCSIClockValPCLKdiv4 (HW bug..see SoC errata)
       
   573 	switch(iSpiHeader.iClkMode)
       
   574 		{
       
   575 		case ESpiPolarityLowRisingEdge: // Active high, odd edges
       
   576 			val = KHtCSIClockSelectCKP; // CKP 1, DAP 0
       
   577 			break;
       
   578 		case ESpiPolarityLowFallingEdge: // Active high, even edges
       
   579 			val = KHtCSIClockSelectCKP | // CKP 1, DAP 1
       
   580 			      KHtCSIClockSelectDAP;
       
   581 			break;
       
   582 
       
   583 		case ESpiPolarityHighFallingEdge: // Active low,  odd edges
       
   584 			val = 0; // CKP 0, DAP 0
       
   585 			break;
       
   586 
       
   587 		case ESpiPolarityHighRisingEdge: // Active low,  even edges
       
   588 			val = KHtCSIClockSelectDAP; // CKP 0, DAP 1
       
   589 			break;
       
   590 		default:
       
   591 			break; // there's no default..no other value can be specified as it's an enum ;)
       
   592 		}
       
   593 
       
   594 	// set the clock..
       
   595 	switch(iSpiHeader.iClkSpeedHz)
       
   596 		{
       
   597 		case 130000:
       
   598 			val |= KHCSIClockValPCLKdiv512; //  1/512 PCLK (master mode)     130 kHz
       
   599 			break;
       
   600 		case 260000:
       
   601 			val |= KHCSIClockValPCLKdiv256; //  1/256 PCLK (master mode)     260 kHz
       
   602 			break;
       
   603 		case 521000:
       
   604 			val |= KHCSIClockValPCLKdiv128; //  1/128 PCLK (master mode)     521 kHz
       
   605 			break;
       
   606 		case 1040000:
       
   607 			val |= KHCSIClockValPCLKdiv64; //  1/64 PCLK (master mode) 1.04 MHz
       
   608 			break;
       
   609 		case 2080000:
       
   610 			val |= KHCSIClockValPCLKdiv32; //  1/32 PCLK (master mode) 2.08 MHz
       
   611 			break;
       
   612 		case 4170000:
       
   613 			val |= KHCSIClockValPCLKdiv16; //  1/16 PCLK (master mode) 4.17 MHz
       
   614 			break;
       
   615 		case 16670000:
       
   616 			if(val & KHtCSIClockSelectDAP) // see @**
       
   617 				{
       
   618 				__KTRACE_OPT(KIIC, Kern::Printf("Unsupported CLK/Clock mode"));
       
   619 				return KErrArgument;
       
   620 				}
       
   621 			val |= KHCSIClockValPCLKdiv4; //  1/4 PCLK (master mode)   16.67 MHz
       
   622 			break;
       
   623 		default:
       
   624 			return KErrNotSupported;
       
   625 		}
       
   626 
       
   627 	// set transaction wait time..
       
   628 	val |= (0xf & iSpiHeader.iTransactionWaitCycles) << KHsCSIModeTWait;
       
   629 
       
   630 	// and finally update the register
       
   631 	AsspRegister::Write32(iChannelBase + KHoCSIClockSelect, val);
       
   632 
       
   633 	// 5. clear KHtCSIControlCSIRst bit..
       
   634 	AsspRegister::Modify32(iChannelBase + KHoCSIControl, KHtCSIControlCSIRst, 0);
       
   635 
       
   636 	// 6. Set Mode Control register:
       
   637 	// Transmission and reception mode
       
   638 	val = KHtCSIModeTrEnable;
       
   639 
       
   640 	// Select transmit data length (8/16 bits)
       
   641 	if(iSpiHeader.iWordWidth == ESpiWordWidth_16)
       
   642 		{
       
   643 		iWordSize = 2;
       
   644 		val |= KHtCSIModeDataLen;
       
   645 		}
       
   646 	else
       
   647 		{
       
   648 		iWordSize = 1;
       
   649 		}
       
   650 
       
   651 	// Select Transfer direction (if set-LSB first)
       
   652 	if(iSpiHeader.iBitOrder == ELsbFirst)
       
   653 		{
       
   654 		val |= KHtCSIModeTransferDir;
       
   655 		}
       
   656 
       
   657 	// update the register
       
   658 	AsspRegister::Write32(iChannelBase + KHoCSIModeControl, val);
       
   659 
       
   660 	// 7. Set FIFO trigger levels
       
   661 	TUint8 csiFifoRxTrigerLvl;
       
   662 	
       
   663 	settingId.iCat = KHcrCat_HWServ_CSI;
       
   664 	settingId.iKey = KHcrKey_CSI_FifoRxTrigerLvl;
       
   665 	
       
   666 	TInt r = HCR::GetUInt(settingId, csiFifoRxTrigerLvl);
       
   667 	if(r != KErrNone) 
       
   668 		{
       
   669 		__KTRACE_OPT(KIIC, Kern::Printf("Failed to read HCR setting for category = %d and key = %d\n", settingId.iCat, settingId.iKey));
       
   670 		return r;
       
   671 		}
       
   672 	AsspRegister::Write32(iChannelBase + KHoCSIFifoTrgLvl, (csiFifoRxTrigerLvl << KHsCSIRxFifoTrgLvl));
       
   673 
       
   674 	// 8. Clear all interrupts
       
   675 	AsspRegister::Write32(iChannelBase + KHoCSIIntStatus, KInterruptsAll);
       
   676 
       
   677 	// 9. Set RxTrig permission and enable TEnd and RxTrg interrupts
       
   678 	AsspRegister::Write32(iChannelBase + KHoCSIControl, KHtCSIControlRxTrgEn |
       
   679 	                                                    KHtCSIControlTEndIE    |
       
   680 	                                                    KHtCSIControlRxTrgIE);
       
   681 
       
   682 	// 10. finally set CSIE bit
       
   683 	AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, 0, KHtCSIModeEnable);
       
   684 
       
   685 	// enable and configure GPIO pin - it is CS Pin used for the transmission..
       
   686 	// if specified different (e.g. 0) - iSSPin will be ignored during the transmission..
       
   687 	if(iSSPin < 1 || iSSPin > 32) // can be 1 - 32
       
   688 		{
       
   689 		__KTRACE_OPT(KIIC, Kern::Printf("Wrong pin number specified()"));
       
   690 		return KErrArgument;
       
   691 		}
       
   692 	else
       
   693 		{
       
   694 		GPIO::SetPinMode(iSSPin, GPIO::EEnabled);
       
   695 		GPIO::SetPinDirection(iSSPin, GPIO::EOutput);
       
   696 		GPIO::SetDebounceTime(iSSPin, 0);
       
   697 
       
   698 		// and set active high bit (KtCSPinHigh)
       
   699 		if(iSpiHeader.iSSPinActiveMode == ESpiCSPinActiveHigh)
       
   700 			{
       
   701 			iSSPinActiveStateOn = GPIO::EHigh;
       
   702 			iSSPinActiveStateOff = GPIO::ELow;
       
   703 			}
       
   704 		else
       
   705 			{
       
   706 			iSSPinActiveStateOn = GPIO::ELow;
       
   707 			iSSPinActiveStateOff = GPIO::EHigh;
       
   708 			}
       
   709 		}
       
   710 
       
   711 	// clear KHtCSIModeEnable.. it will be set to trigger the transmission in DoTransfer()
       
   712 	AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, KHtCSIModeEnable, 0);
       
   713 
       
   714 	return KErrNone;
       
   715 	}
       
   716 
       
   717 // This method starts data transfer - filling the Transmit FIFO and enabling the device (CSIE bit)
       
   718 TInt DCsiChannelMaster::DoTransfer(TInt8 *aBuff, TUint aNumOfBytes)
       
   719 	{
       
   720 	__KTRACE_OPT(KIIC, Kern::Printf("\nDCsiChannelMaster::DoTransfer()"));
       
   721 	__KTRACE_OPT(KIIC, Kern::Printf("Receiving %d, Transmitting %d", iOperation.iOp.iIsReceiving, iOperation.iOp.iIsTransmitting));
       
   722 
       
   723 	if(aNumOfBytes == 0) // wanted to transfer an empty buffer??
       
   724 		{
       
   725 		return KErrArgument;
       
   726 		}
       
   727 
       
   728 	// store current Tx buffer addresses - to use them later in the ISR,
       
   729 	// when re-filling the buffer if its level drops down to the threshold value..
       
   730 	iTxData = aBuff;
       
   731 	iTxDataEnd = (TInt8*) (aBuff + aNumOfBytes);
       
   732 	__KTRACE_OPT(KIIC, Kern::Printf("Tx: Start: %x, End %x, bytes %d\n\n", iTxData, iTxDataEnd, aNumOfBytes));
       
   733 
       
   734 	// ensure, we won't be sending until we've filled up the FIFO..
       
   735 	AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, KHtCSIModeEnable, 0);
       
   736 
       
   737 	// clean the FIFO..
       
   738 	AsspRegister::Write32(iChannelBase + KHoCSIOFifoL, 0);
       
   739 
       
   740 	// if we are transmitting - Add data to the FIFO..
       
   741 	if(iOperation.iOp.iIsTransmitting)
       
   742 		{
       
   743 		// Set mode to transmission and reception (Set TRMD)
       
   744 		AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, 0, KHtCSIModeTrEnable);
       
   745 
       
   746 		while(AsspRegister::Read32(iChannelBase + KHoCSIOFifoL) < KHwCSIFifoLMax && // until FIFO not full..
       
   747 		      iTxData != iTxDataEnd) // or whole data has been copied.
       
   748 			{
       
   749 			// copy data to the FIFO..
       
   750 			TUint16 val;
       
   751 
       
   752 			// in 16bit mode we need to write two bytes as once MSB first..
       
   753 			if(iWordSize > 1)
       
   754 				{
       
   755 				val = (*iTxData) << 8; // MSB shifted up..
       
   756 				val |= *(iTxData + 1) & 0xff; // LSB..
       
   757 				}
       
   758 			else
       
   759 				{
       
   760 				val = *iTxData;
       
   761 				}
       
   762 
       
   763 			// write this value to the register..
       
   764 			AsspRegister::Write32(iChannelBase + KHoCSIOFifo, val);
       
   765 
       
   766 			// increment the pointer.
       
   767 			iTxData += iWordSize;
       
   768 			}
       
   769 		}
       
   770 	else // we are starting receive transfer only..
       
   771 		{
       
   772 		// Set mode to reception only (clear TRMD)
       
   773 		AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, KHtCSIModeTrEnable, 0);
       
   774 		}
       
   775 
       
   776 	// change the SS line status - start of the transmission. This should be set back to high - after
       
   777 	// the transmission has been finished (iTransferEndDfc)
       
   778 	GPIO::SetOutputState(iSSPin, iSSPinActiveStateOn);
       
   779 
       
   780 	// enable interrupts..
       
   781 	Interrupt::Enable(iInterruptId);
       
   782 
       
   783 	// enable transmission..this will trigger the HW to start the transmission..
       
   784 	AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, 0, KHtCSIModeEnable);
       
   785 
       
   786 	return KErrNone;
       
   787 	}
       
   788 
       
   789 // this method starts the given transfer..
       
   790 TInt DCsiChannelMaster::StartTransfer(TIicBusTransfer* aTransferPtr, TUint8 aType)
       
   791 	{
       
   792 	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelMaster::StartTransfer()"));
       
   793 
       
   794 	TInt r = KErrNone;
       
   795 
       
   796 	switch(aType)
       
   797 		{
       
   798 		case TIicBusTransfer::EMasterWrite:
       
   799 			{
       
   800 			__KTRACE_OPT(KIIC, Kern::Printf("Starting EMasterWrite, duplex=%d", iFullDTransfer));
       
   801 
       
   802 			const TDes8* aBufPtr = GetTferBuffer(aTransferPtr);
       
   803 
       
   804 			__KTRACE_OPT(KIIC, Kern::Printf("Length %d, iWordSize %d", aBufPtr->Length(), iWordSize));
       
   805 
       
   806 			// set this flag - to indicate, that we'll be transmitting the data.
       
   807 			// if this is set to 0 prior to calling to DoTransfer() - only '0'(or KValueSentOnRead) values will be
       
   808 			// sent out of the interface (e.g. if only receiving from the slave - to generate the clock)
       
   809 			iOperation.iOp.iIsTransmitting = ETrue;
       
   810 
       
   811 			// initiate the transmission..
       
   812 			r = DoTransfer((TInt8 *) aBufPtr->Ptr(), aBufPtr->Length());
       
   813 
       
   814 			if(r != KErrNone)
       
   815 				{
       
   816 				__KTRACE_OPT(KIIC, Kern::Printf("Starting Write filed, r = %d", r));
       
   817 				}
       
   818 			break;
       
   819 			}
       
   820 		case TIicBusTransfer::EMasterRead:
       
   821 			{
       
   822 			__KTRACE_OPT(KIIC, Kern::Printf("Starting EMasterRead, duplex=%x", iFullDTransfer));
       
   823 
       
   824 			// store the current address and ending address for Reception- to use them later in the ISR and DFC
       
   825 			const TDes8* aBufPtr = GetTferBuffer(aTransferPtr);
       
   826 
       
   827 			iRxData = (TInt8*) aBufPtr->Ptr();
       
   828 			iRxDataEnd = (TInt8*) (iRxData + aBufPtr->Length());
       
   829 
       
   830 			__KTRACE_OPT(KIIC, Kern::Printf("Rx: Start: %x, End %x, bytes %d", iRxData, iRxDataEnd, aBufPtr->Length()));
       
   831 
       
   832 			// set the flag - that we're going to receive the data..
       
   833 			iOperation.iOp.iIsReceiving = ETrue;
       
   834 
       
   835 			// if this is half-duplex transfer.. (read-only)
       
   836 			// we still need to transmit '0' to generate CLK and SS signals for the Slave
       
   837 			if(!iFullDTransfer)
       
   838 				{
       
   839 				// make sure transmitting flag is cleared
       
   840 				iOperation.iOp.iIsTransmitting = EFalse;
       
   841 
       
   842 				// set pointers - as if we're transmitting the same amount of data..
       
   843 				r = DoTransfer((TInt8 *) aBufPtr->Ptr(), aBufPtr->Length());
       
   844 				}
       
   845 			}
       
   846 			break;
       
   847 		default:
       
   848 			{
       
   849 			__KTRACE_OPT(KIIC, Kern::Printf("Unsupported TrasactionType %x", aType));
       
   850 			r = KErrArgument;
       
   851 			break;
       
   852 			}
       
   853 		}
       
   854 
       
   855 	return r;
       
   856 	}
       
   857 
       
   858 // calling this method whenever a transfer has been finished - will process all transfers in the transaction
       
   859 TInt DCsiChannelMaster::ProcessNextTransfers()
       
   860 	{
       
   861 	// transfers are queued in linked list.. so just go through that list and start them
       
   862 	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelMaster::ProcessNextTransfers(),BUSY=%d", iState));
       
   863 
       
   864 	// clear flags..
       
   865 	iOperation.iValue = TCsiOperationType::ENop;
       
   866 
       
   867 	// in both cases - full-duplex - or simple half-duplex
       
   868 	// we need to flush the buffers for the transmission:
       
   869 	AsspRegister::Write32(iChannelBase + KHoCSIIFifoL, 0); // write 0 to FIFOL will drop data
       
   870 	AsspRegister::Write32(iChannelBase + KHoCSIOFifoL, 0); // write 0 to FIFOL will drop data
       
   871 
       
   872 	// if this is the first transfer in the transaction..(called from DoCreate)
       
   873 	if(iState == EIdle)
       
   874 		{
       
   875 		// Get the pointer to half-duplex transfer object..
       
   876 		iHalfDTransfer = GetTransHalfDuplexTferPtr(iCurrTransaction);
       
   877 
       
   878 		// Get the pointer to full-duplex transfer object..
       
   879 		iFullDTransfer = GetTransFullDuplexTferPtr(iCurrTransaction);
       
   880 
       
   881 		// from now on - our state is EBusy.
       
   882 		iState = EBusy;
       
   883 
       
   884 		// kick-off the transaction timer..
       
   885 		// it's default handler, run in ISR context will change the iTransactionStatus
       
   886 		// and queue TranferEndDfc (in the case if it wasn't queued) - this DFC
       
   887 		// will then finish transfer and report this error to the PIL.
       
   888 		__ASSERT_DEBUG(iSpiHeader.iTimeoutPeriod > 0, Kern::Fault("NE1_TB SPI: timeout value not set,line: %d", __LINE__));
       
   889 		__KTRACE_OPT(KIIC, Kern::Printf("Timeout for transaction %d", iSpiHeader.iTimeoutPeriod));
       
   890 		iTransactionStatus = KErrNone;
       
   891 		// Initiate the timer for the transaction. When it expires - PIL will call
       
   892 		// HandleSlaveTimeout() - which will stop the HW operations..
       
   893 		StartSlaveTimeOutTimer(iSpiHeader.iTimeoutPeriod);
       
   894 		// When the KIIC trace flag is enabled, we need cancel the transaction timeout,
       
   895 		// so that debug traces don't cause slave timer expiration.
       
   896 		__KTRACE_OPT(KIIC, CancelTimeOut());
       
   897 
       
   898 		}
       
   899 	else
       
   900 	// We continue with next transfer in the transaction..(Called from TransferEndDfc)
       
   901 		{
       
   902 		// Get the pointer the next half-duplex transfer object..
       
   903 		iHalfDTransfer = GetTferNextTfer(iHalfDTransfer);
       
   904 
       
   905 		// Get the pointer to the next half-duplex transfer object..
       
   906 		if(iFullDTransfer)
       
   907 			{
       
   908 			iFullDTransfer = GetTferNextTfer(iFullDTransfer);
       
   909 			}
       
   910 		}
       
   911 
       
   912 	// all of the transfers were completed, just notify the PIL and return.
       
   913 	// (if either Rx or Tx has not finished properly ExitComplete() would have been called
       
   914 	// from TransferEndDfc if there was an error during the transfer)
       
   915 	TInt r = KErrNone;
       
   916 	if(!iFullDTransfer && !iHalfDTransfer)
       
   917 		{
       
   918 		__KTRACE_OPT(KIIC, Kern::Printf("All transfers completed successfully"));
       
   919 		// complete the request..
       
   920 		ExitComplete(KErrNone);
       
   921 		}
       
   922 	else
       
   923 		{
       
   924 		// start transfers..
       
   925 		// if this is full-duplex transfer - we need to Start EMasterRead transfer first
       
   926 		// this is because buffer pointers and flags for this transfer type must be initialized
       
   927 		// prior to starting EMasterWrite (which always triggers the transmission start)
       
   928 		TInt8 hDTrType = (TInt8) GetTferType(iHalfDTransfer);
       
   929 
       
   930 		if(iFullDTransfer)
       
   931 			{
       
   932 			// if iHalfDTransfer is EMasterRead - start it first..
       
   933 			if(hDTrType == TIicBusTransfer::EMasterRead)
       
   934 				{
       
   935 				r = StartTransfer(iHalfDTransfer, TIicBusTransfer::EMasterRead);
       
   936 				if(r != KErrNone)
       
   937 					{
       
   938 					return r;
       
   939 					}
       
   940 				r = StartTransfer(iFullDTransfer, TIicBusTransfer::EMasterWrite);
       
   941 				}
       
   942 			else // hDTrType == TIicBusTransfer::EMasterWrite)
       
   943 				{
       
   944 				r = StartTransfer(iFullDTransfer, TIicBusTransfer::EMasterRead);
       
   945 				if(r != KErrNone)
       
   946 					{
       
   947 					return r;
       
   948 					}
       
   949 				r = StartTransfer(iHalfDTransfer, TIicBusTransfer::EMasterWrite);
       
   950 				}
       
   951 			}
       
   952 		else
       
   953 		// this is normal halfDuplex transfer - so just start it
       
   954 			{
       
   955 			r = StartTransfer(iHalfDTransfer, hDTrType);
       
   956 			}
       
   957 		}
       
   958 	return r;
       
   959 	}
       
   960 
       
   961 // Gateway function for PSL implementation - this method is an entry point - it is called by the PIL
       
   962 // to initiate the transaction. After finishing it's processing PSL calls CompleteRequest(error_status)
       
   963 TInt DCsiChannelMaster::DoRequest(TIicBusTransaction* aTransaction)
       
   964 	{
       
   965 	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelMaster::DoRequest (aTransaction=0x%x)\n", aTransaction));
       
   966 
       
   967 	// Check, if pointers are not NULL..
       
   968 	if(!aTransaction || !GetTransactionHeader(aTransaction))
       
   969 		{
       
   970 		return KErrArgument;
       
   971 		}
       
   972 
       
   973 	// Make sure if the PIL doesn't try to start another one- before we've confirmed the previous one..
       
   974 	if(iState != EIdle)
       
   975 		{
       
   976 		return KErrInUse;
       
   977 		}
       
   978 
       
   979 	// copy pointer to the transaction..
       
   980 	iCurrTransaction = aTransaction;
       
   981 
       
   982 	// check, if Hardware needs re-configuration
       
   983 	// (i.e. this transaction and SlaveAddress (iSSPin) are the same as for the previous one)
       
   984 	TInt r = KErrNone;
       
   985 	if(TransConfigDiffersFromPrev())
       
   986 		{
       
   987 		r = ConfigureInterface();
       
   988 		if(r != KErrNone)
       
   989 			{
       
   990 			iSSPin = 0;
       
   991 			return r;
       
   992 			}
       
   993 		}
       
   994 
       
   995 	// start processing transfers of this transaction.
       
   996 	r = ProcessNextTransfers();
       
   997 
       
   998 	return r;
       
   999 	}
       
  1000