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 { |
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 |
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.. |