omap3530/omap3530_drivers/spi/master.cpp
branchBeagle_BSP_dev
changeset 84 09e266454dcf
parent 82 65b40f262685
child 85 d93b485c1325
--- a/omap3530/omap3530_drivers/spi/master.cpp	Wed Sep 22 23:37:20 2010 +0100
+++ b/omap3530/omap3530_drivers/spi/master.cpp	Tue Sep 28 02:37:35 2010 +0100
@@ -47,18 +47,17 @@
 	iTransferEndDfc(TransferEndDfc, this, KIicPslDfcPriority)
 	{
 	iChannelNumber = aChannelNumber;
-	iIrqId = KMcSpiIrqId[iChannelNumber];
+	iIrqId  = KMcSpiIrqId[iChannelNumber];
 	iHwBase = KMcSpiRegBase[iChannelNumber];
-	iState = EIdle;
-	iCurrSS = -1;
+	iState  = EIdle;
+	iCurrSS = -1; // make sure channel will be fully configured on the first use
 	DBGPRINT(Kern::Printf("DSpiMasterBeagle::DSpiMasterBeagle: at 0x%x, iChannelNumber = %d", this, iChannelNumber));
 	}
 
 TInt DSpiMasterBeagle::DoCreate()
 	{
-	DBGPRINT(Kern::Printf("\nDSpiMasterBeagle::DoCreate() ch: %d \n", iChannelNumber));
+	DBGPRINT(Kern::Printf("\nDSpiMasterBeagle::DoCreate() McSPI%d \n", iChannelNumber+1));
 	DBGPRINT(Kern::Printf("HW revision is %x", AsspRegister::Read32(iHwBase + MCSPI_REVISION)));
-
 	TInt r = KErrNone;
 
 	// Create the DFCQ to be used by the channel
@@ -99,8 +98,8 @@
 	Prcm::SetClockState( Prcm::EClkMcSpi3_I, Prcm::EClkOn );
 	// TODO:consider auto-idle for PRCM.CM_AUTOIDLE1_CORE
 
+	// setup default spi pins. For channel 2 (McSPI3) it can be configured dynamically
 	SetupSpiPins(iChannelNumber);
-	// end of system wide settings..
 
 	return r;
 	}
@@ -148,44 +147,50 @@
 	iCurrTransaction = aTransaction;
 
 	// Configure the hardware to support the transaction
-	TInt r = KErrNone;
-	if(TransConfigDiffersFromPrev())
+	TInt r = PrepareConfiguration();
+	if(r == KErrNone)
 		{
 		r = ConfigureInterface();
-		if(r != KErrNone)
+		if(r == KErrNone)
 			{
-			return r;
+			// start processing transfers of this transaction.
+			r = ProcessNextTransfers();
 			}
 		}
-
-	// start processing transfers of this transaction.
-	r = ProcessNextTransfers();
 	return r;
 	}
 
-TBool DSpiMasterBeagle::TransConfigDiffersFromPrev()
+TInt DSpiMasterBeagle::PrepareConfiguration()
 	{
 	TConfigSpiV01 &newHeader = (*(TConfigSpiBufV01*) (GetTransactionHeader(iCurrTransaction)))();
 
 	// get the slave address (i.e. known as a 'channel' for the current SPI module)
-	TInt slaveAddr = GET_SLAVE_ADDR(iCurrTransaction->GetBusId());
-	DBGPRINT(Kern::Printf("slaveAddr %x", slaveAddr));
+	TInt busId       = iCurrTransaction->GetBusId();
+	TInt slaveAddr   = GET_SLAVE_ADDR(busId);
+	TInt slavePinSet = 0;
+
+	if(slaveAddr >= KMcSpiNumSupportedSlaves[iChannelNumber]) // address is 0-based
+		{
+		DBG_ERR(Kern::Printf("Slave address for McSPI%d should be < %, was: %d !",
+				iChannelNumber + 1, KMcSpiNumSupportedSlaves[iChannelNumber], slaveAddr));
+		return KErrArgument; // Slave address out of range
+		}
 
-	// compare it to the previous configuration..
-	if(slaveAddr                        != iCurrSS ||
-	   newHeader.iWordWidth             != iCurrHeader.iWordWidth ||
-	   newHeader.iClkSpeedHz            != iCurrHeader.iClkSpeedHz ||
-	   newHeader.iClkMode               != iCurrHeader.iClkMode ||
-	   newHeader.iTimeoutPeriod         != iCurrHeader.iTimeoutPeriod ||
-	   newHeader.iBitOrder              != iCurrHeader.iBitOrder ||
-	   newHeader.iTransactionWaitCycles != iCurrHeader.iTransactionWaitCycles ||
-	   newHeader.iSSPinActiveMode       != iCurrHeader.iSSPinActiveMode)
+	// Slave addresses > 1 for McSPI3 (iChannel2) really means alternative pin settings,
+	// so adjust it in such case. *Pin set indexes are +1 to skip over the pin set for McSPI4
+	// channel in the pin configuration table.
+	if(iChannelNumber == 2 && slaveAddr > 1)
 		{
-		iCurrSS = slaveAddr;
-		iCurrHeader = newHeader; //copy the header..
-		return ETrue;
+		slavePinSet  =  slaveAddr > 3 ?  3 : 2; // slaveAddr: 2-3: pin set 2(1*); 4-5: pin set 3(2*)
+		slaveAddr &= 1; // modulo 2 (i.e. 2 CS for McSPI3)
 		}
-	return EFalse;
+
+	// store configuration parameters
+	iCurrSS          = slaveAddr;
+	iCurrSlavePinSet = slavePinSet;
+	iCurrHeader      = newHeader; //copy the header..
+
+	return KErrNone;
 	}
 
 // Init the hardware with the data provided in the transaction and slave-address field
@@ -194,6 +199,12 @@
 	{
 	DBGPRINT(Kern::Printf("ConfigureInterface()"));
 
+	// make sure pins are set up properly (only for McSPI3)
+	if(iCurrSlavePinSet == 2)
+		{
+		SetupSpiPins(iChannelNumber, iCurrSlavePinSet);
+		}
+
 	// soft reset the SPI..
 	TUint val = AsspRegister::Read32(iHwBase + MCSPI_SYSCONFIG);
 	val = MCSPI_SYSCONFIG_SOFTRESET;  // issue reset
@@ -204,9 +215,14 @@
 	while (!(val & MCSPI_SYSSTATUS_RESETDONE))
 		val = AsspRegister::Read32(iHwBase + MCSPI_SYSSTATUS);
 
-	//AsspRegister::Write32(iHwBase + MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_CLOCKACTIVITY_ALL_ON);
-
-	AsspRegister::Write32(iHwBase + MCSPI_IRQSTATUS, ~0); // clear all interrupts (for now) -- normally only for channel..
+	// disable and clear all interrupts..
+	AsspRegister::Write32(iHwBase + MCSPI_IRQENABLE, 0);
+	AsspRegister::Write32(iHwBase + MCSPI_IRQSTATUS,
+	                      MCSPI_IRQ_RX_FULL(iCurrSS) |
+	                      MCSPI_IRQ_RX_FULL(iCurrSS) |
+	                      MCSPI_IRQ_TX_UNDERFLOW(iCurrSS) |
+	                      MCSPI_IRQ_TX_EMPTY(iCurrSS) |
+	                      MCSPI_IRQ_RX_OVERFLOW);
 
 	// channel configuration
 	//	Set the SPI1.MCSPI_CHxCONF[18] IS bit to 0 for the spi1_somi pin in receive mode.
@@ -259,24 +275,19 @@
 	// update the register..
 	AsspRegister::Write32(iHwBase + MCSPI_CHxCONF(iCurrSS), val);
 
-	// CS (SS) pin direction..
+	// set spim_somi pin direction to input
 	val = MCSPI_SYST_SPIDATDIR0;
 
-	// drive csx pin high or low
-//	val |= (iCurrHeader.iSSPinActiveMode == ESpiCSPinActiveLow)? 1 << iCurrSS : 0;
-//	AsspRegister::Modify32(iHwBase + MCSPI_SYST, val);
-
+	// drive csx pin to inactive state
 	if(iCurrHeader.iSSPinActiveMode == ESpiCSPinActiveLow)
 		{
-		AsspRegister::Modify32(iHwBase + MCSPI_SYST, 1u << iCurrSS, MCSPI_SYST_SPIDATDIR0);
+		AsspRegister::Modify32(iHwBase + MCSPI_SYST, 1u << iCurrSS, 0);
 		}
 	else
 		{
-		AsspRegister::Modify32(iHwBase + MCSPI_SYST, 0, (1u << iCurrSS) | MCSPI_SYST_SPIDATDIR0);
+		AsspRegister::Modify32(iHwBase + MCSPI_SYST, 0, (1u << iCurrSS));
 		}
 
-
-
 	// Set the MS bit to 0 to provide the clock (ie. to setup as master)
 #ifndef SINGLE_MODE
 	AsspRegister::Write32(iHwBase + MCSPI_MODULCTRL, MCSPI_MODULCTRL_MS_MASTER);
@@ -477,7 +488,7 @@
 			AsspRegister::Modify32(iHwBase + MCSPI_CHxCONF(iCurrSS), 0, MCSPI_CHxCONF_FORCE);
 
 			// change the pad config - now the SPI drives the line appropriately..
-			SetCsActive(iChannelNumber, iCurrSS);
+			SetCsActive(iChannelNumber, iCurrSS, iCurrSlavePinSet);
 #endif /*SINGLE_MODE*/
 
 #ifdef USE_TX_FIFO
@@ -538,7 +549,7 @@
 				AsspRegister::Modify32(iHwBase + MCSPI_CHxCONF(iCurrSS), 0, MCSPI_CHxCONF_FORCE);
 
 				// change the pad config - now the SPI drives the line appropriately..
-				SetCsActive(iChannelNumber, iCurrSS);
+				SetCsActive(iChannelNumber, iCurrSS, iCurrSlavePinSet);
 #endif /*SINGLE_MODE*/
 				}
 			else
@@ -761,28 +772,12 @@
 		               Kern::Fault("SPI master: exiting not having received all?", 12));
 		}
 
-	// make sure the CS pin is asserted..
-	if(a->iCurrHeader.iSSPinActiveMode == ESpiCSPinActiveLow)
-		{
-		AsspRegister::Modify32(a->iHwBase + MCSPI_SYST, 0, 1 << a->iCurrSS);
-		}
-	else
-		{
-		AsspRegister::Modify32(a->iHwBase + MCSPI_SYST, 1 << a->iCurrSS, 0);
-		}
-
 #ifdef SINGLE_MODE
 	// manually de-assert CS line for this channel
 	AsspRegister::Modify32(a->iHwBase + MCSPI_CHxCONF(a->iCurrSS), MCSPI_CHxCONF_FORCE, 0);
 
-	// drive csx pin high or low. Doing this here causes, that CS lines are toggled for each transfers.
-	TUint val = (a->iCurrHeader.iSSPinActiveMode == ESpiCSPinActiveLow)? 1 << a->iCurrSS : 0;
-	if (val)
-		{
-		AsspRegister::Modify32(a->iHwBase + MCSPI_SYST, 0, val);
-		}
 	// put the CS signal to 'inactive' state (as on channel disable it would have a glitch)
-	SetCsInactive(a->iChannelNumber, a->iCurrSS, a->iCurrHeader.iSSPinActiveMode);
+	SetCsInactive(a->iChannelNumber, a->iCurrSS, a->iCurrHeader.iSSPinActiveMode, a->iCurrSlavePinSet);
 
 #endif
 
@@ -807,15 +802,19 @@
 	DBGPRINT(Kern::Printf("DSpiMasterBeagle::ExitComplete, aErr %d, aComplete %d", aErr, aComplete));
 
 	// make sure CS is in inactive state (for the current / last transaction) on error
-	if(!aComplete)
+	// TODO: add extendable transaction support (..i.e. with no de-assertion of CS pin between such transactions)
+	SetCsInactive(iChannelNumber, iCurrSS, iCurrHeader.iSSPinActiveMode, iCurrSlavePinSet);
+
+	// disable this channel
+	AsspRegister::Modify32(iHwBase + MCSPI_CHxCTRL(iCurrSS), MCSPI_CHxCTRL_EN, 0);
+
+	// in the case of error - make sure to reset the channel
+	if(aErr != KErrNone)
 		{
-		SetCsInactive(iChannelNumber, iCurrSS, iCurrHeader.iSSPinActiveMode);
+		AsspRegister::Write32(iHwBase + MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_SOFTRESET);
+		iCurrSS = -1; // make sure the interface will be re-configured at next transaction
 		}
 
-	// disable this channel (and reset..)
-	AsspRegister::Modify32(iHwBase + MCSPI_CHxCTRL(iCurrSS), MCSPI_CHxCTRL_EN, 0);
-	AsspRegister::Write32(iHwBase + MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_SOFTRESET);
-
 	// Disable interrupts for the channel
 	Interrupt::Disable(iIrqId);