omap3530/omap3530_drivers/spi/master.cpp
branchBYD_LCD_Integration
changeset 86 56c9b613f311
parent 85 d93b485c1325
child 112 fdfa12d9a47a
equal deleted inserted replaced
81:8b0d299f2a61 86:56c9b613f311
       
     1 // Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 // lukasz.forynski@gmail.com
       
    13 //
       
    14 // Description:
       
    15 // Implementation of IIC master channel for a SPI bus.
       
    16 //
       
    17 
       
    18 #define DBGPRINT(x)
       
    19 #define DBG_ERR(x) x
       
    20 
       
    21 
       
    22 #ifdef _DEBUG
       
    23 #define DEBUG_ONLY(x) //x
       
    24 #else
       
    25 #define DEBUG_ONLY(x)
       
    26 #endif
       
    27 
       
    28 
       
    29 // DO NOT CHANGE THESE- trying to tune the driver (unless you really know what you're doing)
       
    30 // as this this is only for development purpose to tune the driver. Fifo mode is not yet enabled, but this
       
    31 // doesn't affect operation. After development has been finished - these macros and #ifdefs will be removed
       
    32 // entirely. For now only SINGLE_MODE should ever be defined.
       
    33 //#define USE_TX_FIFO
       
    34 //#define USING_TX_COUNTER
       
    35 //#define PER_TRANSFER_MODE
       
    36 #define SINGLE_MODE
       
    37 
       
    38 #include <assp/omap3530_assp/omap3530_assp_priv.h>
       
    39 #include <assp/omap3530_assp/omap3530_prcm.h>
       
    40 #include <drivers/iic.h>
       
    41 #include "omap3530_spi.h"
       
    42 #include "psl_init.h"
       
    43 #include "master.h"
       
    44 
       
    45 DSpiMasterBeagle::DSpiMasterBeagle(TInt aChannelNumber, TBusType aBusType, TChannelDuplex aChanDuplex) :
       
    46 	DIicBusChannelMaster(aBusType, aChanDuplex),
       
    47 	iTransferEndDfc(TransferEndDfc, this, KIicPslDfcPriority)
       
    48 	{
       
    49 	iChannelNumber = aChannelNumber;
       
    50 	iIrqId  = KMcSpiIrqId[iChannelNumber];
       
    51 	iHwBase = KMcSpiRegBase[iChannelNumber];
       
    52 	iState  = EIdle;
       
    53 	iCurrSS = -1; // make sure channel will be fully configured on the first use
       
    54 	DBGPRINT(Kern::Printf("DSpiMasterBeagle::DSpiMasterBeagle: at 0x%x, iChannelNumber = %d", this, iChannelNumber));
       
    55 	}
       
    56 
       
    57 TInt DSpiMasterBeagle::DoCreate()
       
    58 	{
       
    59 	DBGPRINT(Kern::Printf("\nDSpiMasterBeagle::DoCreate() McSPI%d \n", iChannelNumber+1));
       
    60 	DBGPRINT(Kern::Printf("HW revision is %x", AsspRegister::Read32(iHwBase + MCSPI_REVISION)));
       
    61 	TInt r = KErrNone;
       
    62 
       
    63 	// Create the DFCQ to be used by the channel
       
    64 	if(!iDfcQ)
       
    65 		{
       
    66 		TBuf8<KMaxName> threadName (KIicPslThreadName);
       
    67 		threadName.AppendNum(iChannelNumber);
       
    68 		r = Kern::DfcQCreate(iDfcQ, KIicPslThreadPriority, &threadName);
       
    69 		if(r != KErrNone)
       
    70 			{
       
    71 			DBG_ERR(Kern::Printf("DFC Queue creation failed, channel number: %d, r = %d\n", iChannelNumber, r));
       
    72 			return r;
       
    73 			}
       
    74 		}
       
    75 
       
    76 	// PIL Base class initialization - this must be called prior to SetDfcQ(iDfcQ)
       
    77 	r = Init();
       
    78 	if(r == KErrNone)
       
    79 		{
       
    80 		// Call base class function to set DFCQ pointers in the required objects
       
    81 		// This also enables the channel to process transaction requests
       
    82 		SetDfcQ(iDfcQ);
       
    83 
       
    84 		// PSL DFCQ initialisation for local DFC
       
    85 		iTransferEndDfc.SetDfcQ(iDfcQ);
       
    86 
       
    87 		// Bind interrupts.
       
    88 		r = Interrupt::Bind(iIrqId, Isr, this);
       
    89 		if(r < KErrNone)
       
    90 			{
       
    91 			DBG_ERR(Kern::Printf("ERROR: InterruptBind error.. %d", r));
       
    92 			return r;
       
    93 			}
       
    94 		}
       
    95 
       
    96 	// Make sure clocks are enabled (TBD: this could go to 'PowerUp/PowerDown' if using PRM)
       
    97 	Prcm::SetClockState( Prcm::EClkMcSpi3_F, Prcm::EClkOn );
       
    98 	Prcm::SetClockState( Prcm::EClkMcSpi3_I, Prcm::EClkOn );
       
    99 	// TODO:consider auto-idle for PRCM.CM_AUTOIDLE1_CORE
       
   100 
       
   101 	// setup default spi pins. For channel 2 (McSPI3) it can be configured dynamically
       
   102 	SetupSpiPins(iChannelNumber);
       
   103 
       
   104 	return r;
       
   105 	}
       
   106 
       
   107 // A static method used to construct the DSpiMasterBeagle object.
       
   108 DSpiMasterBeagle* DSpiMasterBeagle::New(TInt aChannelNumber, const TBusType aBusType, const TChannelDuplex aChanDuplex)
       
   109 	{
       
   110 	DBGPRINT(Kern::Printf("DSpiMasterBeagle::NewL(): ChannelNumber = %d, BusType =%d", aChannelNumber, aBusType));
       
   111 	DSpiMasterBeagle *pChan = new DSpiMasterBeagle(aChannelNumber, aBusType, aChanDuplex);
       
   112 
       
   113 	TInt r = KErrNoMemory;
       
   114 	if(pChan)
       
   115 		{
       
   116 		r = pChan->DoCreate();
       
   117 		}
       
   118 	if(r != KErrNone)
       
   119 		{
       
   120 		delete pChan;
       
   121 		pChan = NULL;
       
   122 		}
       
   123 	return pChan;
       
   124 	}
       
   125 
       
   126 // This method is called by the PIL to initiate the transaction. After finishing it's processing,
       
   127 // the PSL calls the PIL function CompleteRequest to indicate the success (or otherwise) of the request
       
   128 TInt DSpiMasterBeagle::DoRequest(TIicBusTransaction* aTransaction)
       
   129 	{
       
   130 	DBGPRINT(Kern::Printf("\n=>DSpiMasterBeagle::DoRequest (aTransaction=0x%x)\n", aTransaction));
       
   131 
       
   132 	// If the pointer to the transaction passed in as a parameter, or its associated pointer to the
       
   133 	// header information is NULL, return KErrArgument
       
   134 	if(!aTransaction || !GetTransactionHeader(aTransaction))
       
   135 		{
       
   136 		return KErrArgument;
       
   137 		}
       
   138 
       
   139 	// The PSL operates a simple state machine to ensure that only one transaction is processed
       
   140 	// at a time - if the channel is currently busy, reject the request (PIL should not try that!)
       
   141 	if(iState != EIdle)
       
   142 		{
       
   143 		return KErrInUse;
       
   144 		}
       
   145 
       
   146 	// copy pointer to the transaction
       
   147 	iCurrTransaction = aTransaction;
       
   148 
       
   149 	// Configure the hardware to support the transaction
       
   150 	TInt r = PrepareConfiguration();
       
   151 	if(r == KErrNone)
       
   152 		{
       
   153 		r = ConfigureInterface();
       
   154 		if(r == KErrNone)
       
   155 			{
       
   156 			// start processing transfers of this transaction.
       
   157 			r = ProcessNextTransfers();
       
   158 			}
       
   159 		}
       
   160 	return r;
       
   161 	}
       
   162 
       
   163 TInt DSpiMasterBeagle::PrepareConfiguration()
       
   164 	{
       
   165 	TConfigSpiV01 &newHeader = (*(TConfigSpiBufV01*) (GetTransactionHeader(iCurrTransaction)))();
       
   166 
       
   167 	// get the slave address (i.e. known as a 'channel' for the current SPI module)
       
   168 	TInt busId       = iCurrTransaction->GetBusId();
       
   169 	TInt slaveAddr   = GET_SLAVE_ADDR(busId);
       
   170 	TInt slavePinSet = 0;
       
   171 
       
   172 	if(slaveAddr >= KMcSpiNumSupportedSlaves[iChannelNumber]) // address is 0-based
       
   173 		{
       
   174 		DBG_ERR(Kern::Printf("Slave address for McSPI%d should be < %, was: %d !",
       
   175 				iChannelNumber + 1, KMcSpiNumSupportedSlaves[iChannelNumber], slaveAddr));
       
   176 		return KErrArgument; // Slave address out of range
       
   177 		}
       
   178 
       
   179 	// Slave addresses > 1 for McSPI3 (iChannel2) really means alternative pin settings,
       
   180 	// so adjust it in such case. *Pin set indexes are +1 to skip over the pin set for McSPI4
       
   181 	// channel in the pin configuration table.
       
   182 	if(iChannelNumber == 2 && slaveAddr > 1)
       
   183 		{
       
   184 		slavePinSet  =  slaveAddr > 3 ?  3 : 2; // slaveAddr: 2-3: pin set 2(1*); 4-5: pin set 3(2*)
       
   185 		slaveAddr &= 1; // modulo 2 (i.e. 2 CS for McSPI3)
       
   186 		}
       
   187 
       
   188 	// reconfigure pins if needed..
       
   189 	if(slavePinSet != iCurrSlavePinSet)
       
   190 		{
       
   191 		iCurrSlavePinSet = slavePinSet;
       
   192 		SetupSpiPins(iChannelNumber, iCurrSlavePinSet);
       
   193 		}
       
   194 
       
   195 	// store configuration parameters
       
   196 	iCurrSS          = slaveAddr;
       
   197 	iCurrHeader      = newHeader; //copy the header..
       
   198 
       
   199 	return KErrNone;
       
   200 	}
       
   201 
       
   202 // Init the hardware with the data provided in the transaction and slave-address field
       
   203 // (these values are already stored in the iCurrHeader)
       
   204 TInt DSpiMasterBeagle::ConfigureInterface()
       
   205 	{
       
   206 	DBGPRINT(Kern::Printf("ConfigureInterface()"));
       
   207 
       
   208 	// soft reset the SPI..
       
   209 	TUint val = AsspRegister::Read32(iHwBase + MCSPI_SYSCONFIG);
       
   210 	val = MCSPI_SYSCONFIG_SOFTRESET;  // issue reset
       
   211 
       
   212 	AsspRegister::Write32(iHwBase + MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_SOFTRESET);
       
   213 
       
   214 	val = 0; // TODO will add here this 'smart-wait' stuff that was proposed earlier..
       
   215 	while (!(val & MCSPI_SYSSTATUS_RESETDONE))
       
   216 		val = AsspRegister::Read32(iHwBase + MCSPI_SYSSTATUS);
       
   217 
       
   218 	// disable and clear all interrupts..
       
   219 	AsspRegister::Write32(iHwBase + MCSPI_IRQENABLE, 0);
       
   220 	AsspRegister::Write32(iHwBase + MCSPI_IRQSTATUS,
       
   221 	                      MCSPI_IRQ_RX_FULL(iCurrSS) |
       
   222 	                      MCSPI_IRQ_RX_FULL(iCurrSS) |
       
   223 	                      MCSPI_IRQ_TX_UNDERFLOW(iCurrSS) |
       
   224 	                      MCSPI_IRQ_TX_EMPTY(iCurrSS) |
       
   225 	                      MCSPI_IRQ_RX_OVERFLOW);
       
   226 
       
   227 	// channel configuration
       
   228 	//	Set the SPI1.MCSPI_CHxCONF[18] IS bit to 0 for the spi1_somi pin in receive mode.
       
   229 	//	val = MCSPI_CHxCONF_IS; // pin selection (somi - simo)
       
   230 	// TODO configuration of PINS could also be configurable on a 'per SPI module' basis..
       
   231 
       
   232 	// Set the SPI1.MCSPI_CHxCONF[17] DPE1 bit to 0 and the SPI1.MCSPI_CHxCONF[16] DPE0 bit to 1 for the spi1.simo pin in transmit mode.
       
   233 	val = MCSPI_CHxCONF_DPE0;
       
   234 
       
   235 	// Set transmit & | receive mode for transmit only mode here. If needed - it will be changed dynamically.
       
   236 	val |= MCSPI_CHxCONF_TRM_NO_RECEIVE;
       
   237 
       
   238 	// set word length.
       
   239 	val |= SpiWordWidth(iCurrHeader.iWordWidth);
       
   240 
       
   241 	// use the appropriate word with (assuming the data is aligned to bytes).
       
   242 	if(iCurrHeader.iWordWidth > ESpiWordWidth_16)
       
   243 		{
       
   244 		iWordSize = 4;
       
   245 		}
       
   246 	else if (iCurrHeader.iWordWidth > ESpiWordWidth_8)
       
   247 		{
       
   248 		iWordSize = 2;
       
   249 		}
       
   250 	else
       
   251 		{
       
   252 		iWordSize = 1;
       
   253 		}
       
   254 
       
   255 	// set Slave Select / Chip select signal mode
       
   256 	val |= iCurrHeader.iSSPinActiveMode == ESpiCSPinActiveLow ? MCSPI_CHxCONF_EPOL_LOW : 0;
       
   257 
       
   258 	// set the CLK POL and PHA (clock mode)
       
   259 	val |= SpiClkMode(iCurrHeader.iClkMode);
       
   260 
       
   261 	// Set clock. Note that CheckHdr() will be called prior to this function for this header,
       
   262 	// so the value iClkSpeedHz is valid at this point, the KErrNotSupported is not possible
       
   263 	// so the return value check can be ommited here
       
   264 	val |= SpiClkValue(iCurrHeader.iClkSpeedHz);
       
   265 	// __ASSERT_DEBUG(val >= KErrNone, Kern::Fault("spi/master.cpp, line: ", __LINE__));
       
   266 
       
   267 #ifdef USE_TX_FIFO
       
   268 	// enable fifo for transmission..
       
   269 	// Update me: this can only set in a 'single' mode.. or for only one channel
       
   270 	// but at the momment IIC SPI is used in 'single' mode onlny..
       
   271 	val |= MCSPI_CHxCONF_FFEW;
       
   272 //	val |= MCSPI_CHxCONF_FFER; // fifo enable for receive.. (TODO)
       
   273 #endif
       
   274 
       
   275 	val |= (iCurrHeader.iTransactionWaitCycles & 3) << MCSPI_CHxCONF_TCS_SHIFT;
       
   276 
       
   277 	// update the register..
       
   278 	AsspRegister::Write32(iHwBase + MCSPI_CHxCONF(iCurrSS), val);
       
   279 
       
   280 	// set spim_somi pin direction to input
       
   281 	val = MCSPI_SYST_SPIDATDIR0;
       
   282 
       
   283 	// drive csx pin to inactive state
       
   284 	if(iCurrHeader.iSSPinActiveMode == ESpiCSPinActiveLow)
       
   285 		{
       
   286 		AsspRegister::Modify32(iHwBase + MCSPI_SYST, 1u << iCurrSS, 0);
       
   287 		}
       
   288 	else
       
   289 		{
       
   290 		AsspRegister::Modify32(iHwBase + MCSPI_SYST, 0, (1u << iCurrSS));
       
   291 		}
       
   292 
       
   293 	// Set the MS bit to 0 to provide the clock (ie. to setup as master)
       
   294 #ifndef SINGLE_MODE
       
   295 	AsspRegister::Write32(iHwBase + MCSPI_MODULCTRL, MCSPI_MODULCTRL_MS_MASTER);
       
   296 	// change the pad config - now the SPI drives the line appropriately..
       
   297 	SetCsActive(iChannelNumber, iCurrSS, iCurrSlavePinSet);
       
   298 #else
       
   299 	AsspRegister::Write32(iHwBase + MCSPI_MODULCTRL, MCSPI_MODULCTRL_MS_MASTER | MCSPI_MODULCTRL_SINGLE);
       
   300 #endif
       
   301 
       
   302 	return KErrNone;
       
   303 	}
       
   304 
       
   305 TInt DSpiMasterBeagle::ProcessNextTransfers()
       
   306 	{
       
   307 	DBGPRINT(Kern::Printf("DSpiMasterBeagle::ProcessNextTransfers():%s", iState==EIdle ? "first" : "next"));
       
   308 
       
   309 	// Since new transfers are strating, clear exisiting flags
       
   310 	iOperation.iValue = TIicOperationType::ENop;
       
   311 
       
   312 	// If this is the first transfer in the transaction the channel will be in state EIdle
       
   313 	if(iState == EIdle)
       
   314 		{
       
   315 		// Get the pointer to half-duplex transfer object..
       
   316 		iHalfDTransfer = GetTransHalfDuplexTferPtr(iCurrTransaction);
       
   317 
       
   318 		// Get the pointer to full-duplex transfer object..
       
   319 		iFullDTransfer = GetTransFullDuplexTferPtr(iCurrTransaction);
       
   320 
       
   321 		// Update the channel state to EBusy and initialise the transaction status
       
   322 		iState = EBusy;
       
   323 		iTransactionStatus = KErrNone;
       
   324 
       
   325 		// start timeout timer for this transaction
       
   326 		StartSlaveTimeOutTimer(iCurrHeader.iTimeoutPeriod);
       
   327 		}
       
   328 	else
       
   329 	// If not in state EIdle, get the next transfer in the linked-list held by the transaction
       
   330 		{
       
   331 		// Get the pointer the next half-duplex transfer object..
       
   332 		iHalfDTransfer = GetTferNextTfer(iHalfDTransfer);
       
   333 
       
   334 		// Get the pointer to the next half-duplex transfer object..
       
   335 		if(iFullDTransfer)
       
   336 			{
       
   337 			iFullDTransfer = GetTferNextTfer(iFullDTransfer);
       
   338 			}
       
   339 		}
       
   340 
       
   341 	TInt r = KErrNone;
       
   342 	if(!iFullDTransfer && !iHalfDTransfer)
       
   343 		{
       
   344 		// There is no more to transfer - and all previous were were completed,
       
   345 		DBGPRINT(Kern::Printf("All transfers completed successfully"));
       
   346 		ExitComplete(KErrNone);
       
   347 		}
       
   348 	else
       
   349 		{
       
   350 		// Process next transfers
       
   351 		TInt8 hDTrType = (TInt8) GetTferType(iHalfDTransfer);
       
   352 
       
   353 		if(iFullDTransfer)
       
   354 			{
       
   355 			// For full-duplex transfer setup the read transfer first, as it doesn't
       
   356 			// really start anything - SPI master starts operation when Tx (or clocks)starts..
       
   357 
       
   358 			if(hDTrType == TIicBusTransfer::EMasterRead)
       
   359 				{
       
   360 				r = StartTransfer(iHalfDTransfer, TIicBusTransfer::EMasterRead);
       
   361 				if(r != KErrNone)
       
   362 					{
       
   363 					return r;
       
   364 					}
       
   365 				r = StartTransfer(iFullDTransfer, TIicBusTransfer::EMasterWrite);
       
   366 				}
       
   367 			else // hDTrType == TIicBusTransfer::EMasterWrite)
       
   368 				{
       
   369 				r = StartTransfer(iFullDTransfer, TIicBusTransfer::EMasterRead);
       
   370 				if(r != KErrNone)
       
   371 					{
       
   372 					return r;
       
   373 					}
       
   374 				r = StartTransfer(iHalfDTransfer, TIicBusTransfer::EMasterWrite);
       
   375 				}
       
   376 			}
       
   377 		else
       
   378 		// This is a HalfDuplex transfer - so just start it
       
   379 			{
       
   380 			r = StartTransfer(iHalfDTransfer, hDTrType);
       
   381 			}
       
   382 		}
       
   383 	return r;
       
   384 	}
       
   385 
       
   386 TInt DSpiMasterBeagle::StartTransfer(TIicBusTransfer* aTransferPtr, TUint8 aType)
       
   387 	{
       
   388 	DBGPRINT(Kern::Printf("DSpiMasterBeagle::StartTransfer() @0x%x, aType: %s",
       
   389 			               aTransferPtr, aType == TIicBusTransfer::EMasterWrite ? "write" : "read"));
       
   390 
       
   391 	if(aTransferPtr == NULL)
       
   392 		{
       
   393 		DBG_ERR(Kern::Printf("DSpiMasterBeagle::StartTransfer - NULL pointer\n"));
       
   394 		return KErrArgument;
       
   395 		}
       
   396 
       
   397 	TInt r = KErrNone;
       
   398 
       
   399 	switch(aType)
       
   400 		{
       
   401 		case TIicBusTransfer::EMasterWrite:
       
   402 			{
       
   403 			DBGPRINT(Kern::Printf("Starting EMasterWrite, duplex=%x", iFullDTransfer));
       
   404 
       
   405 			// Get a pointer to the transfer object's buffer, to facilitate passing arguments to DoTransfer
       
   406 			const TDes8* desBufPtr = GetTferBuffer(aTransferPtr);
       
   407 
       
   408 			DBGPRINT(Kern::Printf("Length %d, iWordSize %d", desBufPtr->Length(), iWordSize));
       
   409 
       
   410 			// Store the current address and ending address for Transmission - they are required by the ISR and DFC
       
   411 			iTxData    = (TInt8*)  desBufPtr->Ptr();
       
   412 			iTxDataEnd = (TInt8*) (iTxData + desBufPtr->Length());
       
   413 			if ((TInt)iTxDataEnd % iWordSize)
       
   414 				{
       
   415 				DBG_ERR(Kern::Printf("Wrong configuration - word size does not match buffer length"));
       
   416 				return KErrArgument;
       
   417 				}
       
   418 
       
   419 			DBGPRINT(Kern::Printf("Tx: Start: %x, End %x, bytes %d", iTxData, iTxDataEnd, desBufPtr->Length()));
       
   420 
       
   421 			// Set the flag to indicate that we'll be transmitting data
       
   422 			iOperation.iOp.iIsTransmitting = ETrue;
       
   423 
       
   424 			// initiate the transmission..
       
   425 			r = DoTransfer(aType);
       
   426 			if(r != KErrNone)
       
   427 				{
       
   428 				DBG_ERR(Kern::Printf("Starting Write failed, r = %d", r));
       
   429 				}
       
   430 			break;
       
   431 			}
       
   432 
       
   433 		case TIicBusTransfer::EMasterRead:
       
   434 			{
       
   435 			DBGPRINT(Kern::Printf("Starting EMasterRead, duplex=%x", iFullDTransfer));
       
   436 
       
   437 			// Get a pointer to the transfer object's buffer, to facilitate passing arguments to DoTransfer
       
   438 			const TDes8* aBufPtr = GetTferBuffer(aTransferPtr);
       
   439 
       
   440 			// Store the current address and ending address for Reception - they are required by the ISR and DFC
       
   441 			iRxData = (TInt8*) aBufPtr->Ptr();
       
   442 			iRxDataEnd = (TInt8*) (iRxData + aBufPtr->Length());
       
   443 
       
   444 			DBGPRINT(Kern::Printf("Rx: Start: %x, End %x, bytes %d", iRxData, iRxDataEnd, aBufPtr->Length()));
       
   445 
       
   446 			// Set the flag to indicate that we'll be receiving data
       
   447 			iOperation.iOp.iIsReceiving = ETrue;
       
   448 
       
   449 			// initiate the reception
       
   450 			r = DoTransfer(aType);
       
   451 			if(r != KErrNone)
       
   452 				{
       
   453 				DBG_ERR(Kern::Printf("Starting Read failed, r = %d", r));
       
   454 				}
       
   455 			break;
       
   456 			}
       
   457 
       
   458 		default:
       
   459 			{
       
   460 			DBG_ERR(Kern::Printf("Unsupported TransactionType %x", aType));
       
   461 			r = KErrArgument;
       
   462 			break;
       
   463 			}
       
   464 		}
       
   465 
       
   466 	return r;
       
   467 	}
       
   468 
       
   469 // Method called by StartTransfer to actually initiate the transfers.
       
   470 TInt DSpiMasterBeagle::DoTransfer(TUint8 aType)
       
   471 	{
       
   472 	DBGPRINT(Kern::Printf("\nDSpiMasterBeagle::DoTransfer()"));
       
   473 	TInt r = KErrNone;
       
   474 
       
   475 	AsspRegister::Write32(iHwBase + MCSPI_IRQSTATUS, ~0);
       
   476 
       
   477 	switch(aType)
       
   478 		{
       
   479 		case TIicBusTransfer::EMasterWrite:
       
   480 			{
       
   481 			// enable the channel here..
       
   482 			AsspRegister::Write32(iHwBase + MCSPI_CHxCTRL(iCurrSS), MCSPI_CHxCTRL_EN);
       
   483 
       
   484 			AsspRegister::Modify32(iHwBase + MCSPI_IRQSTATUS, 0,
       
   485 			                       MCSPI_IRQ_TX_EMPTY(iCurrSS) /*| MCSPI_IRQ_TX_UNDERFLOW(iCurrSS)*/);
       
   486 
       
   487 			AsspRegister::Modify32(iHwBase + MCSPI_IRQENABLE, 0,
       
   488 			                       MCSPI_IRQ_TX_EMPTY(iCurrSS) /*| MCSPI_IRQ_TX_UNDERFLOW(iCurrSS)*/);
       
   489 
       
   490 #ifdef SINGLE_MODE
       
   491 			// in SINGLE mode needs to manually assert CS line for current
       
   492 			AsspRegister::Modify32(iHwBase + MCSPI_CHxCONF(iCurrSS), 0, MCSPI_CHxCONF_FORCE);
       
   493 
       
   494 			// change the pad config - now the SPI drives the line appropriately..
       
   495 			SetCsActive(iChannelNumber, iCurrSS, iCurrSlavePinSet);
       
   496 #endif /*SINGLE_MODE*/
       
   497 
       
   498 #ifdef USE_TX_FIFO
       
   499 			const TInt KTxFifoThreshold = 8;
       
   500 			TUint numWordsToTransfer = (iTxDataEnd - iTxData);
       
   501 			TUint wordsToWrite = Min(numWordsToTransfer/iWordSize, KTxFifoThreshold/iWordSize);
       
   502 
       
   503 
       
   504 			TInt iAlmostFullLevel = 0;
       
   505 			TInt iAlmostEmptyLevel = 1; //KTxFifoThreshold;
       
   506 
       
   507 			// setup FIFOs
       
   508 			AsspRegister::Write32(iHwBase + MCSPI_XFERLEVEL,
       
   509 								  MCSPI_XFERLEVEL_WCNT(0) | // total num words
       
   510 								  MCSPI_XFERLEVEL_AFL(iAlmostFullLevel)     | // Rx almost full
       
   511 								  MCSPI_XFERLEVEL_AEL(iAlmostEmptyLevel) );   // Tx almost empty
       
   512 
       
   513 			// copy data to fifo..
       
   514 			for (TInt i = 0; i < wordsToWrite; i++)
       
   515 				{
       
   516 				iTxData += iWordSize;
       
   517 				AsspRegister::Write32(iHwBase + MCSPI_TXx(iCurrSS), *(iTxData -iWordSize));
       
   518 				}
       
   519 
       
   520 #else /*USE_TX_FIFO*/
       
   521 
       
   522 			TUint val = 0;
       
   523 			for (TInt i = 0; i < iWordSize; i++)
       
   524 				{
       
   525 				val |= (*iTxData++) << i * 8;
       
   526 				}
       
   527 
       
   528 			DEBUG_ONLY(DumpCurrentStatus("DoTransfer(Write)"));
       
   529 			AsspRegister::Write32(iHwBase + MCSPI_TXx(iCurrSS), val);
       
   530 #endif /*USE_TX_FIFO*/
       
   531 
       
   532 			// enable system interrupt
       
   533 			Interrupt::Enable(iIrqId);
       
   534 			break;
       
   535 			}
       
   536 		case TIicBusTransfer::EMasterRead:
       
   537 			{
       
   538 			// enable transmit and receive..
       
   539 			AsspRegister::Modify32(iHwBase + MCSPI_CHxCONF(iCurrSS), MCSPI_CHxCONF_TRM_NO_RECEIVE, 0);
       
   540 
       
   541 			// for single read (not duplex) one way to to allow clock generation is to enable Tx
       
   542 			// and write '0' to Txregister (just like in duplex transaction). We also need to assert Cs line.
       
   543 			if(!iFullDTransfer)
       
   544 				{
       
   545 				// enable the channel..
       
   546 				AsspRegister::Write32(iHwBase + MCSPI_CHxCTRL(iCurrSS), MCSPI_CHxCTRL_EN);
       
   547 
       
   548 				// enable TX and RX Empty interrupts
       
   549 				AsspRegister::Modify32(iHwBase + MCSPI_IRQSTATUS, 0, MCSPI_IRQ_TX_EMPTY(iCurrSS) | MCSPI_IRQ_RX_FULL(iCurrSS));
       
   550 				AsspRegister::Modify32(iHwBase + MCSPI_IRQENABLE, 0, MCSPI_IRQ_TX_EMPTY(iCurrSS) | MCSPI_IRQ_RX_FULL(iCurrSS));
       
   551 #ifdef SINGLE_MODE
       
   552 				// in SINGLE mode needs to manually assert CS line for current
       
   553 				AsspRegister::Modify32(iHwBase + MCSPI_CHxCONF(iCurrSS), 0, MCSPI_CHxCONF_FORCE);
       
   554 
       
   555 				// change the pad config - now the SPI drives the line appropriately..
       
   556 				SetCsActive(iChannelNumber, iCurrSS, iCurrSlavePinSet);
       
   557 #endif /*SINGLE_MODE*/
       
   558 				}
       
   559 			else
       
   560 				{
       
   561 				// enable only interrupts for RX here. Tx is handled in EMasterWrite case above.
       
   562 				AsspRegister::Write32(iHwBase + MCSPI_IRQSTATUS, MCSPI_IRQ_RX_FULL(iCurrSS));
       
   563 				AsspRegister::Write32(iHwBase + MCSPI_IRQENABLE, MCSPI_IRQ_RX_FULL(iCurrSS));
       
   564 				}
       
   565 
       
   566 			DEBUG_ONLY(DumpCurrentStatus("DoTransfer(Read)"));
       
   567 			// and enable system interrupts
       
   568 			if(!iFullDTransfer)
       
   569 				Interrupt::Enable(iIrqId);
       
   570 			break;
       
   571 			}
       
   572 		default:
       
   573 			{
       
   574 			DBG_ERR(Kern::Printf("Unsupported TransactionType %x", aType));
       
   575 			r = KErrArgument;
       
   576 			break;
       
   577 			}
       
   578 		}
       
   579 
       
   580 	return r;
       
   581 	}
       
   582 
       
   583 #ifdef _DEBUG
       
   584 static TInt IsrCnt = 0;
       
   585 void DSpiMasterBeagle::DumpCurrentStatus(const TInt8* aWhere /*=NULL*/)
       
   586 	{
       
   587 	if(aWhere)
       
   588 		Kern::Printf("------ Status (%s)--------", aWhere);
       
   589 	else
       
   590 		Kern::Printf("------ Status --------");
       
   591 	Kern::Printf("\niTransactionStatus: %d", iTransactionStatus);
       
   592 	Kern::Printf("iTransferEndDfc %s queued", iTransferEndDfc.Queued() ? "" : "NOT");
       
   593 
       
   594 	if(iOperation.iOp.iIsTransmitting)
       
   595 		{
       
   596 		Kern::Printf("TX STATUS:");
       
   597 		Kern::Printf("  iTxData    %x", iTxData);
       
   598 		Kern::Printf("  iTxDataEnd %x", iTxDataEnd);
       
   599 		Kern::Printf("  left to write: %x (words)", (iTxDataEnd - iTxData)/iWordSize);
       
   600 		}
       
   601 
       
   602 	if(iOperation.iOp.iIsReceiving)
       
   603 		{
       
   604 		Kern::Printf("RX STATUS:");
       
   605 		Kern::Printf("  iRxData    %x", iRxData);
       
   606 		Kern::Printf("  iRxDataEnd %x", iRxDataEnd);
       
   607 		Kern::Printf("  left to read: %x (words)", (iRxDataEnd - iRxData)/iWordSize);
       
   608 		}
       
   609 	Kern::Printf("  iCurrSS %d",iCurrSS);
       
   610 
       
   611 	Kern::Printf("IsrCnt %d", IsrCnt);
       
   612 	TUint status = AsspRegister::Read32(iHwBase + MCSPI_IRQSTATUS);
       
   613 	Kern::Printf("MCSPI_IRQSTATUS (0x%x):", status);
       
   614 	if(status & MCSPI_IRQ_TX_EMPTY(iCurrSS))
       
   615 		Kern::Printf("   MCSPI_IRQ_TX_EMPTY");
       
   616 	if(status & MCSPI_IRQ_TX_UNDERFLOW(iCurrSS))
       
   617 		Kern::Printf("   MCSPI_IRQ_TX_UNDERFLOW");
       
   618 	if(!iCurrSS && status & MCSPI_IRQ_RX_OVERFLOW)
       
   619 		Kern::Printf("   MCSPI_IRQ_RX_OVERFLOW");
       
   620 	if(status & MCSPI_IRQ_RX_FULL(iCurrSS))
       
   621 		Kern::Printf("   MCSPI_IRQ_RX_FULL");
       
   622 
       
   623 	Kern::Printf("MCSPI_CHxSTAT(%d):", iCurrSS);
       
   624 	status = AsspRegister::Read32(iHwBase + MCSPI_CHxSTAT(iCurrSS));
       
   625 	if(status & MCSPI_CHxSTAT_RXFFF)
       
   626 		Kern::Printf("   MCSPI_CHxSTAT_RXFFF");
       
   627 	if(status & MCSPI_CHxSTAT_RXFFE)
       
   628 		Kern::Printf("   MCSPI_CHxSTAT_RXFFE");
       
   629 	if(status & MCSPI_CHxSTAT_TXFFF)
       
   630 		Kern::Printf("   MCSPI_CHxSTAT_TXFFF");
       
   631 	if(status & MCSPI_CHxSTAT_TXFFE)
       
   632 		Kern::Printf("   MCSPI_CHxSTAT_TXFFE");
       
   633 	if(status & MCSPI_CHxSTAT_EOT)
       
   634 		Kern::Printf("   MCSPI_CHxSTAT_EOT");
       
   635 	if(status & MCSPI_CHxSTAT_TXS)
       
   636 		Kern::Printf("   MCSPI_CHxSTAT_TXS");
       
   637 	if(status & MCSPI_CHxSTAT_RXS)
       
   638 		Kern::Printf("   MCSPI_CHxSTAT_RXS");
       
   639 
       
   640 	Kern::Printf("MCSPI_XFERLEVEL:");
       
   641 	status = AsspRegister::Read32(iHwBase + MCSPI_XFERLEVEL);
       
   642 	Kern::Printf("   MCSPI_XFERLEVEL_WCNT %d", status >> MCSPI_XFERLEVEL_WCNT_OFFSET);
       
   643 	Kern::Printf("   MCSPI_XFERLEVEL_AFL %d", (status >> MCSPI_XFERLEVEL_AFL_OFFSET) & 0x3F);
       
   644 	Kern::Printf("   MCSPI_XFERLEVEL_AEL %d\n", (status >> MCSPI_XFERLEVEL_AEL_OFFSET) & 0x1F);
       
   645 	Kern::Printf("---------------------------------------/*\n\n\n");
       
   646 	}
       
   647 #endif
       
   648 
       
   649 void DSpiMasterBeagle::Isr(TAny* aPtr)
       
   650 	{
       
   651 	DSpiMasterBeagle *a = (DSpiMasterBeagle*) aPtr;
       
   652 	DEBUG_ONLY(IsrCnt++);
       
   653 	DEBUG_ONLY(a->DumpCurrentStatus("Isr entry"));
       
   654 
       
   655 	TUint32 status = AsspRegister::Read32(a->iHwBase + MCSPI_IRQSTATUS);
       
   656 	AsspRegister::Write32(a->iHwBase + MCSPI_IRQSTATUS, status); // clear status bits..
       
   657 
       
   658 	// TX_EMPTY - when an item (or number of items if FIFO is used) was transmitted..
       
   659 	if(status & MCSPI_IRQ_TX_EMPTY(a->iCurrSS))
       
   660 		{
       
   661 
       
   662 		if(a->iOperation.iOp.iIsTransmitting)
       
   663 			{
       
   664 #ifdef USE_TX_FIFO
       
   665 			// when FIFO is used - should write (at least) the MCSPI_XFERLEVEL_AFL + 1 words to this register..
       
   666 			while(a->iTxData != a->iTxDataEnd)
       
   667 				{
       
   668 				AsspRegister::Write32(a->iHwBase + MCSPI_TXx(a->iCurrSS), *a->iTxData);
       
   669 				a->iTxData += a->iWordSize;	// Then increment the pointer to the data.s
       
   670 
       
   671 				if(AsspRegister::Read32(a->iHwBase + MCSPI_CHxSTAT(a->iCurrSS)) & MCSPI_CHxSTAT_TXFFF)
       
   672 					{
       
   673 					break;
       
   674 					}
       
   675 				}
       
   676 #else
       
   677 			// transfer next word..
       
   678 			if(a->iTxData != a->iTxDataEnd)
       
   679 				{
       
   680 				TUint val = 0;
       
   681 				for (TInt i = 0; i < a->iWordSize; i++)
       
   682 					{
       
   683 					val |= (*a->iTxData++) << i * 8;
       
   684 					}
       
   685 				AsspRegister::Write32(a->iHwBase + MCSPI_TXx(a->iCurrSS), val);
       
   686 				}
       
   687 
       
   688 			// check again - if this was the last one..and we're not waiting for rx - end transfer
       
   689 			if(a->iTxData == a->iTxDataEnd && !a->iOperation.iOp.iIsReceiving)
       
   690 				{
       
   691 				Interrupt::Disable(a->iIrqId);
       
   692 				a->iTransferEndDfc.Add();
       
   693 				}
       
   694 #endif
       
   695 			}
       
   696 		else
       
   697 			{
       
   698 			// writing a 'dummy' word (for read only transferss (writing 0 doesn't change line state)
       
   699 			AsspRegister::Write32(a->iHwBase + MCSPI_TXx(a->iCurrSS), 0);
       
   700 			}
       
   701 		}
       
   702 
       
   703 	if(status & MCSPI_IRQ_RX_FULL(a->iCurrSS))
       
   704 		{
       
   705 		if(a->iOperation.iOp.iIsReceiving)
       
   706 			{
       
   707 			if(a->iRxDataEnd != a->iRxData)
       
   708 				{
       
   709 				TUint8 nextRxValue = AsspRegister::Read32(a->iHwBase + MCSPI_RXx(a->iCurrSS));
       
   710 				*a->iRxData = nextRxValue;
       
   711 				a->iRxData += a->iWordSize;
       
   712 				}
       
   713 
       
   714 			// If the Rx buffer is now full, finish the transmission.
       
   715 			if(a->iRxDataEnd == a->iRxData)
       
   716 				{
       
   717 				Interrupt::Disable(a->iIrqId);
       
   718 				a->iTransferEndDfc.Add();
       
   719 				}
       
   720 			}
       
   721 		}
       
   722 
       
   723 #if 0 // TODO - probably master, as it creates CLK for slave - will never have to bother with this..
       
   724 	if(status & MCSPI_IRQ_TX_UNDERFLOW(a->iCurrSS))
       
   725 		{
       
   726 		DBG_ERR(Kern::Printf("Underflow"));
       
   727 		a->iTransactionStatus = KErrUnderflow;
       
   728 
       
   729 		// disable the channel..
       
   730 		AsspRegister::Modify32(a->iHwBase + MCSPI_CHxCTRL(0), MCSPI_CHxCTRL_EN, 0);
       
   731 		Interrupt::Disable(a->iIrqId);
       
   732 		DEBUG_ONLY(a->DumpCurrentStatus("TxUnderflow"));
       
   733 		DBG_ERR(Kern::Fault("TxUnderflow", 0));
       
   734 		}
       
   735 #endif
       
   736 #if defined(USE_TX_FIFO) && defined(USING_TX_COUNTER)
       
   737 	if(status & MCSPI_IRQSTATUS_EOW)
       
   738 		{
       
   739 		Kern::Printf("EOW");
       
   740 		// TODO: end of transfer..
       
   741 		}
       
   742 #endif
       
   743 
       
   744 	// end of ISR processing
       
   745 	DEBUG_ONLY(a->DumpCurrentStatus("Isr end"));
       
   746 	}
       
   747 
       
   748 void DSpiMasterBeagle::TransferEndDfc(TAny* aPtr)
       
   749 	{
       
   750 	DBGPRINT(Kern::Printf("DSpiMasterBeagle::TransferEndDfc"));
       
   751 	DSpiMasterBeagle *a = (DSpiMasterBeagle*) aPtr;
       
   752 
       
   753 	TUint chanStatus = AsspRegister::Read32(a->iHwBase + MCSPI_CHxSTAT(a->iCurrSS));
       
   754 	if(a->iOperation.iOp.iIsTransmitting)
       
   755 		{
       
   756 		TUint expected = MCSPI_CHxSTAT_EOT | MCSPI_CHxSTAT_TXS;
       
   757 
       
   758 #ifdef USE_TX_FIFO
       
   759 		while(!AsspRegister::Read32(a->iHwBase + MCSPI_CHxSTAT(a->iCurrSS)) & MCSPI_CHxSTAT_TXFFE);
       
   760 #endif
       
   761 		while(chanStatus & expected != expected)
       
   762 			{
       
   763 			chanStatus = AsspRegister::Read32(a->iHwBase + MCSPI_CHxSTAT(a->iCurrSS));
       
   764 			}
       
   765 		}
       
   766 
       
   767 	if(a->iOperation.iOp.iIsReceiving)
       
   768 		{
       
   769 		TUint expected = MCSPI_CHxSTAT_RXS;
       
   770 
       
   771 		while(chanStatus & expected != expected)
       
   772 			{
       
   773 			chanStatus = AsspRegister::Read32(a->iHwBase + MCSPI_CHxSTAT(a->iCurrSS));
       
   774 			}
       
   775 		__ASSERT_DEBUG(a->iRxDataEnd == a->iRxData,
       
   776 		               Kern::Fault("SPI master: exiting not having received all?", 12));
       
   777 		}
       
   778 
       
   779 #ifdef SINGLE_MODE
       
   780 	// manually de-assert CS line for this channel
       
   781 	AsspRegister::Modify32(a->iHwBase + MCSPI_CHxCONF(a->iCurrSS), MCSPI_CHxCONF_FORCE, 0);
       
   782 
       
   783 	// put the CS signal to 'inactive' state (as on channel disable it would have a glitch)
       
   784 	SetCsInactive(a->iChannelNumber, a->iCurrSS, a->iCurrHeader.iSSPinActiveMode, a->iCurrSlavePinSet);
       
   785 
       
   786 #endif
       
   787 
       
   788 	// disable the channel
       
   789 	AsspRegister::Modify32(a->iHwBase + MCSPI_CHxCTRL(0), MCSPI_CHxCTRL_EN, 0);
       
   790 
       
   791 	// Start the next transfer for this transaction, if any remain
       
   792 	if(a->iState == EBusy)
       
   793 		{
       
   794 		TInt err = a->ProcessNextTransfers();
       
   795 		if(err != KErrNone)
       
   796 			{
       
   797 			// If the next transfer could not be started, complete the transaction with
       
   798 			// the returned error code
       
   799 			a->ExitComplete(err);
       
   800 			}
       
   801 		}
       
   802 	}
       
   803 
       
   804 void DSpiMasterBeagle::ExitComplete(TInt aErr, TBool aComplete /*= ETrue*/)
       
   805 	{
       
   806 	DBGPRINT(Kern::Printf("DSpiMasterBeagle::ExitComplete, aErr %d, aComplete %d", aErr, aComplete));
       
   807 
       
   808 
       
   809 	// in the case of error - make sure to reset the channel
       
   810 	if(aErr != KErrNone)
       
   811 		{
       
   812 		// make sure CS is in inactive state (for the current / last transaction) on error
       
   813 		// TODO: add extendable transaction support (..i.e. with no de-assertion of CS pin between such transactions)
       
   814 		SetCsInactive(iChannelNumber, iCurrSS, iCurrHeader.iSSPinActiveMode, iCurrSlavePinSet);
       
   815 
       
   816 		// disable this channel
       
   817 		AsspRegister::Modify32(iHwBase + MCSPI_CHxCTRL(iCurrSS), MCSPI_CHxCTRL_EN, 0);
       
   818 
       
   819 		AsspRegister::Write32(iHwBase + MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_SOFTRESET);
       
   820 		iCurrSS = -1; // make sure the interface will be re-configured at next transaction
       
   821 		}
       
   822 
       
   823 	// Disable interrupts for the channel
       
   824 	Interrupt::Disable(iIrqId);
       
   825 
       
   826 	// Cancel any timers and DFCs..
       
   827 	CancelTimeOut();
       
   828 	iTransferEndDfc.Cancel();
       
   829 
       
   830 	// Change the channel state back to EIdle
       
   831 	iState = EIdle;
       
   832 
       
   833 	// Call the PIL method to complete the request
       
   834 	if(aComplete)
       
   835 		{
       
   836 		CompleteRequest(aErr);
       
   837 		}
       
   838 	}
       
   839 
       
   840 #ifdef _DEBUG
       
   841 void DumpHeader(TConfigSpiV01& aHeader)
       
   842 	{
       
   843 	Kern::Printf("header:");
       
   844 	Kern::Printf("iWordWidth %d (%d bits)", aHeader.iWordWidth, (SpiWordWidth(aHeader.iWordWidth)) >> MCSPI_CHxCONF_WL_OFFSET + 1);
       
   845 	Kern::Printf("iClkSpeedHz %d", aHeader.iClkSpeedHz);
       
   846 	Kern::Printf("iClkMode %d", aHeader.iClkMode);
       
   847 	Kern::Printf("iTimeoutPeriod %d", aHeader.iTimeoutPeriod);
       
   848 	Kern::Printf("iBitOrder %d", aHeader.iBitOrder);
       
   849 	Kern::Printf("iTransactionWaitCycles %d", aHeader.iTransactionWaitCycles);
       
   850 	Kern::Printf("iSSPinActiveMode %d", aHeader.iSSPinActiveMode);
       
   851 	}
       
   852 #endif
       
   853 
       
   854 // virtual method called by the PIL when a transaction is queued (with QueueTransaction).
       
   855 // This is done in the context of the Client's thread.
       
   856 // The PSL is required to check that the transaction header is valid for this channel.
       
   857 TInt DSpiMasterBeagle::CheckHdr(TDes8* aHdrBuff)
       
   858 	{
       
   859 	TInt r = KErrNone;
       
   860 	if(!aHdrBuff)
       
   861 		{
       
   862 		r = KErrArgument;
       
   863 		}
       
   864 	else
       
   865 		{
       
   866 		TConfigSpiV01 &header = (*(TConfigSpiBufV01*) (aHdrBuff))();
       
   867 
       
   868 		// check if word width and clock are supported
       
   869 		if(SpiWordWidth(header.iWordWidth) < KMinSpiWordWidth ||
       
   870 		   SpiClkValue(header.iClkSpeedHz) < 0 || // == KErrNotSupported
       
   871 		   header.iBitOrder == ELsbFirst ||  // this SPI only transmits MSB fist
       
   872 		   (TUint)header.iTransactionWaitCycles > KMaxTransactionWaitTime) // max 3(+.5) cycles between words
       
   873 			{
       
   874 #ifdef _DEBUG
       
   875 			if(header.iBitOrder == ELsbFirst)
       
   876 				DBG_ERR(Kern::Printf("iClkSpeedHz value (%d) is not supported", header.iClkSpeedHz));
       
   877 			if(SpiClkValue(header.iClkSpeedHz) < 0)
       
   878 				DBG_ERR(Kern::Printf("iClkSpeedHz: %d is not supported", header.iClkSpeedHz));
       
   879 			if((SpiWordWidth(header.iWordWidth)+ 1) >> MCSPI_CHxCONF_WL_OFFSET < KMinSpiWordWidth)
       
   880 				DBG_ERR(Kern::Printf("iWordWidth: %d is not supported, min value is: %d",
       
   881 						             SpiWordWidth(header.iWordWidth), KMinSpiWordWidth));
       
   882 			if((TUint)header.iTransactionWaitCycles > 3)
       
   883 				DBG_ERR(Kern::Printf("iTransactionWaitCycles: %d is not supported, value should be from 0 to %d",
       
   884 				                     header.iTransactionWaitCycles, KMaxTransactionWaitTime));
       
   885 
       
   886 			DumpHeader(header);
       
   887 #endif
       
   888 			r = KErrNotSupported;
       
   889 			DBG_ERR(Kern::Printf("DSpiMasterBeagle::CheckHdr()failed, r = %d", r));
       
   890 			}
       
   891 		}
       
   892 	return r;
       
   893 	}
       
   894 
       
   895 // This method is called by the PIL in the case of expiry of a timer for a transaction.
       
   896 // TODO: this name is confusing - it could be changed in the PIL to reflect it's real purpose(TBD)
       
   897 // It has NOTHING to do with a Slave (i.e. slave might be completely silent for SPI-and master won't notice it!)
       
   898 TInt DSpiMasterBeagle::HandleSlaveTimeout()
       
   899 	{
       
   900 	DBG_ERR(Kern::Printf("HandleSlaveTimeout"));
       
   901 
       
   902 	// Stop the PSL's operation, and inform the PIL of the timeout
       
   903 	ExitComplete(KErrTimedOut, EFalse);
       
   904 
       
   905 	return KErrTimedOut;
       
   906 	}
       
   907