omap3530/omap3530_drivers/spi/master.cpp
branchBeagle_BSP_dev
changeset 84 09e266454dcf
parent 82 65b40f262685
child 85 d93b485c1325
equal deleted inserted replaced
83:bcf33365fd8d 84:09e266454dcf
    45 DSpiMasterBeagle::DSpiMasterBeagle(TInt aChannelNumber, TBusType aBusType, TChannelDuplex aChanDuplex) :
    45 DSpiMasterBeagle::DSpiMasterBeagle(TInt aChannelNumber, TBusType aBusType, TChannelDuplex aChanDuplex) :
    46 	DIicBusChannelMaster(aBusType, aChanDuplex),
    46 	DIicBusChannelMaster(aBusType, aChanDuplex),
    47 	iTransferEndDfc(TransferEndDfc, this, KIicPslDfcPriority)
    47 	iTransferEndDfc(TransferEndDfc, this, KIicPslDfcPriority)
    48 	{
    48 	{
    49 	iChannelNumber = aChannelNumber;
    49 	iChannelNumber = aChannelNumber;
    50 	iIrqId = KMcSpiIrqId[iChannelNumber];
    50 	iIrqId  = KMcSpiIrqId[iChannelNumber];
    51 	iHwBase = KMcSpiRegBase[iChannelNumber];
    51 	iHwBase = KMcSpiRegBase[iChannelNumber];
    52 	iState = EIdle;
    52 	iState  = EIdle;
    53 	iCurrSS = -1;
    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));
    54 	DBGPRINT(Kern::Printf("DSpiMasterBeagle::DSpiMasterBeagle: at 0x%x, iChannelNumber = %d", this, iChannelNumber));
    55 	}
    55 	}
    56 
    56 
    57 TInt DSpiMasterBeagle::DoCreate()
    57 TInt DSpiMasterBeagle::DoCreate()
    58 	{
    58 	{
    59 	DBGPRINT(Kern::Printf("\nDSpiMasterBeagle::DoCreate() ch: %d \n", iChannelNumber));
    59 	DBGPRINT(Kern::Printf("\nDSpiMasterBeagle::DoCreate() McSPI%d \n", iChannelNumber+1));
    60 	DBGPRINT(Kern::Printf("HW revision is %x", AsspRegister::Read32(iHwBase + MCSPI_REVISION)));
    60 	DBGPRINT(Kern::Printf("HW revision is %x", AsspRegister::Read32(iHwBase + MCSPI_REVISION)));
    61 
       
    62 	TInt r = KErrNone;
    61 	TInt r = KErrNone;
    63 
    62 
    64 	// Create the DFCQ to be used by the channel
    63 	// Create the DFCQ to be used by the channel
    65 	if(!iDfcQ)
    64 	if(!iDfcQ)
    66 		{
    65 		{
    97 	// Make sure clocks are enabled (TBD: this could go to 'PowerUp/PowerDown' if using PRM)
    96 	// Make sure clocks are enabled (TBD: this could go to 'PowerUp/PowerDown' if using PRM)
    98 	Prcm::SetClockState( Prcm::EClkMcSpi3_F, Prcm::EClkOn );
    97 	Prcm::SetClockState( Prcm::EClkMcSpi3_F, Prcm::EClkOn );
    99 	Prcm::SetClockState( Prcm::EClkMcSpi3_I, Prcm::EClkOn );
    98 	Prcm::SetClockState( Prcm::EClkMcSpi3_I, Prcm::EClkOn );
   100 	// TODO:consider auto-idle for PRCM.CM_AUTOIDLE1_CORE
    99 	// TODO:consider auto-idle for PRCM.CM_AUTOIDLE1_CORE
   101 
   100 
       
   101 	// setup default spi pins. For channel 2 (McSPI3) it can be configured dynamically
   102 	SetupSpiPins(iChannelNumber);
   102 	SetupSpiPins(iChannelNumber);
   103 	// end of system wide settings..
       
   104 
   103 
   105 	return r;
   104 	return r;
   106 	}
   105 	}
   107 
   106 
   108 // A static method used to construct the DSpiMasterBeagle object.
   107 // A static method used to construct the DSpiMasterBeagle object.
   146 
   145 
   147 	// copy pointer to the transaction
   146 	// copy pointer to the transaction
   148 	iCurrTransaction = aTransaction;
   147 	iCurrTransaction = aTransaction;
   149 
   148 
   150 	// Configure the hardware to support the transaction
   149 	// Configure the hardware to support the transaction
   151 	TInt r = KErrNone;
   150 	TInt r = PrepareConfiguration();
   152 	if(TransConfigDiffersFromPrev())
   151 	if(r == KErrNone)
   153 		{
   152 		{
   154 		r = ConfigureInterface();
   153 		r = ConfigureInterface();
   155 		if(r != KErrNone)
   154 		if(r == KErrNone)
   156 			{
   155 			{
   157 			return r;
   156 			// start processing transfers of this transaction.
   158 			}
   157 			r = ProcessNextTransfers();
   159 		}
   158 			}
   160 
   159 		}
   161 	// start processing transfers of this transaction.
       
   162 	r = ProcessNextTransfers();
       
   163 	return r;
   160 	return r;
   164 	}
   161 	}
   165 
   162 
   166 TBool DSpiMasterBeagle::TransConfigDiffersFromPrev()
   163 TInt DSpiMasterBeagle::PrepareConfiguration()
   167 	{
   164 	{
   168 	TConfigSpiV01 &newHeader = (*(TConfigSpiBufV01*) (GetTransactionHeader(iCurrTransaction)))();
   165 	TConfigSpiV01 &newHeader = (*(TConfigSpiBufV01*) (GetTransactionHeader(iCurrTransaction)))();
   169 
   166 
   170 	// get the slave address (i.e. known as a 'channel' for the current SPI module)
   167 	// get the slave address (i.e. known as a 'channel' for the current SPI module)
   171 	TInt slaveAddr = GET_SLAVE_ADDR(iCurrTransaction->GetBusId());
   168 	TInt busId       = iCurrTransaction->GetBusId();
   172 	DBGPRINT(Kern::Printf("slaveAddr %x", slaveAddr));
   169 	TInt slaveAddr   = GET_SLAVE_ADDR(busId);
   173 
   170 	TInt slavePinSet = 0;
   174 	// compare it to the previous configuration..
   171 
   175 	if(slaveAddr                        != iCurrSS ||
   172 	if(slaveAddr >= KMcSpiNumSupportedSlaves[iChannelNumber]) // address is 0-based
   176 	   newHeader.iWordWidth             != iCurrHeader.iWordWidth ||
   173 		{
   177 	   newHeader.iClkSpeedHz            != iCurrHeader.iClkSpeedHz ||
   174 		DBG_ERR(Kern::Printf("Slave address for McSPI%d should be < %, was: %d !",
   178 	   newHeader.iClkMode               != iCurrHeader.iClkMode ||
   175 				iChannelNumber + 1, KMcSpiNumSupportedSlaves[iChannelNumber], slaveAddr));
   179 	   newHeader.iTimeoutPeriod         != iCurrHeader.iTimeoutPeriod ||
   176 		return KErrArgument; // Slave address out of range
   180 	   newHeader.iBitOrder              != iCurrHeader.iBitOrder ||
   177 		}
   181 	   newHeader.iTransactionWaitCycles != iCurrHeader.iTransactionWaitCycles ||
   178 
   182 	   newHeader.iSSPinActiveMode       != iCurrHeader.iSSPinActiveMode)
   179 	// Slave addresses > 1 for McSPI3 (iChannel2) really means alternative pin settings,
   183 		{
   180 	// so adjust it in such case. *Pin set indexes are +1 to skip over the pin set for McSPI4
   184 		iCurrSS = slaveAddr;
   181 	// channel in the pin configuration table.
   185 		iCurrHeader = newHeader; //copy the header..
   182 	if(iChannelNumber == 2 && slaveAddr > 1)
   186 		return ETrue;
   183 		{
   187 		}
   184 		slavePinSet  =  slaveAddr > 3 ?  3 : 2; // slaveAddr: 2-3: pin set 2(1*); 4-5: pin set 3(2*)
   188 	return EFalse;
   185 		slaveAddr &= 1; // modulo 2 (i.e. 2 CS for McSPI3)
       
   186 		}
       
   187 
       
   188 	// store configuration parameters
       
   189 	iCurrSS          = slaveAddr;
       
   190 	iCurrSlavePinSet = slavePinSet;
       
   191 	iCurrHeader      = newHeader; //copy the header..
       
   192 
       
   193 	return KErrNone;
   189 	}
   194 	}
   190 
   195 
   191 // Init the hardware with the data provided in the transaction and slave-address field
   196 // Init the hardware with the data provided in the transaction and slave-address field
   192 // (these values are already stored in the iCurrHeader)
   197 // (these values are already stored in the iCurrHeader)
   193 TInt DSpiMasterBeagle::ConfigureInterface()
   198 TInt DSpiMasterBeagle::ConfigureInterface()
   194 	{
   199 	{
   195 	DBGPRINT(Kern::Printf("ConfigureInterface()"));
   200 	DBGPRINT(Kern::Printf("ConfigureInterface()"));
   196 
   201 
       
   202 	// make sure pins are set up properly (only for McSPI3)
       
   203 	if(iCurrSlavePinSet == 2)
       
   204 		{
       
   205 		SetupSpiPins(iChannelNumber, iCurrSlavePinSet);
       
   206 		}
       
   207 
   197 	// soft reset the SPI..
   208 	// soft reset the SPI..
   198 	TUint val = AsspRegister::Read32(iHwBase + MCSPI_SYSCONFIG);
   209 	TUint val = AsspRegister::Read32(iHwBase + MCSPI_SYSCONFIG);
   199 	val = MCSPI_SYSCONFIG_SOFTRESET;  // issue reset
   210 	val = MCSPI_SYSCONFIG_SOFTRESET;  // issue reset
   200 
   211 
   201 	AsspRegister::Write32(iHwBase + MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_SOFTRESET);
   212 	AsspRegister::Write32(iHwBase + MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_SOFTRESET);
   202 
   213 
   203 	val = 0; // TODO will add here this 'smart-wait' stuff that was proposed earlier..
   214 	val = 0; // TODO will add here this 'smart-wait' stuff that was proposed earlier..
   204 	while (!(val & MCSPI_SYSSTATUS_RESETDONE))
   215 	while (!(val & MCSPI_SYSSTATUS_RESETDONE))
   205 		val = AsspRegister::Read32(iHwBase + MCSPI_SYSSTATUS);
   216 		val = AsspRegister::Read32(iHwBase + MCSPI_SYSSTATUS);
   206 
   217 
   207 	//AsspRegister::Write32(iHwBase + MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_CLOCKACTIVITY_ALL_ON);
   218 	// disable and clear all interrupts..
   208 
   219 	AsspRegister::Write32(iHwBase + MCSPI_IRQENABLE, 0);
   209 	AsspRegister::Write32(iHwBase + MCSPI_IRQSTATUS, ~0); // clear all interrupts (for now) -- normally only for channel..
   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);
   210 
   226 
   211 	// channel configuration
   227 	// channel configuration
   212 	//	Set the SPI1.MCSPI_CHxCONF[18] IS bit to 0 for the spi1_somi pin in receive mode.
   228 	//	Set the SPI1.MCSPI_CHxCONF[18] IS bit to 0 for the spi1_somi pin in receive mode.
   213 	//	val = MCSPI_CHxCONF_IS; // pin selection (somi - simo)
   229 	//	val = MCSPI_CHxCONF_IS; // pin selection (somi - simo)
   214 	// TODO configuration of PINS could also be configurable on a 'per SPI module' basis..
   230 	// TODO configuration of PINS could also be configurable on a 'per SPI module' basis..
   257 #endif
   273 #endif
   258 
   274 
   259 	// update the register..
   275 	// update the register..
   260 	AsspRegister::Write32(iHwBase + MCSPI_CHxCONF(iCurrSS), val);
   276 	AsspRegister::Write32(iHwBase + MCSPI_CHxCONF(iCurrSS), val);
   261 
   277 
   262 	// CS (SS) pin direction..
   278 	// set spim_somi pin direction to input
   263 	val = MCSPI_SYST_SPIDATDIR0;
   279 	val = MCSPI_SYST_SPIDATDIR0;
   264 
   280 
   265 	// drive csx pin high or low
   281 	// drive csx pin to inactive state
   266 //	val |= (iCurrHeader.iSSPinActiveMode == ESpiCSPinActiveLow)? 1 << iCurrSS : 0;
       
   267 //	AsspRegister::Modify32(iHwBase + MCSPI_SYST, val);
       
   268 
       
   269 	if(iCurrHeader.iSSPinActiveMode == ESpiCSPinActiveLow)
   282 	if(iCurrHeader.iSSPinActiveMode == ESpiCSPinActiveLow)
   270 		{
   283 		{
   271 		AsspRegister::Modify32(iHwBase + MCSPI_SYST, 1u << iCurrSS, MCSPI_SYST_SPIDATDIR0);
   284 		AsspRegister::Modify32(iHwBase + MCSPI_SYST, 1u << iCurrSS, 0);
   272 		}
   285 		}
   273 	else
   286 	else
   274 		{
   287 		{
   275 		AsspRegister::Modify32(iHwBase + MCSPI_SYST, 0, (1u << iCurrSS) | MCSPI_SYST_SPIDATDIR0);
   288 		AsspRegister::Modify32(iHwBase + MCSPI_SYST, 0, (1u << iCurrSS));
   276 		}
   289 		}
   277 
       
   278 
       
   279 
   290 
   280 	// Set the MS bit to 0 to provide the clock (ie. to setup as master)
   291 	// Set the MS bit to 0 to provide the clock (ie. to setup as master)
   281 #ifndef SINGLE_MODE
   292 #ifndef SINGLE_MODE
   282 	AsspRegister::Write32(iHwBase + MCSPI_MODULCTRL, MCSPI_MODULCTRL_MS_MASTER);
   293 	AsspRegister::Write32(iHwBase + MCSPI_MODULCTRL, MCSPI_MODULCTRL_MS_MASTER);
   283 #else
   294 #else
   475 #ifdef SINGLE_MODE
   486 #ifdef SINGLE_MODE
   476 			// in SINGLE mode needs to manually assert CS line for current
   487 			// in SINGLE mode needs to manually assert CS line for current
   477 			AsspRegister::Modify32(iHwBase + MCSPI_CHxCONF(iCurrSS), 0, MCSPI_CHxCONF_FORCE);
   488 			AsspRegister::Modify32(iHwBase + MCSPI_CHxCONF(iCurrSS), 0, MCSPI_CHxCONF_FORCE);
   478 
   489 
   479 			// change the pad config - now the SPI drives the line appropriately..
   490 			// change the pad config - now the SPI drives the line appropriately..
   480 			SetCsActive(iChannelNumber, iCurrSS);
   491 			SetCsActive(iChannelNumber, iCurrSS, iCurrSlavePinSet);
   481 #endif /*SINGLE_MODE*/
   492 #endif /*SINGLE_MODE*/
   482 
   493 
   483 #ifdef USE_TX_FIFO
   494 #ifdef USE_TX_FIFO
   484 			const TInt KTxFifoThreshold = 8;
   495 			const TInt KTxFifoThreshold = 8;
   485 			TUint numWordsToTransfer = (iTxDataEnd - iTxData);
   496 			TUint numWordsToTransfer = (iTxDataEnd - iTxData);
   536 #ifdef SINGLE_MODE
   547 #ifdef SINGLE_MODE
   537 				// in SINGLE mode needs to manually assert CS line for current
   548 				// in SINGLE mode needs to manually assert CS line for current
   538 				AsspRegister::Modify32(iHwBase + MCSPI_CHxCONF(iCurrSS), 0, MCSPI_CHxCONF_FORCE);
   549 				AsspRegister::Modify32(iHwBase + MCSPI_CHxCONF(iCurrSS), 0, MCSPI_CHxCONF_FORCE);
   539 
   550 
   540 				// change the pad config - now the SPI drives the line appropriately..
   551 				// change the pad config - now the SPI drives the line appropriately..
   541 				SetCsActive(iChannelNumber, iCurrSS);
   552 				SetCsActive(iChannelNumber, iCurrSS, iCurrSlavePinSet);
   542 #endif /*SINGLE_MODE*/
   553 #endif /*SINGLE_MODE*/
   543 				}
   554 				}
   544 			else
   555 			else
   545 				{
   556 				{
   546 				// enable only interrupts for RX here. Tx is handled in EMasterWrite case above.
   557 				// enable only interrupts for RX here. Tx is handled in EMasterWrite case above.
   759 			}
   770 			}
   760 		__ASSERT_DEBUG(a->iRxDataEnd == a->iRxData,
   771 		__ASSERT_DEBUG(a->iRxDataEnd == a->iRxData,
   761 		               Kern::Fault("SPI master: exiting not having received all?", 12));
   772 		               Kern::Fault("SPI master: exiting not having received all?", 12));
   762 		}
   773 		}
   763 
   774 
   764 	// make sure the CS pin is asserted..
       
   765 	if(a->iCurrHeader.iSSPinActiveMode == ESpiCSPinActiveLow)
       
   766 		{
       
   767 		AsspRegister::Modify32(a->iHwBase + MCSPI_SYST, 0, 1 << a->iCurrSS);
       
   768 		}
       
   769 	else
       
   770 		{
       
   771 		AsspRegister::Modify32(a->iHwBase + MCSPI_SYST, 1 << a->iCurrSS, 0);
       
   772 		}
       
   773 
       
   774 #ifdef SINGLE_MODE
   775 #ifdef SINGLE_MODE
   775 	// manually de-assert CS line for this channel
   776 	// manually de-assert CS line for this channel
   776 	AsspRegister::Modify32(a->iHwBase + MCSPI_CHxCONF(a->iCurrSS), MCSPI_CHxCONF_FORCE, 0);
   777 	AsspRegister::Modify32(a->iHwBase + MCSPI_CHxCONF(a->iCurrSS), MCSPI_CHxCONF_FORCE, 0);
   777 
   778 
   778 	// drive csx pin high or low. Doing this here causes, that CS lines are toggled for each transfers.
       
   779 	TUint val = (a->iCurrHeader.iSSPinActiveMode == ESpiCSPinActiveLow)? 1 << a->iCurrSS : 0;
       
   780 	if (val)
       
   781 		{
       
   782 		AsspRegister::Modify32(a->iHwBase + MCSPI_SYST, 0, val);
       
   783 		}
       
   784 	// put the CS signal to 'inactive' state (as on channel disable it would have a glitch)
   779 	// put the CS signal to 'inactive' state (as on channel disable it would have a glitch)
   785 	SetCsInactive(a->iChannelNumber, a->iCurrSS, a->iCurrHeader.iSSPinActiveMode);
   780 	SetCsInactive(a->iChannelNumber, a->iCurrSS, a->iCurrHeader.iSSPinActiveMode, a->iCurrSlavePinSet);
   786 
   781 
   787 #endif
   782 #endif
   788 
   783 
   789 	// disable the channel
   784 	// disable the channel
   790 	AsspRegister::Modify32(a->iHwBase + MCSPI_CHxCTRL(0), MCSPI_CHxCTRL_EN, 0);
   785 	AsspRegister::Modify32(a->iHwBase + MCSPI_CHxCTRL(0), MCSPI_CHxCTRL_EN, 0);
   805 void DSpiMasterBeagle::ExitComplete(TInt aErr, TBool aComplete /*= ETrue*/)
   800 void DSpiMasterBeagle::ExitComplete(TInt aErr, TBool aComplete /*= ETrue*/)
   806 	{
   801 	{
   807 	DBGPRINT(Kern::Printf("DSpiMasterBeagle::ExitComplete, aErr %d, aComplete %d", aErr, aComplete));
   802 	DBGPRINT(Kern::Printf("DSpiMasterBeagle::ExitComplete, aErr %d, aComplete %d", aErr, aComplete));
   808 
   803 
   809 	// make sure CS is in inactive state (for the current / last transaction) on error
   804 	// make sure CS is in inactive state (for the current / last transaction) on error
   810 	if(!aComplete)
   805 	// TODO: add extendable transaction support (..i.e. with no de-assertion of CS pin between such transactions)
   811 		{
   806 	SetCsInactive(iChannelNumber, iCurrSS, iCurrHeader.iSSPinActiveMode, iCurrSlavePinSet);
   812 		SetCsInactive(iChannelNumber, iCurrSS, iCurrHeader.iSSPinActiveMode);
   807 
   813 		}
   808 	// disable this channel
   814 
       
   815 	// disable this channel (and reset..)
       
   816 	AsspRegister::Modify32(iHwBase + MCSPI_CHxCTRL(iCurrSS), MCSPI_CHxCTRL_EN, 0);
   809 	AsspRegister::Modify32(iHwBase + MCSPI_CHxCTRL(iCurrSS), MCSPI_CHxCTRL_EN, 0);
   817 	AsspRegister::Write32(iHwBase + MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_SOFTRESET);
   810 
       
   811 	// in the case of error - make sure to reset the channel
       
   812 	if(aErr != KErrNone)
       
   813 		{
       
   814 		AsspRegister::Write32(iHwBase + MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_SOFTRESET);
       
   815 		iCurrSS = -1; // make sure the interface will be re-configured at next transaction
       
   816 		}
   818 
   817 
   819 	// Disable interrupts for the channel
   818 	// Disable interrupts for the channel
   820 	Interrupt::Disable(iIrqId);
   819 	Interrupt::Disable(iIrqId);
   821 
   820 
   822 	// Cancel any timers and DFCs..
   821 	// Cancel any timers and DFCs..