diff -r bcf33365fd8d -r 09e266454dcf omap3530/omap3530_drivers/spi/master.cpp --- 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);