navienginebsp/naviengine_assp/csi/csi_slave.cpp
changeset 0 5de814552237
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/navienginebsp/naviengine_assp/csi/csi_slave.cpp	Tue Sep 28 18:00:05 2010 +0100
@@ -0,0 +1,879 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+
+
+#include <drivers/iic.h>
+#include <drivers/iic_channel.h>
+#include <assp/naviengine/naviengine_priv.h>
+#include "csi_psl.h"
+#include "csi_slave.h"
+
+#include "hcrconfig.h"
+#include "hcrconfig_csi.h"
+
+// the timeout period to wait for a response from the client.
+// We can't predict the frequency, at which the Master will be sending us data,
+// it can be from 130kHz (which is 16,25bytes/ms) up to 16,67MHz(2083 bytes/ms).
+// Timeout is set for the slowest transfer - for the time that the 32 bytes Tx FIFO would be emptied
+// (Rx FIFO filled), so 2ms.
+const TInt KClientWaitTime = 2; // when debugging might set up to KMaxWaitTime
+
+// set of interrupt flags used by the driver
+const TUint32 KSlaveInterruptFlags =
+			KHtCSIControlSSDnIE	 | // SS signal negative-edge interrupt enable
+	        KHtCSIControlSSUpIE  | // SS signal positive-edge interrupt enable
+	        KHtCSIControlTEndIE  |
+	        KHtCSIControlRxTrgEn |
+	        KHtCSIControlRxTrgIE;
+
+
+#ifdef __SMP__
+static TSpinLock CsiSpinLock = TSpinLock(TSpinLock::EOrderGenericIrqLow2);
+#endif
+
+// this is call-back for iHwGuard timer. It is called in the ISR context
+// if the iHwGuardTimer expires.
+// It will change the iTransactionStatus to KErrTimedOut to allow exiting from the while-loop..
+void DCsiChannelSlave::TimeoutCallback(TAny* aPtr)
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelMaster::TimeoutCallback"));
+	DCsiChannelSlave *a = (DCsiChannelSlave*) aPtr;
+	a->iTransactionStatus = KErrTimedOut;
+	}
+
+
+// this is a static method to be called - when SS line is de-asserted.
+// it disabled the interface and interrupts, and then it checks which flags
+// need to be specified and then calls NotifyClient using it
+void DCsiChannelSlave::NotifyClientEnd(DCsiChannelSlave* aPtr)
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("NotifyClientEnd, iTrigger %x", aPtr->iTrigger));
+
+	// disable interrupts and the interface..
+	AsspRegister::Modify32(aPtr->iChannelBase + KHoCSIModeControl,
+	                       KHtCSIModeEnable | KSlaveInterruptFlags, 0);
+
+	// call NotifyClient with xAllBytes (as specified by the Operation)
+	TInt flag = 0;
+	if(aPtr->iTrigger & EReceive)
+		{
+		flag = ERxAllBytes;
+		// if received less data, than the buffer size (i.e the Master de-asserted SS line
+		// before we could fill the whole buffer) - this is the underrun situation
+		if(aPtr->iRxDataEnd != aPtr->iRxData)
+			{
+			__KTRACE_OPT(KIIC, Kern::Printf("Rx Underrun"));
+			flag |= ERxUnderrun;
+			}
+		}
+
+	if(aPtr->iTrigger & ETransmit)
+		{
+		flag |= ETxAllBytes;
+		// if not everything was transferred, i.e. Master de-asserted SS line
+		// before we could transmit all the data - this is the overrun error..
+		if(aPtr->iTxDataEnd != aPtr->iTxData)
+			{
+			__KTRACE_OPT(KIIC, Kern::Printf("Tx Overrun"));
+			flag |= ETxOverrun;
+			}
+		}
+
+	aPtr->NotifyClient(flag);
+	}
+
+// ISR Handler
+void DCsiChannelSlave::CsiIsr(TAny* aPtr)
+	{
+	DCsiChannelSlave *a = (DCsiChannelSlave*) aPtr;
+	TInt intState = 0;
+
+	// read the interrupt flags - to see, what was causing the interrupt..
+	TUint32 status = AsspRegister::Read32(a->iChannelBase + KHoCSIIntStatus);
+
+	// SS signal negative-edge interrupt
+	if (status & KHtCSIIntStatusSSDn)
+		{
+		// falling edge..
+		TInt pin = AsspRegister::Read32(a->iChannelBase + KHoCSIControl) & KHtCSIControlSSMon;
+
+		// falling edge.. and if pin active at LOW state - this is the beginning
+		// of the transmission from the Master..
+		if (a->iSSPinActiveMode == ESpiCSPinActiveLow)
+			{
+			intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
+			if (!pin && !a->iInProgress)
+				{
+				a->iInProgress = ETrue;
+				}
+			__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
+			}
+		else
+		// falling edge.. and if pin active at HIGH state - this is the end
+		// of the transmission from the Master..
+			{
+			TInt8 notify = EFalse;
+			intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
+			if (pin && a->iInProgress)
+				{
+				a->iInProgress = EFalse;
+				notify = ETrue;
+				}
+			__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
+
+			if(notify)
+				{
+				a->NotifyClientEnd(a);
+				return;
+				}
+			}
+
+
+		// clear KHtCSIIntStatusSSDn interrupt..
+		AsspRegister::Write32(a->iChannelBase + KHoCSIIntStatus, KHtCSIIntStatusSSDn);
+		}
+
+	// SS signal positive-edge interrupt
+	if (status & KHtCSIIntStatusSSUp)
+		{
+		// rising edge..
+		TInt pin = AsspRegister::Read32(a->iChannelBase + KHoCSIControl) & KHtCSIControlSSMon;
+
+		// rising edge.. and if pin active at HIGH state - this is the beginning
+		// of the transmission from the Master..
+		if (a->iSSPinActiveMode == ESpiCSPinActiveHigh)
+			{
+			intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
+			if (pin && !a->iInProgress)
+				{
+				a->iInProgress = ETrue;
+				}
+			__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
+			}
+		else
+		// rising edge.. and if pin active at LOW state - this is the END
+		// of the transmission from the Master..
+			{
+			TInt8 notify = EFalse;
+
+			intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
+			if(pin && a->iInProgress)
+				{
+				a->iInProgress = EFalse;
+				notify = ETrue;
+				}
+			__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
+
+			if(notify)
+				{
+				a->NotifyClientEnd(a);
+				return;
+				}
+			}
+
+		// clear KHtCSIIntStatusSSUp interrupt..
+		AsspRegister::Write32(a->iChannelBase + KHoCSIIntStatus, KHtCSIIntStatusSSUp);
+		}
+
+	TInt trigger = 0;
+	if (status & (KHtCSIIntStatusTEnd | KHtCSIIntStatusRxTrgIE))
+		{
+		intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
+		trigger = a->iTrigger;
+		__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
+		}
+
+	// process TEND end interrupts
+	// this ISR happens every time ONE unit has been transfered..
+	if (status & KHtCSIIntStatusTEnd)
+		{
+		// clear TxEnd interrupt..
+		AsspRegister::Write32(a->iChannelBase + KHoCSIIntStatus, KHtCSIIntStatusTEnd);
+
+		if(trigger & ETransmit)
+			{
+			if(a->iTxData == a->iTxDataEnd)
+				{
+				// if we've moved all the data to the FIFO..
+				// notify the PIL with ETxAllBytes | ETxUnderrun;
+				// (so that - if the Client set ERxUnderrun - he could provide more data to be sent..
+				AsspRegister::Modify32(a->iChannelBase + KHoCSIControl, KHtCSIControlTEndIE, 0);
+				a->NotifyClient(ETxAllBytes | ETxUnderrun);
+				}
+			else
+				{
+				// if tere's more data to be sent - copy next item to the FIFO window register.
+				TUint16 val;
+
+				// in 16bit mode we need to read MSB first..
+				if(a->iWordSize > 1)
+					{
+					val = (*a->iTxData) >> 8; // MSB shifted down..
+					val |= *(a->iTxData + 1) & 0xff; // LSB..
+					}
+				else
+					{
+					val = *a->iTxData;
+					}
+
+				// copy the data item to the FIFO window register
+				AsspRegister::Write32(a->iChannelBase + KHoCSIOFifo, val);
+
+				// increment the pointer..
+				a->iTxData += a->iWordSize;
+				}
+			}
+		} //end of TXEnd processing
+
+	// process receive threshold interrupt
+	if (status & KHtCSIIntStatusRxTrgIE)
+		{
+		// read data from the FIFO ..
+		if(trigger & EReceive)
+			{
+			while(AsspRegister::Read32(a->iChannelBase + KHoCSIIFifoL))
+				{
+				// if there's still some place in the buffer - put it into buffer..
+				if((a->iRxDataEnd - a->iRxData) >= a->iWordSize)
+					{
+					// copy data from the FIFO if tere's more space in the buffer
+					TUint16 val = AsspRegister::Read32(a->iChannelBase + KHoCSIIFifo);
+
+					// we're big-endian.. (AB)..
+					// so in 16bit mode we need to read MSB first..
+					if(a->iWordSize > 1)
+						{
+						*a->iRxData = val >> 8; // MSB shifted down..
+						*(a->iRxData + 1) = val & 0xff; // LSB..
+						}
+					else
+						{
+						*a->iRxData = val;
+						}
+
+					// increment the pointer..
+					a->iRxData += a->iWordSize;
+					}
+				else
+					{
+					// overrun, i.e Slave has sent more data than expected by the client
+					//__KTRACE_OPT(KIIC, Kern::Printf("REND, ERxOverrun"));
+					AsspRegister::Modify32(a->iChannelBase + KHoCSIControl, KHtCSIControlRxTrgIE, 0);
+					a->NotifyClient(ERxAllBytes | ERxOverrun);
+					break;
+					}
+				}
+			}
+		else
+			{
+			// or drop the data, writing 0 to the FIFOL register
+			AsspRegister::Write32(a->iChannelBase + KHoCSIIFifoL, 0);
+			}
+
+		// Clear the  RxThreshold interrupt
+		AsspRegister::Write32(a->iChannelBase + KHoCSIIntStatus, KHtCSIIntStatusRxTrgIE);
+
+		} // end of reception processing..
+	}
+
+// overloaded constructor
+DCsiChannelSlave::DCsiChannelSlave(TInt aChannelNumber,
+	const DIicBusChannel::TBusType aBusType,
+	const DIicBusChannel::TChannelDuplex aChanDuplex) :
+	DIicBusChannelSlave(aBusType, aChanDuplex, 0),
+	iHwGuardTimer(TimeoutCallback, this)
+	{
+    iHwTimeoutValue = -1;
+	iChannelNumber = aChannelNumber;
+	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelSlave::DCsiChannelSlave, iChannelNumber = %d\n", iChannelNumber));
+	}
+
+// 2nd stage object construction
+TInt DCsiChannelSlave::DoCreate()
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("\nDCsiChannelSlave::DoCreate, ch: %d \n", iChannelNumber));
+
+	TUint32 channelBase;
+
+	HCR::TSettingId channelBaseId;
+	channelBaseId.iCat = KHcrCat_MHA_HWBASE;
+
+	TInt r = KErrNone;
+	switch (iChannelNumber)
+		{
+		case 0:
+			channelBaseId.iKey = KHcrKey_HwBase_CSI0;
+			break;
+		case 1:
+			channelBaseId.iKey = KHcrKey_HwBase_CSI1;
+			break;
+		default:
+			__KTRACE_OPT(KIIC, Kern::Printf("Wrong ChannelNumber specified (%d)", iChannelNumber));
+			return KErrArgument;
+		}
+
+	r = HCR::GetUInt(channelBaseId, channelBase);
+	iChannelBase = channelBase;
+
+	if(r != KErrNone)
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("Failed to read HCR setting for category = %d and key = %d\n", channelBaseId.iCat, channelBaseId.iKey));
+		return r;
+		}
+
+	//Read the timeout value from HCR
+	if(iHwTimeoutValue == -1) 
+        {
+        HCR::TSettingId settingId;
+        // csiTimeout values was not yet read from HCR; read it
+        settingId.iCat = KHcrCat_HWServ_CSI;
+        settingId.iKey = KHcrKey_CSI_Timeout;
+    
+        TInt r = HCR::GetInt(settingId, iHwTimeoutValue);
+        if(r != KErrNone) 
+            {
+            __KTRACE_OPT(KIIC, Kern::Printf("Failed to read HCR setting for category = %d and key = %d\n", settingId.iCat, settingId.iKey));
+            return r;
+            }
+        }
+	
+	// PIL Base class initialization.
+	r = Init();
+
+	// set the unique Slave's iChannelId
+	// THis, along with the instance count of opened Slave channels - will be returned to the client
+ 	// as he captures the Channel (in the referenced aChannelId making an unique ID) - and if the capture is
+	// successful he refers to this channel using the returned ChannelId.
+
+	// For now, let's just use the combination of iChannelNumber/iChannelBase(register address))
+	// This might be later replaced by the call into ConfRep to obtain the iChannelId for the PSL.
+	iChannelId = 0xffff & (iChannelNumber + iChannelBase);
+
+	return r;
+	}
+
+// static method used to construct the DCsiChannelSlave object.
+#ifdef STANDALONE_CHANNEL
+EXPORT_C
+#endif
+DCsiChannelSlave* DCsiChannelSlave::New(TInt aChannelNumber, const TBusType aBusType, const TChannelDuplex aChanDuplex)
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelSlave::NewL(): aChannelNumber = %d, BusType =%d", aChannelNumber, aBusType));
+	DCsiChannelSlave *pChan = new DCsiChannelSlave(aChannelNumber, aBusType, aChanDuplex);
+
+	TInt r = KErrNoMemory;
+	if (pChan)
+		{
+		r = pChan->DoCreate();
+		}
+	if (r != KErrNone)
+		{
+		delete pChan;
+		pChan = NULL;
+		}
+
+	return pChan;
+	}
+
+// Validates the various Fields in the transaction header
+// THis is a pure virtual.. which.. is never called by the PIL?..
+TInt DCsiChannelSlave::CheckHdr(TDes8* aHdrBuff)
+	{
+	TInt r = KErrNone;
+
+	if(!aHdrBuff)
+		{
+		r = KErrArgument;
+		}
+	else
+		{
+		TConfigSpiBufV01* headerBuf = (TConfigSpiBufV01*) aHdrBuff;
+		TConfigSpiV01 &spiHeader = (*headerBuf)();
+
+		if(spiHeader.iTransactionWaitCycles > 15) // (can be 0 - 15)
+			{
+			__KTRACE_OPT(KIIC, Kern::Printf("iTransactionWaitCycles not supported"));
+			r = KErrNotSupported;
+			}
+		else
+			{
+			if(spiHeader.iWordWidth != ESpiWordWidth_8 &&
+			spiHeader.iWordWidth != ESpiWordWidth_16)
+				{
+				__KTRACE_OPT(KIIC, Kern::Printf("iWordWidth not supported"));
+				r = KErrNotSupported;
+				}
+			}
+		}
+	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelSlave::CheckHdr() r %d", r));
+
+	return r;
+	}
+
+void DCsiChannelSlave::ProcessData(TInt aTrigger, TIicBusSlaveCallback* aCb)
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelSlave::ProcessData(), trigger: %x, in progress %d", aTrigger, iInProgress));
+	TInt intState;
+
+	// if NotifyClient was called due to SS line de-assertion..
+	TInt inProgress;
+	intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
+	inProgress = iInProgress;
+	__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
+
+	if(!inProgress &&
+	   (aTrigger & (ERxAllBytes | ETxAllBytes)))
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("Finished, cleaning.."));
+		// we migh be still receiving or transmitting data, so must wait until the end of the transmission
+		// start the guard timer, which - in case of the following while got stucked - will
+		// unblock this dfc by changing iTransactionStatus
+		iTransactionStatus = KErrNone;
+
+		iHwGuardTimer.OneShot(NKern::TimerTicks(iHwTimeoutValue));
+
+		// active wait until the transfer has finished
+		while((iTransactionStatus == KErrNone) &&
+		      (AsspRegister::Read32(iChannelBase + KHoCSIModeControl) & KHtCSIModeTransferState));
+
+		// clear CSIE bit..
+		AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, KHtCSIModeEnable, 0);
+
+		// check if the the guard timer or transaction timer hasn't expired..
+		if(iTransactionStatus != KErrNone)
+			{
+			__KTRACE_OPT(KIIC, Kern::Printf("CsiChannelMaster::TransferEndDfc(): Transaction timed-out"));
+			return;
+			}
+		else
+			{
+			iHwGuardTimer.Cancel();
+			}
+
+		// clear internal flags
+		intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
+		iTrigger = 0;
+		__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
+		}
+
+	// if the transaction was finished
+	// NotifyClient() with ERxAllBytes (and)or  ETxAllBytes called, when SS pin is de-asserted
+	// this indicated end of the transmission. Check buffer boundaries, as if Rx or Tx buffers
+	// provided by the client were bigger - this indicates ERxUnderrun or ETxOverrun - accordingly
+	// Rx..
+	if(aTrigger & ERxAllBytes)
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("Rx Buf:    %x", iRxData));
+		__KTRACE_OPT(KIIC, Kern::Printf("Rx BufeND: %x", iRxDataEnd));
+
+		__KTRACE_OPT(KIIC, Kern::Printf("\n\nTxFifo level %d", AsspRegister::Read32(iChannelBase + KHoCSIOFifoL)));
+		__KTRACE_OPT(KIIC, Kern::Printf("RxFifo level %d\n\n", AsspRegister::Read32(iChannelBase + KHoCSIIFifoL)));
+
+		// clear the internal EReceive flag..
+		intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
+		iTrigger &= ~EReceive;
+		__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
+
+		// update the buffer information in the Callback object..
+		aCb->SetRxWords(iNumRxWords - ((iRxDataEnd - iRxData) / iWordSize));
+		}
+
+	// Tx...
+	if(aTrigger & ETxAllBytes)
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("Tx Buf:    %x", iTxData));
+		__KTRACE_OPT(KIIC, Kern::Printf("Tx BufeND: %x", iTxDataEnd));
+
+		// set the callback's TxWords value
+		__KTRACE_OPT(KIIC, Kern::Printf("aCb->SetTxWords %d", iNumTxWords - ((iTxDataEnd - iTxData) / iWordSize)));
+
+		// clear the internal ETransmit flag..
+		intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
+		iTrigger &= ~ETransmit;
+		__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
+
+		// update the buffer information in the Callback object..
+		aCb->SetTxWords(iNumTxWords - ((iTxDataEnd - iTxData) / iWordSize));
+		}
+
+	if(aTrigger & EGeneralBusError)
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("BusError.."));
+		// clear CSIE bit..and disable HW interrupts..
+		AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, KHtCSIModeEnable | KSlaveInterruptFlags, 0);
+
+		// clear internal flags
+		intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
+		iTrigger = 0;
+		__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
+		}
+
+	// set the callback's trigger..
+	aCb->SetTrigger(aTrigger | aCb->GetTrigger());
+	}
+
+// Initializes the hardware with the data provided in the transaction and slave-address field
+TInt DCsiChannelSlave::ConfigureInterface()
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("ConfigureInterface()"));
+
+	HCR::TSettingId settingId;
+	TConfigSpiBufV01* aBuf = (TConfigSpiBufV01*) iConfigHeader;
+	TConfigSpiV01 &spiHeader = (*aBuf)();
+
+	// CSI initialization procedure:
+	// 1. clear CISE bit..
+	AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, KHtCSIModeEnable, 0);
+
+	// 2. wait until CIS_MODE.bit0 (CSOT) changes to 0
+	// start the GuardTimer before while-loop..
+	iTransactionStatus = KErrNone;
+
+	iHwGuardTimer.OneShot(NKern::TimerTicks(iHwTimeoutValue));
+
+	while((iTransactionStatus == KErrNone) &&
+	       AsspRegister::Read32(iChannelBase + KHoCSIModeControl) & KHtCSIModeTransferState);
+
+	// check if the the guard timer or transaction timer hasn't expired..
+	if(iTransactionStatus != KErrNone)
+		{
+		return KErrGeneral;
+		}
+	else
+		{
+		iHwGuardTimer.Cancel();
+		}
+
+	// 3. set CSIRST bit..
+	AsspRegister::Modify32(iChannelBase + KHoCSIControl, 0, KHtCSIControlCSIRst);
+
+	// 4. set KHoCSIClockSelect register..
+	TUint32 val = 0;
+
+	// CKP - ClocK Polarity (bit 4) 0: initial value is high, 1: initial val is low
+	// DAP - Clock phase select (bit 3) 0: 180 degree delay, 1: 0 degree delay
+	// @** don't use DAP=1 when iClock set to KHCSIClockValPCLKdiv4 (HW bug..see SoC errata)
+	switch (spiHeader.iClkMode)
+		{
+		case ESpiPolarityLowRisingEdge: // Active high, odd edges
+			val = KHtCSIClockSelectCKP; // CKP 1, DAP 0
+			break;
+		case ESpiPolarityLowFallingEdge: // Active high, even edges
+			val = KHtCSIClockSelectCKP | // CKP 1, DAP 1
+			      KHtCSIClockSelectDAP;
+			break;
+
+		case ESpiPolarityHighFallingEdge: // Active low,  odd edges
+			val = 0; // CKP 0, DAP 0
+			break;
+
+		case ESpiPolarityHighRisingEdge: // Active low,  even edges
+			val = KHtCSIClockSelectDAP; // CKP 0, DAP 1
+			break;
+		default:
+			break; // there's no default..no other value can be specified as it's an enum ;)
+		}
+
+	// we are a Slave - so we use only one setting for the clk speed, ignoring the header
+	val |= KHCSIClockValSlave;
+
+	// Set the SS pin configuration..
+	val |= KHtCSIClockSelectSSE; // SS pin enable
+
+	if (spiHeader.iSSPinActiveMode == ESpiCSPinActiveHigh)
+		{
+		val |= KHtCSIClockSelectSSPol; //  1: SS pin high active
+		}
+
+	// store iSSPinActiveMode internaly - it will be used in interrupts.
+	iSSPinActiveMode = spiHeader.iSSPinActiveMode;
+
+	// set transaction wait time..
+	val |= (0xf & spiHeader.iTransactionWaitCycles) << KHsCSIModeTWait;
+
+	// and finally update the register
+	AsspRegister::Write32(iChannelBase + KHoCSIClockSelect, val);
+
+	// 5. clear KHtCSIControlCSIRst bit..
+	AsspRegister::Modify32(iChannelBase + KHoCSIControl, KHtCSIControlCSIRst, 0);
+
+	// 6. Set Mode Control register:
+	// Transmission and reception mode
+	val = KHtCSIModeTrEnable;
+
+	// Select transmit data length (8/16 bits)
+	if (spiHeader.iWordWidth == ESpiWordWidth_16)
+		{
+		iWordSize = 2;
+		val |= KHtCSIModeDataLen;
+		}
+	else
+		{
+		iWordSize = 1;
+		}
+
+	// Select Transfer direction (if set-LSB first)
+	if (spiHeader.iBitOrder == ELsbFirst)
+		{
+		val |= KHtCSIModeTransferDir;
+		}
+
+	// update the register
+	AsspRegister::Write32(iChannelBase + KHoCSIModeControl, val);
+
+	// 7. Set FIFO trigger levels
+	TUint8 csiFifoRxTrigerLvl; // set RxTrigger level
+	
+	settingId.iCat = KHcrCat_HWServ_CSI;
+	settingId.iKey = KHcrKey_CSI_FifoRxTrigerLvl;
+	TInt r = HCR::GetUInt(settingId, csiFifoRxTrigerLvl);
+	if(r != KErrNone) 
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("Failed to read HCR setting for category = %d and key = %d\n", settingId.iCat, settingId.iKey));
+		return r;
+		}
+	AsspRegister::Write32(iChannelBase + KHoCSIFifoTrgLvl,
+	                      (csiFifoRxTrigerLvl << KHsCSIRxFifoTrgLvl));
+
+	// 8. Clear all interrupts
+	AsspRegister::Write32(iChannelBase + KHoCSIIntStatus, KInterruptsAll);
+
+	// 9. Set RxTrig permission and enable TEnd and RxTrg interrupts
+	AsspRegister::Write32(iChannelBase + KHoCSIControl, KSlaveInterruptFlags);
+
+	// the timeout period to wait for a response from the client.
+	SetClientWaitTime(KClientWaitTime);
+	// if the KIIC debug trace flag is set, we need to increase the transaction timeout,
+	// so that debug traces don't cause timer expiration. This call will overwrite
+	// previously set value (SetClientWaitTime) and default value set by the PIL (SetMasterWaitTime)
+	__KTRACE_OPT(KIIC, SetClientWaitTime(KMaxWaitTime));
+	__KTRACE_OPT(KIIC, SetMasterWaitTime(KMaxWaitTime));
+
+
+	settingId.iCat = KHcrCat_MHA_Interrupt;
+	settingId.iKey = iChannelNumber == 0 ? KHcrKey_Interrupt_CSI0 : KHcrKey_Interrupt_CSI1;
+
+	TInt32 interruptId;
+	r = HCR::GetInt(settingId, interruptId);
+	if(r != KErrNone)
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("Failed to read HCR setting for category = %d and key = %d\n", settingId.iCat, settingId.iKey));
+		return r;
+		}
+
+	// Bind the ISR for the Slave
+	iInterruptId = Interrupt::Bind(interruptId, DCsiChannelSlave::CsiIsr, this);
+
+	// this returns interruptId or error code(err < 0)
+	if (iInterruptId < KErrNone)
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("ERROR: InterruptBind error.. %d", r));
+		Kern::Printf("ERROR: InterruptBind error.. %d", r);
+		r = iInterruptId;
+		}
+
+	return r;
+	}
+
+// This method starts data transfer - filling the Transmit FIFO and enabling the device (CSIE bit)
+TInt DCsiChannelSlave::InitTransfer()
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelSlave::InitTransfer()"));
+	//__KTRACE_OPT(KIIC, Kern::Printf("Receiving %d, Transmitting %d", (iTrigger & EReceive)>>4, (iTrigger & ETransmit)>>3));
+
+	TUint r = KErrNone;
+	TInt intState;
+	TInt trigger;
+
+	intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
+	if(!iInProgress)
+		{
+		// clean the FIFOs..
+		AsspRegister::Write32(iChannelBase + KHoCSIOFifoL, 0);
+		AsspRegister::Write32(iChannelBase + KHoCSIOFifoL, 0);
+
+		// clear CISE bit..re-enable all HW interrupts..
+		AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, KHtCSIModeEnable, KSlaveInterruptFlags);
+
+		// Clear all interrupts
+		AsspRegister::Write32(iChannelBase + KHoCSIIntStatus, KInterruptsAll);
+		}
+	__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
+
+
+	intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
+	trigger = iTrigger;
+	__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
+
+	// if we are transmitting - Add data to the FIFO..
+	if(trigger & ETransmit)
+		{
+		// Set mode to transmission and reception (Set TRMD)
+		AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, 0, KHtCSIModeTrEnable);
+
+		// enable TEND interrupt (e.g. if this is called during the transmission as the result of
+		// TxUnderrun event.
+		AsspRegister::Modify32(iChannelBase + KHoCSIControl, 0, KHtCSIControlTEndIE);
+
+		iWordSize = iTxGranularity >> 3;
+		iTxData = iTxBuf + (iWordSize * iTxOffset);
+		iTxDataEnd = iTxData + (iWordSize * iNumTxWords);
+
+		__KTRACE_OPT(KIIC, Kern::Printf("Tx Buf:    %x", iTxData));
+		__KTRACE_OPT(KIIC, Kern::Printf("Tx BufeND: %x", iTxDataEnd));
+
+		// copy data to the FIFO..
+		while(AsspRegister::Read32(iChannelBase + KHoCSIOFifoL) <= (KHwCSIFifoLMax - iWordSize) && // until FIFO not full..
+		      iTxData != iTxDataEnd) // or whole data has been copied.
+			{
+			TUint16 val;
+
+			// in 16bit mode we need to read MSB first..
+			if(iWordSize > 1)
+				{
+				val = (*iTxData) << 8; // MSB shifted up..
+				val |= *(iTxData + 1) & 0xff; // LSB..
+				}
+			else
+				{
+				val = *iTxData;
+				}
+
+			// write this value to the FIFO window register..
+			AsspRegister::Write32(iChannelBase + KHoCSIOFifo, val);
+
+			// increment the pointer.
+			iTxData += iWordSize;
+			}
+
+		__KTRACE_OPT(KIIC, Kern::Printf("After adding:\n\rTx Buf:    %x", iTxData));
+		__KTRACE_OPT(KIIC, Kern::Printf("Tx BufeND: %x", iTxDataEnd));
+		}
+
+	if(trigger & EReceive) // we are starting receive transfer only..
+		{
+		if(!(trigger & ETransmit))
+			{
+			// if only receiving - set it to reveive-only
+			// Set mode to reception only (clear TRMD)
+			AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, KHtCSIModeTrEnable, 0);
+			}
+
+		// enable RxTrg interrupt (e.g. if this is called during the transmission as the result
+		// of RxOverrun event.
+		AsspRegister::Modify32(iChannelBase + KHoCSIControl, 0, KHtCSIControlRxTrgIE);
+
+		iWordSize = iRxGranularity >> 3;
+		iRxData = iRxBuf + (iWordSize * iRxOffset);
+		iRxDataEnd = iRxData + (iWordSize * iNumRxWords);
+
+		__KTRACE_OPT(KIIC, Kern::Printf("Rx Buffer:  %x", iRxData));
+		__KTRACE_OPT(KIIC, Kern::Printf("Rx BufreND: %x", iRxDataEnd));
+		}
+
+	// enable interrupts..
+	Interrupt::Enable(iInterruptId);
+
+	// enable transmission..this will trigger the HW to start the transmission..
+	AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, 0, KHtCSIModeEnable);
+
+	return r;
+	}
+
+// aOperation is a bit-mask made of TPslOperation
+TInt DCsiChannelSlave::DoRequest(TInt aOperation)
+	{
+//	__KTRACE_OPT(KIIC, Kern::Printf("\n===>DCsiChannelSlave::DoRequest, Operation %x", aOperation));
+
+	TInt r = KErrNone;
+	TInt intState;
+
+	if (aOperation & EAsyncConfigPwrUp)
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("EAsyncConfigPwrUp"));
+		// this is called when the client calls IicBus::CaptureChannel() asynchronously
+		r = ConfigureInterface();
+		ChanCaptureCallback(r);
+		return r;
+		}
+
+	// PowerUp
+	if (aOperation & ESyncConfigPwrUp)
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("ESyncConfigPwrUp"));
+		// this is called when the client calls IicBus::CaptureChannel()
+		// - configure the channel with the configuration provided in the header.
+		r = ConfigureInterface();
+		// we can't continue in this case..
+		if (r != KErrNone)
+			{
+			__KTRACE_OPT(KIIC, Kern::Printf("Coudln't configure the interface..r %d", r));
+			return r;
+			}
+		}
+
+	if (aOperation & ETransmit)
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("ETransmit"));
+		intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
+		iTrigger |= ETransmit;
+		__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
+		}
+
+	if (aOperation & EReceive)
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("EReceive"));
+		intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
+		iTrigger |= EReceive;
+		__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
+		}
+
+	if (aOperation & (EReceive | ETransmit))
+		{
+		r = InitTransfer();
+		}
+
+	if (aOperation & EAbort)
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("EAbort"));
+		intState = __SPIN_LOCK_IRQSAVE(CsiSpinLock);
+		// disable CSI (clear CSIE bit), and interrupts
+		if(!iInProgress)
+			{
+			AsspRegister::Modify32(iChannelBase + KHoCSIModeControl, KHtCSIModeEnable | KSlaveInterruptFlags, 0);
+			iInProgress = EFalse;
+			iTrigger = 0;
+			}
+		__SPIN_UNLOCK_IRQRESTORE(CsiSpinLock, intState);
+		Interrupt::Disable(iInterruptId);
+		}
+
+	if (aOperation & EPowerDown)
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("EPowerDown"));
+
+		// set CSI Rst bit
+		AsspRegister::Write32(iChannelBase + KHoCSIModeControl, KHtCSIControlCSIRst);
+
+		// disable and unbind the ISR,
+		Interrupt::Disable(iInterruptId);
+		Interrupt::Unbind(iInterruptId);
+		}
+	return r;
+	}
+