navienginebsp/naviengine_assp/csi/csi_slave.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 "csi_psl.h"
       
    24 #include "csi_slave.h"
       
    25 
       
    26 #include "hcrconfig.h"
       
    27 #include "hcrconfig_csi.h"
       
    28 
       
    29 // the timeout period to wait for a response from the client.
       
    30 // We can't predict the frequency, at which the Master will be sending us data,
       
    31 // it can be from 130kHz (which is 16,25bytes/ms) up to 16,67MHz(2083 bytes/ms).
       
    32 // Timeout is set for the slowest transfer - for the time that the 32 bytes Tx FIFO would be emptied
       
    33 // (Rx FIFO filled), so 2ms.
       
    34 const TInt KClientWaitTime = 2; // when debugging might set up to KMaxWaitTime
       
    35 
       
    36 // set of interrupt flags used by the driver
       
    37 const TUint32 KSlaveInterruptFlags =
       
    38 			KHtCSIControlSSDnIE	 | // SS signal negative-edge interrupt enable
       
    39 	        KHtCSIControlSSUpIE  | // SS signal positive-edge interrupt enable
       
    40 	        KHtCSIControlTEndIE  |
       
    41 	        KHtCSIControlRxTrgEn |
       
    42 	        KHtCSIControlRxTrgIE;
       
    43 
       
    44 
       
    45 #ifdef __SMP__
       
    46 static TSpinLock CsiSpinLock = TSpinLock(TSpinLock::EOrderGenericIrqLow2);
       
    47 #endif
       
    48 
       
    49 // this is call-back for iHwGuard timer. It is called in the ISR context
       
    50 // if the iHwGuardTimer expires.
       
    51 // It will change the iTransactionStatus to KErrTimedOut to allow exiting from the while-loop..
       
    52 void DCsiChannelSlave::TimeoutCallback(TAny* aPtr)
       
    53 	{
       
    54 	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelMaster::TimeoutCallback"));
       
    55 	DCsiChannelSlave *a = (DCsiChannelSlave*) aPtr;
       
    56 	a->iTransactionStatus = KErrTimedOut;
       
    57 	}
       
    58 
       
    59 
       
    60 // this is a static method to be called - when SS line is de-asserted.
       
    61 // it disabled the interface and interrupts, and then it checks which flags
       
    62 // need to be specified and then calls NotifyClient using it
       
    63 void DCsiChannelSlave::NotifyClientEnd(DCsiChannelSlave* aPtr)
       
    64 	{
       
    65 	__KTRACE_OPT(KIIC, Kern::Printf("NotifyClientEnd, iTrigger %x", aPtr->iTrigger));
       
    66 
       
    67 	// disable interrupts and the interface..
       
    68 	AsspRegister::Modify32(aPtr->iChannelBase + KHoCSIModeControl,
       
    69 	                       KHtCSIModeEnable | KSlaveInterruptFlags, 0);
       
    70 
       
    71 	// call NotifyClient with xAllBytes (as specified by the Operation)
       
    72 	TInt flag = 0;
       
    73 	if(aPtr->iTrigger & EReceive)
       
    74 		{
       
    75 		flag = ERxAllBytes;
       
    76 		// if received less data, than the buffer size (i.e the Master de-asserted SS line
       
    77 		// before we could fill the whole buffer) - this is the underrun situation
       
    78 		if(aPtr->iRxDataEnd != aPtr->iRxData)
       
    79 			{
       
    80 			__KTRACE_OPT(KIIC, Kern::Printf("Rx Underrun"));
       
    81 			flag |= ERxUnderrun;
       
    82 			}
       
    83 		}
       
    84 
       
    85 	if(aPtr->iTrigger & ETransmit)
       
    86 		{
       
    87 		flag |= ETxAllBytes;
       
    88 		// if not everything was transferred, i.e. Master de-asserted SS line
       
    89 		// before we could transmit all the data - this is the overrun error..
       
    90 		if(aPtr->iTxDataEnd != aPtr->iTxData)
       
    91 			{
       
    92 			__KTRACE_OPT(KIIC, Kern::Printf("Tx Overrun"));
       
    93 			flag |= ETxOverrun;
       
    94 			}
       
    95 		}
       
    96 
       
    97 	aPtr->NotifyClient(flag);
       
    98 	}
       
    99 
       
   100 // ISR Handler
       
   101 void DCsiChannelSlave::CsiIsr(TAny* aPtr)
       
   102 	{
       
   103 	DCsiChannelSlave *a = (DCsiChannelSlave*) aPtr;
       
   104 	TInt intState = 0;
       
   105 
       
   106 	// read the interrupt flags - to see, what was causing the interrupt..
       
   107 	TUint32 status = AsspRegister::Read32(a->iChannelBase + KHoCSIIntStatus);
       
   108 
       
   109 	// SS signal negative-edge interrupt
       
   110 	if (status & KHtCSIIntStatusSSDn)
       
   111 		{
       
   112 		// falling edge..
       
   113 		TInt pin = AsspRegister::Read32(a->iChannelBase + KHoCSIControl) & KHtCSIControlSSMon;
       
   114 
       
   115 		// falling edge.. and if pin active at LOW state - this is the beginning
       
   116 		// of the transmission from the Master..
       
   117 		if (a->iSSPinActiveMode == ESpiCSPinActiveLow)
       
   118 			{
       
   119 			intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
       
   120 			if (!pin && !a->iInProgress)
       
   121 				{
       
   122 				a->iInProgress = ETrue;
       
   123 				}
       
   124 			__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
       
   125 			}
       
   126 		else
       
   127 		// falling edge.. and if pin active at HIGH state - this is the end
       
   128 		// of the transmission from the Master..
       
   129 			{
       
   130 			TInt8 notify = EFalse;
       
   131 			intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
       
   132 			if (pin && a->iInProgress)
       
   133 				{
       
   134 				a->iInProgress = EFalse;
       
   135 				notify = ETrue;
       
   136 				}
       
   137 			__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
       
   138 
       
   139 			if(notify)
       
   140 				{
       
   141 				a->NotifyClientEnd(a);
       
   142 				return;
       
   143 				}
       
   144 			}
       
   145 
       
   146 
       
   147 		// clear KHtCSIIntStatusSSDn interrupt..
       
   148 		AsspRegister::Write32(a->iChannelBase + KHoCSIIntStatus, KHtCSIIntStatusSSDn);
       
   149 		}
       
   150 
       
   151 	// SS signal positive-edge interrupt
       
   152 	if (status & KHtCSIIntStatusSSUp)
       
   153 		{
       
   154 		// rising edge..
       
   155 		TInt pin = AsspRegister::Read32(a->iChannelBase + KHoCSIControl) & KHtCSIControlSSMon;
       
   156 
       
   157 		// rising edge.. and if pin active at HIGH state - this is the beginning
       
   158 		// of the transmission from the Master..
       
   159 		if (a->iSSPinActiveMode == ESpiCSPinActiveHigh)
       
   160 			{
       
   161 			intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
       
   162 			if (pin && !a->iInProgress)
       
   163 				{
       
   164 				a->iInProgress = ETrue;
       
   165 				}
       
   166 			__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
       
   167 			}
       
   168 		else
       
   169 		// rising edge.. and if pin active at LOW state - this is the END
       
   170 		// of the transmission from the Master..
       
   171 			{
       
   172 			TInt8 notify = EFalse;
       
   173 
       
   174 			intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
       
   175 			if(pin && a->iInProgress)
       
   176 				{
       
   177 				a->iInProgress = EFalse;
       
   178 				notify = ETrue;
       
   179 				}
       
   180 			__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
       
   181 
       
   182 			if(notify)
       
   183 				{
       
   184 				a->NotifyClientEnd(a);
       
   185 				return;
       
   186 				}
       
   187 			}
       
   188 
       
   189 		// clear KHtCSIIntStatusSSUp interrupt..
       
   190 		AsspRegister::Write32(a->iChannelBase + KHoCSIIntStatus, KHtCSIIntStatusSSUp);
       
   191 		}
       
   192 
       
   193 	TInt trigger = 0;
       
   194 	if (status & (KHtCSIIntStatusTEnd | KHtCSIIntStatusRxTrgIE))
       
   195 		{
       
   196 		intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
       
   197 		trigger = a->iTrigger;
       
   198 		__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
       
   199 		}
       
   200 
       
   201 	// process TEND end interrupts
       
   202 	// this ISR happens every time ONE unit has been transfered..
       
   203 	if (status & KHtCSIIntStatusTEnd)
       
   204 		{
       
   205 		// clear TxEnd interrupt..
       
   206 		AsspRegister::Write32(a->iChannelBase + KHoCSIIntStatus, KHtCSIIntStatusTEnd);
       
   207 
       
   208 		if(trigger & ETransmit)
       
   209 			{
       
   210 			if(a->iTxData == a->iTxDataEnd)
       
   211 				{
       
   212 				// if we've moved all the data to the FIFO..
       
   213 				// notify the PIL with ETxAllBytes | ETxUnderrun;
       
   214 				// (so that - if the Client set ERxUnderrun - he could provide more data to be sent..
       
   215 				AsspRegister::Modify32(a->iChannelBase + KHoCSIControl, KHtCSIControlTEndIE, 0);
       
   216 				a->NotifyClient(ETxAllBytes | ETxUnderrun);
       
   217 				}
       
   218 			else
       
   219 				{
       
   220 				// if tere's more data to be sent - copy next item to the FIFO window register.
       
   221 				TUint16 val;
       
   222 
       
   223 				// in 16bit mode we need to read MSB first..
       
   224 				if(a->iWordSize > 1)
       
   225 					{
       
   226 					val = (*a->iTxData) >> 8; // MSB shifted down..
       
   227 					val |= *(a->iTxData + 1) & 0xff; // LSB..
       
   228 					}
       
   229 				else
       
   230 					{
       
   231 					val = *a->iTxData;
       
   232 					}
       
   233 
       
   234 				// copy the data item to the FIFO window register
       
   235 				AsspRegister::Write32(a->iChannelBase + KHoCSIOFifo, val);
       
   236 
       
   237 				// increment the pointer..
       
   238 				a->iTxData += a->iWordSize;
       
   239 				}
       
   240 			}
       
   241 		} //end of TXEnd processing
       
   242 
       
   243 	// process receive threshold interrupt
       
   244 	if (status & KHtCSIIntStatusRxTrgIE)
       
   245 		{
       
   246 		// read data from the FIFO ..
       
   247 		if(trigger & EReceive)
       
   248 			{
       
   249 			while(AsspRegister::Read32(a->iChannelBase + KHoCSIIFifoL))
       
   250 				{
       
   251 				// if there's still some place in the buffer - put it into buffer..
       
   252 				if((a->iRxDataEnd - a->iRxData) >= a->iWordSize)
       
   253 					{
       
   254 					// copy data from the FIFO if tere's more space in the buffer
       
   255 					TUint16 val = AsspRegister::Read32(a->iChannelBase + KHoCSIIFifo);
       
   256 
       
   257 					// we're big-endian.. (AB)..
       
   258 					// so in 16bit mode we need to read MSB first..
       
   259 					if(a->iWordSize > 1)
       
   260 						{
       
   261 						*a->iRxData = val >> 8; // MSB shifted down..
       
   262 						*(a->iRxData + 1) = val & 0xff; // LSB..
       
   263 						}
       
   264 					else
       
   265 						{
       
   266 						*a->iRxData = val;
       
   267 						}
       
   268 
       
   269 					// increment the pointer..
       
   270 					a->iRxData += a->iWordSize;
       
   271 					}
       
   272 				else
       
   273 					{
       
   274 					// overrun, i.e Slave has sent more data than expected by the client
       
   275 					//__KTRACE_OPT(KIIC, Kern::Printf("REND, ERxOverrun"));
       
   276 					AsspRegister::Modify32(a->iChannelBase + KHoCSIControl, KHtCSIControlRxTrgIE, 0);
       
   277 					a->NotifyClient(ERxAllBytes | ERxOverrun);
       
   278 					break;
       
   279 					}
       
   280 				}
       
   281 			}
       
   282 		else
       
   283 			{
       
   284 			// or drop the data, writing 0 to the FIFOL register
       
   285 			AsspRegister::Write32(a->iChannelBase + KHoCSIIFifoL, 0);
       
   286 			}
       
   287 
       
   288 		// Clear the  RxThreshold interrupt
       
   289 		AsspRegister::Write32(a->iChannelBase + KHoCSIIntStatus, KHtCSIIntStatusRxTrgIE);
       
   290 
       
   291 		} // end of reception processing..
       
   292 	}
       
   293 
       
   294 // overloaded constructor
       
   295 DCsiChannelSlave::DCsiChannelSlave(TInt aChannelNumber,
       
   296 	const DIicBusChannel::TBusType aBusType,
       
   297 	const DIicBusChannel::TChannelDuplex aChanDuplex) :
       
   298 	DIicBusChannelSlave(aBusType, aChanDuplex, 0),
       
   299 	iHwGuardTimer(TimeoutCallback, this)
       
   300 	{
       
   301     iHwTimeoutValue = -1;
       
   302 	iChannelNumber = aChannelNumber;
       
   303 	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelSlave::DCsiChannelSlave, iChannelNumber = %d\n", iChannelNumber));
       
   304 	}
       
   305 
       
   306 // 2nd stage object construction
       
   307 TInt DCsiChannelSlave::DoCreate()
       
   308 	{
       
   309 	__KTRACE_OPT(KIIC, Kern::Printf("\nDCsiChannelSlave::DoCreate, ch: %d \n", iChannelNumber));
       
   310 
       
   311 	TUint32 channelBase;
       
   312 
       
   313 	HCR::TSettingId channelBaseId;
       
   314 	channelBaseId.iCat = KHcrCat_MHA_HWBASE;
       
   315 
       
   316 	TInt r = KErrNone;
       
   317 	switch (iChannelNumber)
       
   318 		{
       
   319 		case 0:
       
   320 			channelBaseId.iKey = KHcrKey_HwBase_CSI0;
       
   321 			break;
       
   322 		case 1:
       
   323 			channelBaseId.iKey = KHcrKey_HwBase_CSI1;
       
   324 			break;
       
   325 		default:
       
   326 			__KTRACE_OPT(KIIC, Kern::Printf("Wrong ChannelNumber specified (%d)", iChannelNumber));
       
   327 			return KErrArgument;
       
   328 		}
       
   329 
       
   330 	r = HCR::GetUInt(channelBaseId, channelBase);
       
   331 	iChannelBase = channelBase;
       
   332 
       
   333 	if(r != KErrNone)
       
   334 		{
       
   335 		__KTRACE_OPT(KIIC, Kern::Printf("Failed to read HCR setting for category = %d and key = %d\n", channelBaseId.iCat, channelBaseId.iKey));
       
   336 		return r;
       
   337 		}
       
   338 
       
   339 	//Read the timeout value from HCR
       
   340 	if(iHwTimeoutValue == -1) 
       
   341         {
       
   342         HCR::TSettingId settingId;
       
   343         // csiTimeout values was not yet read from HCR; read it
       
   344         settingId.iCat = KHcrCat_HWServ_CSI;
       
   345         settingId.iKey = KHcrKey_CSI_Timeout;
       
   346     
       
   347         TInt r = HCR::GetInt(settingId, iHwTimeoutValue);
       
   348         if(r != KErrNone) 
       
   349             {
       
   350             __KTRACE_OPT(KIIC, Kern::Printf("Failed to read HCR setting for category = %d and key = %d\n", settingId.iCat, settingId.iKey));
       
   351             return r;
       
   352             }
       
   353         }
       
   354 	
       
   355 	// PIL Base class initialization.
       
   356 	r = Init();
       
   357 
       
   358 	// set the unique Slave's iChannelId
       
   359 	// THis, along with the instance count of opened Slave channels - will be returned to the client
       
   360  	// as he captures the Channel (in the referenced aChannelId making an unique ID) - and if the capture is
       
   361 	// successful he refers to this channel using the returned ChannelId.
       
   362 
       
   363 	// For now, let's just use the combination of iChannelNumber/iChannelBase(register address))
       
   364 	// This might be later replaced by the call into ConfRep to obtain the iChannelId for the PSL.
       
   365 	iChannelId = 0xffff & (iChannelNumber + iChannelBase);
       
   366 
       
   367 	return r;
       
   368 	}
       
   369 
       
   370 // static method used to construct the DCsiChannelSlave object.
       
   371 #ifdef STANDALONE_CHANNEL
       
   372 EXPORT_C
       
   373 #endif
       
   374 DCsiChannelSlave* DCsiChannelSlave::New(TInt aChannelNumber, const TBusType aBusType, const TChannelDuplex aChanDuplex)
       
   375 	{
       
   376 	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelSlave::NewL(): aChannelNumber = %d, BusType =%d", aChannelNumber, aBusType));
       
   377 	DCsiChannelSlave *pChan = new DCsiChannelSlave(aChannelNumber, aBusType, aChanDuplex);
       
   378 
       
   379 	TInt r = KErrNoMemory;
       
   380 	if (pChan)
       
   381 		{
       
   382 		r = pChan->DoCreate();
       
   383 		}
       
   384 	if (r != KErrNone)
       
   385 		{
       
   386 		delete pChan;
       
   387 		pChan = NULL;
       
   388 		}
       
   389 
       
   390 	return pChan;
       
   391 	}
       
   392 
       
   393 // Validates the various Fields in the transaction header
       
   394 // THis is a pure virtual.. which.. is never called by the PIL?..
       
   395 TInt DCsiChannelSlave::CheckHdr(TDes8* aHdrBuff)
       
   396 	{
       
   397 	TInt r = KErrNone;
       
   398 
       
   399 	if(!aHdrBuff)
       
   400 		{
       
   401 		r = KErrArgument;
       
   402 		}
       
   403 	else
       
   404 		{
       
   405 		TConfigSpiBufV01* headerBuf = (TConfigSpiBufV01*) aHdrBuff;
       
   406 		TConfigSpiV01 &spiHeader = (*headerBuf)();
       
   407 
       
   408 		if(spiHeader.iTransactionWaitCycles > 15) // (can be 0 - 15)
       
   409 			{
       
   410 			__KTRACE_OPT(KIIC, Kern::Printf("iTransactionWaitCycles not supported"));
       
   411 			r = KErrNotSupported;
       
   412 			}
       
   413 		else
       
   414 			{
       
   415 			if(spiHeader.iWordWidth != ESpiWordWidth_8 &&
       
   416 			spiHeader.iWordWidth != ESpiWordWidth_16)
       
   417 				{
       
   418 				__KTRACE_OPT(KIIC, Kern::Printf("iWordWidth not supported"));
       
   419 				r = KErrNotSupported;
       
   420 				}
       
   421 			}
       
   422 		}
       
   423 	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelSlave::CheckHdr() r %d", r));
       
   424 
       
   425 	return r;
       
   426 	}
       
   427 
       
   428 void DCsiChannelSlave::ProcessData(TInt aTrigger, TIicBusSlaveCallback* aCb)
       
   429 	{
       
   430 	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelSlave::ProcessData(), trigger: %x, in progress %d", aTrigger, iInProgress));
       
   431 	TInt intState;
       
   432 
       
   433 	// if NotifyClient was called due to SS line de-assertion..
       
   434 	TInt inProgress;
       
   435 	intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
       
   436 	inProgress = iInProgress;
       
   437 	__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
       
   438 
       
   439 	if(!inProgress &&
       
   440 	   (aTrigger & (ERxAllBytes | ETxAllBytes)))
       
   441 		{
       
   442 		__KTRACE_OPT(KIIC, Kern::Printf("Finished, cleaning.."));
       
   443 		// we migh be still receiving or transmitting data, so must wait until the end of the transmission
       
   444 		// start the guard timer, which - in case of the following while got stucked - will
       
   445 		// unblock this dfc by changing iTransactionStatus
       
   446 		iTransactionStatus = KErrNone;
       
   447 
       
   448 		iHwGuardTimer.OneShot(NKern::TimerTicks(iHwTimeoutValue));
       
   449 
       
   450 		// active wait until the transfer has finished
       
   451 		while((iTransactionStatus == KErrNone) &&
       
   452 		      (AsspRegister::Read32(iChannelBase + KHoCSIModeControl) & KHtCSIModeTransferState));
       
   453 
       
   454 		// clear CSIE bit..
       
   455 		AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, KHtCSIModeEnable, 0);
       
   456 
       
   457 		// check if the the guard timer or transaction timer hasn't expired..
       
   458 		if(iTransactionStatus != KErrNone)
       
   459 			{
       
   460 			__KTRACE_OPT(KIIC, Kern::Printf("CsiChannelMaster::TransferEndDfc(): Transaction timed-out"));
       
   461 			return;
       
   462 			}
       
   463 		else
       
   464 			{
       
   465 			iHwGuardTimer.Cancel();
       
   466 			}
       
   467 
       
   468 		// clear internal flags
       
   469 		intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
       
   470 		iTrigger = 0;
       
   471 		__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
       
   472 		}
       
   473 
       
   474 	// if the transaction was finished
       
   475 	// NotifyClient() with ERxAllBytes (and)or  ETxAllBytes called, when SS pin is de-asserted
       
   476 	// this indicated end of the transmission. Check buffer boundaries, as if Rx or Tx buffers
       
   477 	// provided by the client were bigger - this indicates ERxUnderrun or ETxOverrun - accordingly
       
   478 	// Rx..
       
   479 	if(aTrigger & ERxAllBytes)
       
   480 		{
       
   481 		__KTRACE_OPT(KIIC, Kern::Printf("Rx Buf:    %x", iRxData));
       
   482 		__KTRACE_OPT(KIIC, Kern::Printf("Rx BufeND: %x", iRxDataEnd));
       
   483 
       
   484 		__KTRACE_OPT(KIIC, Kern::Printf("\n\nTxFifo level %d", AsspRegister::Read32(iChannelBase + KHoCSIOFifoL)));
       
   485 		__KTRACE_OPT(KIIC, Kern::Printf("RxFifo level %d\n\n", AsspRegister::Read32(iChannelBase + KHoCSIIFifoL)));
       
   486 
       
   487 		// clear the internal EReceive flag..
       
   488 		intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
       
   489 		iTrigger &= ~EReceive;
       
   490 		__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
       
   491 
       
   492 		// update the buffer information in the Callback object..
       
   493 		aCb->SetRxWords(iNumRxWords - ((iRxDataEnd - iRxData) / iWordSize));
       
   494 		}
       
   495 
       
   496 	// Tx...
       
   497 	if(aTrigger & ETxAllBytes)
       
   498 		{
       
   499 		__KTRACE_OPT(KIIC, Kern::Printf("Tx Buf:    %x", iTxData));
       
   500 		__KTRACE_OPT(KIIC, Kern::Printf("Tx BufeND: %x", iTxDataEnd));
       
   501 
       
   502 		// set the callback's TxWords value
       
   503 		__KTRACE_OPT(KIIC, Kern::Printf("aCb->SetTxWords %d", iNumTxWords - ((iTxDataEnd - iTxData) / iWordSize)));
       
   504 
       
   505 		// clear the internal ETransmit flag..
       
   506 		intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
       
   507 		iTrigger &= ~ETransmit;
       
   508 		__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
       
   509 
       
   510 		// update the buffer information in the Callback object..
       
   511 		aCb->SetTxWords(iNumTxWords - ((iTxDataEnd - iTxData) / iWordSize));
       
   512 		}
       
   513 
       
   514 	if(aTrigger & EGeneralBusError)
       
   515 		{
       
   516 		__KTRACE_OPT(KIIC, Kern::Printf("BusError.."));
       
   517 		// clear CSIE bit..and disable HW interrupts..
       
   518 		AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, KHtCSIModeEnable | KSlaveInterruptFlags, 0);
       
   519 
       
   520 		// clear internal flags
       
   521 		intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
       
   522 		iTrigger = 0;
       
   523 		__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
       
   524 		}
       
   525 
       
   526 	// set the callback's trigger..
       
   527 	aCb->SetTrigger(aTrigger | aCb->GetTrigger());
       
   528 	}
       
   529 
       
   530 // Initializes the hardware with the data provided in the transaction and slave-address field
       
   531 TInt DCsiChannelSlave::ConfigureInterface()
       
   532 	{
       
   533 	__KTRACE_OPT(KIIC, Kern::Printf("ConfigureInterface()"));
       
   534 
       
   535 	HCR::TSettingId settingId;
       
   536 	TConfigSpiBufV01* aBuf = (TConfigSpiBufV01*) iConfigHeader;
       
   537 	TConfigSpiV01 &spiHeader = (*aBuf)();
       
   538 
       
   539 	// CSI initialization procedure:
       
   540 	// 1. clear CISE bit..
       
   541 	AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, KHtCSIModeEnable, 0);
       
   542 
       
   543 	// 2. wait until CIS_MODE.bit0 (CSOT) changes to 0
       
   544 	// start the GuardTimer before while-loop..
       
   545 	iTransactionStatus = KErrNone;
       
   546 
       
   547 	iHwGuardTimer.OneShot(NKern::TimerTicks(iHwTimeoutValue));
       
   548 
       
   549 	while((iTransactionStatus == KErrNone) &&
       
   550 	       AsspRegister::Read32(iChannelBase + KHoCSIModeControl) & KHtCSIModeTransferState);
       
   551 
       
   552 	// check if the the guard timer or transaction timer hasn't expired..
       
   553 	if(iTransactionStatus != KErrNone)
       
   554 		{
       
   555 		return KErrGeneral;
       
   556 		}
       
   557 	else
       
   558 		{
       
   559 		iHwGuardTimer.Cancel();
       
   560 		}
       
   561 
       
   562 	// 3. set CSIRST bit..
       
   563 	AsspRegister::Modify32(iChannelBase + KHoCSIControl, 0, KHtCSIControlCSIRst);
       
   564 
       
   565 	// 4. set KHoCSIClockSelect register..
       
   566 	TUint32 val = 0;
       
   567 
       
   568 	// CKP - ClocK Polarity (bit 4) 0: initial value is high, 1: initial val is low
       
   569 	// DAP - Clock phase select (bit 3) 0: 180 degree delay, 1: 0 degree delay
       
   570 	// @** don't use DAP=1 when iClock set to KHCSIClockValPCLKdiv4 (HW bug..see SoC errata)
       
   571 	switch (spiHeader.iClkMode)
       
   572 		{
       
   573 		case ESpiPolarityLowRisingEdge: // Active high, odd edges
       
   574 			val = KHtCSIClockSelectCKP; // CKP 1, DAP 0
       
   575 			break;
       
   576 		case ESpiPolarityLowFallingEdge: // Active high, even edges
       
   577 			val = KHtCSIClockSelectCKP | // CKP 1, DAP 1
       
   578 			      KHtCSIClockSelectDAP;
       
   579 			break;
       
   580 
       
   581 		case ESpiPolarityHighFallingEdge: // Active low,  odd edges
       
   582 			val = 0; // CKP 0, DAP 0
       
   583 			break;
       
   584 
       
   585 		case ESpiPolarityHighRisingEdge: // Active low,  even edges
       
   586 			val = KHtCSIClockSelectDAP; // CKP 0, DAP 1
       
   587 			break;
       
   588 		default:
       
   589 			break; // there's no default..no other value can be specified as it's an enum ;)
       
   590 		}
       
   591 
       
   592 	// we are a Slave - so we use only one setting for the clk speed, ignoring the header
       
   593 	val |= KHCSIClockValSlave;
       
   594 
       
   595 	// Set the SS pin configuration..
       
   596 	val |= KHtCSIClockSelectSSE; // SS pin enable
       
   597 
       
   598 	if (spiHeader.iSSPinActiveMode == ESpiCSPinActiveHigh)
       
   599 		{
       
   600 		val |= KHtCSIClockSelectSSPol; //  1: SS pin high active
       
   601 		}
       
   602 
       
   603 	// store iSSPinActiveMode internaly - it will be used in interrupts.
       
   604 	iSSPinActiveMode = spiHeader.iSSPinActiveMode;
       
   605 
       
   606 	// set transaction wait time..
       
   607 	val |= (0xf & spiHeader.iTransactionWaitCycles) << KHsCSIModeTWait;
       
   608 
       
   609 	// and finally update the register
       
   610 	AsspRegister::Write32(iChannelBase + KHoCSIClockSelect, val);
       
   611 
       
   612 	// 5. clear KHtCSIControlCSIRst bit..
       
   613 	AsspRegister::Modify32(iChannelBase + KHoCSIControl, KHtCSIControlCSIRst, 0);
       
   614 
       
   615 	// 6. Set Mode Control register:
       
   616 	// Transmission and reception mode
       
   617 	val = KHtCSIModeTrEnable;
       
   618 
       
   619 	// Select transmit data length (8/16 bits)
       
   620 	if (spiHeader.iWordWidth == ESpiWordWidth_16)
       
   621 		{
       
   622 		iWordSize = 2;
       
   623 		val |= KHtCSIModeDataLen;
       
   624 		}
       
   625 	else
       
   626 		{
       
   627 		iWordSize = 1;
       
   628 		}
       
   629 
       
   630 	// Select Transfer direction (if set-LSB first)
       
   631 	if (spiHeader.iBitOrder == ELsbFirst)
       
   632 		{
       
   633 		val |= KHtCSIModeTransferDir;
       
   634 		}
       
   635 
       
   636 	// update the register
       
   637 	AsspRegister::Write32(iChannelBase + KHoCSIModeControl, val);
       
   638 
       
   639 	// 7. Set FIFO trigger levels
       
   640 	TUint8 csiFifoRxTrigerLvl; // set RxTrigger level
       
   641 	
       
   642 	settingId.iCat = KHcrCat_HWServ_CSI;
       
   643 	settingId.iKey = KHcrKey_CSI_FifoRxTrigerLvl;
       
   644 	TInt r = HCR::GetUInt(settingId, csiFifoRxTrigerLvl);
       
   645 	if(r != KErrNone) 
       
   646 		{
       
   647 		__KTRACE_OPT(KIIC, Kern::Printf("Failed to read HCR setting for category = %d and key = %d\n", settingId.iCat, settingId.iKey));
       
   648 		return r;
       
   649 		}
       
   650 	AsspRegister::Write32(iChannelBase + KHoCSIFifoTrgLvl,
       
   651 	                      (csiFifoRxTrigerLvl << KHsCSIRxFifoTrgLvl));
       
   652 
       
   653 	// 8. Clear all interrupts
       
   654 	AsspRegister::Write32(iChannelBase + KHoCSIIntStatus, KInterruptsAll);
       
   655 
       
   656 	// 9. Set RxTrig permission and enable TEnd and RxTrg interrupts
       
   657 	AsspRegister::Write32(iChannelBase + KHoCSIControl, KSlaveInterruptFlags);
       
   658 
       
   659 	// the timeout period to wait for a response from the client.
       
   660 	SetClientWaitTime(KClientWaitTime);
       
   661 	// if the KIIC debug trace flag is set, we need to increase the transaction timeout,
       
   662 	// so that debug traces don't cause timer expiration. This call will overwrite
       
   663 	// previously set value (SetClientWaitTime) and default value set by the PIL (SetMasterWaitTime)
       
   664 	__KTRACE_OPT(KIIC, SetClientWaitTime(KMaxWaitTime));
       
   665 	__KTRACE_OPT(KIIC, SetMasterWaitTime(KMaxWaitTime));
       
   666 
       
   667 
       
   668 	settingId.iCat = KHcrCat_MHA_Interrupt;
       
   669 	settingId.iKey = iChannelNumber == 0 ? KHcrKey_Interrupt_CSI0 : KHcrKey_Interrupt_CSI1;
       
   670 
       
   671 	TInt32 interruptId;
       
   672 	r = HCR::GetInt(settingId, interruptId);
       
   673 	if(r != KErrNone)
       
   674 		{
       
   675 		__KTRACE_OPT(KIIC, Kern::Printf("Failed to read HCR setting for category = %d and key = %d\n", settingId.iCat, settingId.iKey));
       
   676 		return r;
       
   677 		}
       
   678 
       
   679 	// Bind the ISR for the Slave
       
   680 	iInterruptId = Interrupt::Bind(interruptId, DCsiChannelSlave::CsiIsr, this);
       
   681 
       
   682 	// this returns interruptId or error code(err < 0)
       
   683 	if (iInterruptId < KErrNone)
       
   684 		{
       
   685 		__KTRACE_OPT(KIIC, Kern::Printf("ERROR: InterruptBind error.. %d", r));
       
   686 		Kern::Printf("ERROR: InterruptBind error.. %d", r);
       
   687 		r = iInterruptId;
       
   688 		}
       
   689 
       
   690 	return r;
       
   691 	}
       
   692 
       
   693 // This method starts data transfer - filling the Transmit FIFO and enabling the device (CSIE bit)
       
   694 TInt DCsiChannelSlave::InitTransfer()
       
   695 	{
       
   696 	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelSlave::InitTransfer()"));
       
   697 	//__KTRACE_OPT(KIIC, Kern::Printf("Receiving %d, Transmitting %d", (iTrigger & EReceive)>>4, (iTrigger & ETransmit)>>3));
       
   698 
       
   699 	TUint r = KErrNone;
       
   700 	TInt intState;
       
   701 	TInt trigger;
       
   702 
       
   703 	intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
       
   704 	if(!iInProgress)
       
   705 		{
       
   706 		// clean the FIFOs..
       
   707 		AsspRegister::Write32(iChannelBase + KHoCSIOFifoL, 0);
       
   708 		AsspRegister::Write32(iChannelBase + KHoCSIOFifoL, 0);
       
   709 
       
   710 		// clear CISE bit..re-enable all HW interrupts..
       
   711 		AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, KHtCSIModeEnable, KSlaveInterruptFlags);
       
   712 
       
   713 		// Clear all interrupts
       
   714 		AsspRegister::Write32(iChannelBase + KHoCSIIntStatus, KInterruptsAll);
       
   715 		}
       
   716 	__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
       
   717 
       
   718 
       
   719 	intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
       
   720 	trigger = iTrigger;
       
   721 	__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
       
   722 
       
   723 	// if we are transmitting - Add data to the FIFO..
       
   724 	if(trigger & ETransmit)
       
   725 		{
       
   726 		// Set mode to transmission and reception (Set TRMD)
       
   727 		AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, 0, KHtCSIModeTrEnable);
       
   728 
       
   729 		// enable TEND interrupt (e.g. if this is called during the transmission as the result of
       
   730 		// TxUnderrun event.
       
   731 		AsspRegister::Modify32(iChannelBase + KHoCSIControl, 0, KHtCSIControlTEndIE);
       
   732 
       
   733 		iWordSize = iTxGranularity >> 3;
       
   734 		iTxData = iTxBuf + (iWordSize * iTxOffset);
       
   735 		iTxDataEnd = iTxData + (iWordSize * iNumTxWords);
       
   736 
       
   737 		__KTRACE_OPT(KIIC, Kern::Printf("Tx Buf:    %x", iTxData));
       
   738 		__KTRACE_OPT(KIIC, Kern::Printf("Tx BufeND: %x", iTxDataEnd));
       
   739 
       
   740 		// copy data to the FIFO..
       
   741 		while(AsspRegister::Read32(iChannelBase + KHoCSIOFifoL) <= (KHwCSIFifoLMax - iWordSize) && // until FIFO not full..
       
   742 		      iTxData != iTxDataEnd) // or whole data has been copied.
       
   743 			{
       
   744 			TUint16 val;
       
   745 
       
   746 			// in 16bit mode we need to read MSB first..
       
   747 			if(iWordSize > 1)
       
   748 				{
       
   749 				val = (*iTxData) << 8; // MSB shifted up..
       
   750 				val |= *(iTxData + 1) & 0xff; // LSB..
       
   751 				}
       
   752 			else
       
   753 				{
       
   754 				val = *iTxData;
       
   755 				}
       
   756 
       
   757 			// write this value to the FIFO window register..
       
   758 			AsspRegister::Write32(iChannelBase + KHoCSIOFifo, val);
       
   759 
       
   760 			// increment the pointer.
       
   761 			iTxData += iWordSize;
       
   762 			}
       
   763 
       
   764 		__KTRACE_OPT(KIIC, Kern::Printf("After adding:\n\rTx Buf:    %x", iTxData));
       
   765 		__KTRACE_OPT(KIIC, Kern::Printf("Tx BufeND: %x", iTxDataEnd));
       
   766 		}
       
   767 
       
   768 	if(trigger & EReceive) // we are starting receive transfer only..
       
   769 		{
       
   770 		if(!(trigger & ETransmit))
       
   771 			{
       
   772 			// if only receiving - set it to reveive-only
       
   773 			// Set mode to reception only (clear TRMD)
       
   774 			AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, KHtCSIModeTrEnable, 0);
       
   775 			}
       
   776 
       
   777 		// enable RxTrg interrupt (e.g. if this is called during the transmission as the result
       
   778 		// of RxOverrun event.
       
   779 		AsspRegister::Modify32(iChannelBase + KHoCSIControl, 0, KHtCSIControlRxTrgIE);
       
   780 
       
   781 		iWordSize = iRxGranularity >> 3;
       
   782 		iRxData = iRxBuf + (iWordSize * iRxOffset);
       
   783 		iRxDataEnd = iRxData + (iWordSize * iNumRxWords);
       
   784 
       
   785 		__KTRACE_OPT(KIIC, Kern::Printf("Rx Buffer:  %x", iRxData));
       
   786 		__KTRACE_OPT(KIIC, Kern::Printf("Rx BufreND: %x", iRxDataEnd));
       
   787 		}
       
   788 
       
   789 	// enable interrupts..
       
   790 	Interrupt::Enable(iInterruptId);
       
   791 
       
   792 	// enable transmission..this will trigger the HW to start the transmission..
       
   793 	AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, 0, KHtCSIModeEnable);
       
   794 
       
   795 	return r;
       
   796 	}
       
   797 
       
   798 // aOperation is a bit-mask made of TPslOperation
       
   799 TInt DCsiChannelSlave::DoRequest(TInt aOperation)
       
   800 	{
       
   801 //	__KTRACE_OPT(KIIC, Kern::Printf("\n===>DCsiChannelSlave::DoRequest, Operation %x", aOperation));
       
   802 
       
   803 	TInt r = KErrNone;
       
   804 	TInt intState;
       
   805 
       
   806 	if (aOperation & EAsyncConfigPwrUp)
       
   807 		{
       
   808 		__KTRACE_OPT(KIIC, Kern::Printf("EAsyncConfigPwrUp"));
       
   809 		// this is called when the client calls IicBus::CaptureChannel() asynchronously
       
   810 		r = ConfigureInterface();
       
   811 		ChanCaptureCallback(r);
       
   812 		return r;
       
   813 		}
       
   814 
       
   815 	// PowerUp
       
   816 	if (aOperation & ESyncConfigPwrUp)
       
   817 		{
       
   818 		__KTRACE_OPT(KIIC, Kern::Printf("ESyncConfigPwrUp"));
       
   819 		// this is called when the client calls IicBus::CaptureChannel()
       
   820 		// - configure the channel with the configuration provided in the header.
       
   821 		r = ConfigureInterface();
       
   822 		// we can't continue in this case..
       
   823 		if (r != KErrNone)
       
   824 			{
       
   825 			__KTRACE_OPT(KIIC, Kern::Printf("Coudln't configure the interface..r %d", r));
       
   826 			return r;
       
   827 			}
       
   828 		}
       
   829 
       
   830 	if (aOperation & ETransmit)
       
   831 		{
       
   832 		__KTRACE_OPT(KIIC, Kern::Printf("ETransmit"));
       
   833 		intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
       
   834 		iTrigger |= ETransmit;
       
   835 		__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
       
   836 		}
       
   837 
       
   838 	if (aOperation & EReceive)
       
   839 		{
       
   840 		__KTRACE_OPT(KIIC, Kern::Printf("EReceive"));
       
   841 		intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
       
   842 		iTrigger |= EReceive;
       
   843 		__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
       
   844 		}
       
   845 
       
   846 	if (aOperation & (EReceive | ETransmit))
       
   847 		{
       
   848 		r = InitTransfer();
       
   849 		}
       
   850 
       
   851 	if (aOperation & EAbort)
       
   852 		{
       
   853 		__KTRACE_OPT(KIIC, Kern::Printf("EAbort"));
       
   854 		intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
       
   855 		// disable CSI (clear CSIE bit), and interrupts
       
   856 		if(!iInProgress)
       
   857 			{
       
   858 			AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, KHtCSIModeEnable | KSlaveInterruptFlags, 0);
       
   859 			iInProgress = EFalse;
       
   860 			iTrigger = 0;
       
   861 			}
       
   862 		__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
       
   863 		Interrupt::Disable(iInterruptId);
       
   864 		}
       
   865 
       
   866 	if (aOperation & EPowerDown)
       
   867 		{
       
   868 		__KTRACE_OPT(KIIC, Kern::Printf("EPowerDown"));
       
   869 
       
   870 		// set CSI Rst bit
       
   871 		AsspRegister::Write32(iChannelBase + KHoCSIModeControl, KHtCSIControlCSIRst);
       
   872 
       
   873 		// disable and unbind the ISR,
       
   874 		Interrupt::Disable(iInterruptId);
       
   875 		Interrupt::Unbind(iInterruptId);
       
   876 		}
       
   877 	return r;
       
   878 	}
       
   879