]> rtime.felk.cvut.cz Git - arc.git/blob - arch/ppc/mpc55xx/drivers/Spi.c
30e881355be7ea95ff5e443f487609ece4983452
[arc.git] / arch / ppc / mpc55xx / drivers / Spi.c
1 /* -------------------------------- Arctic Core ------------------------------\r
2  * Arctic Core - the open source AUTOSAR platform http://arccore.com\r
3  *\r
4  * Copyright (C) 2009  ArcCore AB <contact@arccore.com>\r
5  *\r
6  * This source code is free software; you can redistribute it and/or modify it\r
7  * under the terms of the GNU General Public License version 2 as published by the\r
8  * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.\r
9  *\r
10  * This program is distributed in the hope that it will be useful, but\r
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
13  * for more details.\r
14  * -------------------------------- Arctic Core ------------------------------*/\r
15 \r
16 /** @reqSettings DEFAULT_SPECIFICATION_REVISION=3.1.5 */\r
17 \r
18 /* ----------------------------[information]----------------------------------*/\r
19 /*\r
20  * Author: mahi\r
21  *\r
22  * Part of Release:\r
23  *   3.1.5\r
24  *\r
25  * Description:\r
26  *   Implements the SPI driver module\r
27  *\r
28  * Support:\r
29  *   General                     Have Support\r
30  *   -------------------------------------------\r
31  *   SPI_CANCEL_API                 N\r
32  *   SPI_CHANNEL_BUFFERS_ALLOWED    Y/N, Supports only level 1 (0:IB,1:EB,2:IB+EB)\r
33  *   SPI_DEV_ERROR_DETECT           Y\r
34  *   SPI_HW_STATUS_API              N\r
35  *   SPI_INTERRUPTIBLE_SEQ_ALLOWED  N\r
36  *   SPI_LEVEL_DELIVERED            Y/N, supports only level 2 (0:sync,1:sync,2:both)\r
37  *   SPI_VERSION_INFO_API           Y\r
38  *\r
39  *   Extra:\r
40  *   - DMA and FIFO is implementations\r
41  *   - Soft CS by callback\r
42  *\r
43  *   Devices\r
44  *   - MPC5606S\r
45  *   - MPC5604B\r
46  *\r
47  * Implementation Notes:\r
48  * - This driver implements SPI_LEVEL_DELIVERED = 2 but with a number\r
49  *   of restrictions. See REQ. below for more information.\r
50  *\r
51  * - A sequence may use different CS's if the controller is the same.\r
52  *   ( All jobs that belongs to a sequence MUST share the same controller )\r
53  *\r
54  * - The driver uses Spi_DataType as uint8. This means that an 16-bit address have\r
55  *   a length of 2 when setting upASetting async/sync mode is not supported\r
56  *   ( Spi_SetAsyncMode(), SPI188, etc )\r
57  * - Cancel API is NOT supported\r
58  *    ( SPI_CANCEL_API must be STD_OFF )\r
59  *\r
60  * - It's not obvious how to use different modes. My interpretation:\r
61  *\r
62  *   Sync\r
63  *     Always blocking in Spi_SyncTransmit()\r
64  *\r
65  *\r
66  * Info:\r
67  *   - The AsyncModeType (SPI_POLLING_MODE,SPI_INTERRUPT_MODE) is used to handle only the\r
68  *     async API, ie Spi_AsyncTransmit().  The synchrone API just calls Spi_SyncTransmit()->Spi_Isr()....\r
69  *\r
70  *\r
71  *   Async and INTERRUPT\r
72  *\r
73  *   Async and POLLING\r
74  *     Not supported since ??\r
75  *\r
76  * - Some sequence charts\r
77  *\r
78  *\r
79  * == Sync ==\r
80  *       WriteSeq   ISR   WriteJob   MainFunction_Driving\r
81  *       -------------------------------------------------\r
82  *       |          |        |                |\r
83  *       ------>\r
84  *       ---------------->\r
85  *       <---------------\r
86  * ( for each job we will now get an interrupt that write's the next job)\r
87  *                  ----->\r
88  *                  <-----\r
89  *                  ...\r
90  *       <-----\r
91  *\r
92  * == Async and INTERRUPT ==\r
93  *\r
94  *       ------>\r
95  *       ---------------->\r
96  *       <---------------\r
97  *       <-----\r
98  * ( for each job we will now get an interrupt that write's the next job)\r
99  *                  ----->\r
100  *                  <-----\r
101  *       ....\r
102  *\r
103  *\r
104  * == Async and POLLING ==\r
105  * ( Not supported yet )\r
106  *\r
107  *       ------>\r
108  *       ---------------->\r
109  *       <---------------\r
110  *       <-----\r
111  * ( for each job in the sequence the sequence must be repeated )\r
112  *       ---------------------------------->\r
113  *                       <-----------------\r
114  *                 ------>\r
115  *                 <-----\r
116  *                       ------------------>\r
117  *       <----------------------------------\r
118  *       ...\r
119  *\r
120  *\r
121  */\r
122 \r
123 /* HW INFO\r
124  * -----------------------------------------------\r
125  * 4 DSPI modules, A,B,C and D\r
126  * 7 CTAR's for each module.( data-width, baudrate )\r
127  *\r
128  */\r
129 \r
130 /* NOTIFICATION INFORMATION\r
131  * -----------------------------------------------\r
132  *\r
133  * There's a LOT of status and notification in this module....\r
134  *\r
135  *                           Job1              Job2\r
136  *                     |---------------|---------------|\r
137  *                                    JN              JN,SN\r
138  * Status    IDLE             BUSY           BUSY           IDLE\r
139  * HwStatus  IDLE             BUSY           BUSY           IDLE\r
140  * JobResult JOB_OK      JOB_PENDING       JOB_PENDING      JOB_OK,SPI_JOB_FAILED\r
141  * SeqResult SEQ_OK      SEQ_PENDING       SEQ_PENDING      SEQ_OK,SEQ_FAILED,SEQ_CANCELLED\r
142  *\r
143  * JN - JOb Notification\r
144  * SN - Sequence NOtificaiton\r
145  */\r
146 \r
147 /* ----------------------------[includes]------------------------------------*/\r
148 \r
149 #include <stdlib.h>\r
150 #include <assert.h>\r
151 #include <limits.h>\r
152 #include <string.h>\r
153 #include "Spi.h"\r
154 #include "mpc55xx.h"\r
155 //#include <stdio.h>\r
156 #include "Mcu.h"\r
157 #include "math.h"\r
158 #if (SPI_IMPLEMENTATION==SPI_DMA)\r
159 #include "Dma.h"\r
160 #endif\r
161 #include "Det.h"\r
162 #include "isr.h"\r
163 /* ----------------------------[private define]------------------------------*/\r
164 \r
165 #define SPIE_BAD                  (-1)\r
166 #define SPIE_OK                         0\r
167 #define SPIE_JOB_NOT_DONE   1\r
168 \r
169 #if defined(CFG_MPC5604B)\r
170 #define CTAR_CNT    6\r
171 #else\r
172 #define CTAR_CNT    8\r
173 #endif\r
174 \r
175 //#define SPI_IMPLEMENTATION    SPI_FIFO\r
176 #define USE_DIO_CS          STD_ON\r
177 \r
178 // E2 read = cmd + addr + data = 1 + 2 + 64 ) = 67 ~ 72\r
179 #define SPI_INTERNAL_MTU    72\r
180 \r
181 /* The depth of the HW FIFO */\r
182 #define FIFO_DEPTH                      4\r
183 \r
184 /* Define for debug purposes, checks that SPI/DMA is ok */\r
185 //#define STEP_VALIDATION               1\r
186 \r
187 #define MODULE_NAME     "/driver/Spi"\r
188 \r
189 //#define USE_LDEBUG_PRINTF     1\r
190 #undef DEBUG_LVL\r
191 #define DEBUG_LVL DEBUG_NONE\r
192 #include "debug.h"\r
193 \r
194 //#define USE_LOCAL_RAMLOG\r
195 #if defined(USE_LOCAL_RAMLOG)\r
196 #define RAMLOG_STR(_x) ramlog_str(_x)\r
197 #define RAMLOG_DEC(_x) ramlog_dec(_x)\r
198 #define RAMLOG_HEX(_x) ramlog_hex(_x)\r
199 #else\r
200 #define RAMLOG_STR(_x)\r
201 #define RAMLOG_DEC(_x)\r
202 #define RAMLOG_HEX(_x)\r
203 #endif\r
204 \r
205 #define SPI_ASSERT(_exp)        if( !(_exp) ) while(1) {}\r
206 \r
207 /* ----------------------------[private macro]-------------------------------*/\r
208 \r
209 #ifndef MIN\r
210 #define MIN(_x,_y) (((_x) < (_y)) ? (_x) : (_y))\r
211 #endif\r
212 #ifndef MAX\r
213 #define MAX(_x,_y) (((_x) > (_y)) ? (_x) : (_y))\r
214 #endif\r
215 \r
216 #define GET_SPI_HW_PTR(_unit)   \\r
217         ((volatile struct DSPI_tag *)(0xFFF90000 + 0x4000*(_unit)))\r
218 \r
219 #define GET_SPI_UNIT_PTR(_unit) &Spi_Unit[Spi_CtrlToUnit[_unit]]\r
220 \r
221 #define ENABLE_EOQ_INTERRUPT(_spi_hw) _spi_hw->RSER.B.EOQF_RE = 1\r
222 #define DISABLE_EOQ_INTERRUPT(_spi_hw) _spi_hw->RSER.B.EOQF_RE = 0\r
223 \r
224 #define GET_HW(_channel)    ( volatile struct DSPI_tag *)((uint32)&DSPI_A + 0x4000 * _channel )\r
225 \r
226 /* Development error macros. */\r
227 #if ( SPI_DEV_ERROR_DETECT == STD_ON )\r
228 #define VALIDATE(_exp,_api,_err ) \\r
229         if( !(_exp) ) { \\r
230           Det_ReportError(MODULE_ID_SPI,0,_api,_err); \\r
231           return; \\r
232         }\r
233 \r
234 #define VALIDATE_W_RV(_exp,_api,_err,_rv ) \\r
235         if( !(_exp) ) { \\r
236           Det_ReportError(MODULE_ID_SPI,0,_api,_err); \\r
237           return (_rv); \\r
238         }\r
239 #else\r
240 #define VALIDATE(_exp,_api,_err )\r
241 #define VALIDATE_W_RV(_exp,_api,_err,_rv )\r
242 #endif\r
243 \r
244 /* ----------------------------[private typedef]-----------------------------*/\r
245 \r
246 #if (SPI_IMPLEMENTATION == SPI_DMA )\r
247 typedef struct Spi_DmaConfig {\r
248          Dma_ChannelType RxDmaChannel;\r
249          Dma_ChannelType TxDmaChannel;\r
250 } Spi_DmaConfigType;\r
251 \r
252 #endif\r
253 \r
254 \r
255 \r
256 typedef union {\r
257         vuint32_t R;\r
258         struct {\r
259                 vuint32_t CONT :1;\r
260                 vuint32_t CTAS :3;\r
261                 vuint32_t EOQ :1;\r
262                 vuint32_t CTCNT :1;\r
263                 vuint32_t :4;\r
264                 vuint32_t PCS5 :1;\r
265                 vuint32_t PCS4 :1;\r
266                 vuint32_t PCS3 :1;\r
267                 vuint32_t PCS2 :1;\r
268                 vuint32_t PCS1 :1;\r
269                 vuint32_t PCS0 :1;\r
270                 vuint32_t TXDATA :16;\r
271         } B;\r
272 } SPICommandType;\r
273 \r
274 typedef SPICommandType Spi_CommandType;\r
275 typedef struct {\r
276         const Spi_DataType *    src;    /* Pointer to source buffer */\r
277         Spi_DataType *          dest;   /* Pointer to destination buffer */\r
278         Spi_NumberOfDataType    length; // Number of elements of Spi_DataType in destination buffer\r
279         _Bool                   active; // Set if the buffer is configured.\r
280 } Spi_EbType;\r
281 \r
282 typedef enum {\r
283         SPI_ASYNC_CALL,\r
284         SPI_SYNC_CALL,\r
285 } Spi_CallTypeType;\r
286 \r
287 typedef struct {\r
288         uint8 ctarId;    // this channel is assigned to this CTAR\r
289 } Spi_ChannelInfoType;\r
290 \r
291 /**\r
292  * This structure represents a controller unit\r
293  */\r
294 typedef struct {\r
295 \r
296 #if (SPI_IMPLEMENTATION==SPI_DMA)\r
297         Dma_ChannelType dmaTxChannel;       // Tx DMA channel information\r
298         Dma_TcdType     dmaTxTCD;\r
299         Dma_ChannelType dmaRxChannel;      // Rx DMA channel information\r
300         Dma_TcdType     dmaRxTCD;\r
301     Spi_CommandType txQueue[SPI_INTERNAL_MTU];      // Pointed to by SADDR of DMA\r
302     uint32          rxQueue[SPI_INTERNAL_MTU];      // Pointed to by DADDR of DMA\r
303 #endif\r
304         uint32          txCurrIndex;                    // current index for data when sending\r
305         uint32          channelCodes[(CTAR_CNT-1)];                // Helper array to assign CTAR's\r
306         Spi_StatusType status;                          // Status for this unit\r
307         const Spi_JobConfigType *       currJob;         // The current job\r
308         const Spi_JobType *             currJobIndexPtr; // Points array of jobs current\r
309     Spi_JobType                     currJobIndex;\r
310         const Spi_SequenceConfigType *  currSeqPtr;     // The Sequence\r
311         Spi_CallTypeType callType;                      // 1 -  if the current job is sync. 0 - if not\r
312         volatile struct DSPI_tag *      hwPtr;\r
313         uint8                                                   hwUnit;         // 0...\r
314 } Spi_UnitType;\r
315 \r
316 typedef struct {\r
317         Spi_SeqResultType seqResult;\r
318 } Spi_SeqUnitType;\r
319 \r
320 typedef struct {\r
321         volatile struct DSPI_tag *      hwPtr;            /* The HW device used by this Job */\r
322         const Spi_ExternalDeviceType *  extDeviceCfgPtr;  /* The external device used by this job */\r
323         const Spi_JobConfigType *       jobCfgPtr;\r
324         Spi_UnitType *                  unitPtr;\r
325         const Spi_ChannelType *         channelsPtr;\r
326 #if (SPI_IMPLEMENTATION == SPI_FIFO )\r
327         uint32_t    fifoSent;          /* Number of bytes in FIFO (before EOQ is set) */\r
328         uint8_t     currTxChIndex;     /* the currently transmitting channel index for FIFO */\r
329         uint32_t    txChCnt;           /* number of Spi_DataType sent for the current channel */\r
330         uint32_t    rxChCnt;           /* number of Spi_DataType received for the current channel */\r
331         uint32_t    currRxChIndex;     /* the currently receiving channel index for FIFO */\r
332 #endif\r
333         Spi_JobResultType jobResult;\r
334 } Spi_JobUnitType;\r
335 \r
336 typedef struct {\r
337         boolean initRun;                            // Initially FALSE set to TRUE if Spi_Init() have been called\r
338         const Spi_ConfigType *  configPtr;          // Pointer to the configuration\r
339         Spi_EbType *            extBufPtr;          // Pointer to the external buffers\r
340         Spi_ChannelInfoType *   channelInfo;\r
341         uint32                  spiHwConfigured;    // Mask if the HW unit is configured or not\r
342         Spi_AsyncModeType       asyncMode;\r
343 \r
344         /* This is a bunch of debug counters. */\r
345         uint32 totalNbrOfTranfers;\r
346         uint32 totalNbrOfStartedJobs;\r
347         /* Counters for busy waiting for DSPI and DMA. */\r
348         uint32 totalNbrOfWaitTXRXS;\r
349         uint32 totalNbrOfWaitRxDMA;\r
350 #if  defined(STEP_VALIDATION)\r
351         int eoqf_cnt;\r
352         int txrxs_cnt;\r
353 #endif\r
354 } Spi_GlobalType;\r
355 \r
356 /* ----------------------------[private function prototypes]-----------------*/\r
357 /* ----------------------------[private variables]---------------------------*/\r
358 \r
359 #if (SPI_IMPLEMENTATION==SPI_DMA)\r
360 /* Templates for Rx/Tx DMA structures */\r
361 const Dma_TcdType Spi_DmaTx = {\r
362                 .SADDR = 0, .SMOD = 0, .SSIZE = DMA_TRANSFER_SIZE_32BITS, .DMOD = 0,\r
363                 .DSIZE = DMA_TRANSFER_SIZE_32BITS, .SOFF = 4, .NBYTESu.R = 4, .SLAST = 0,\r
364                 .DADDR = 0, .CITERE_LINK = 0, .CITER = 0, .DOFF = 0, .DLAST_SGA = 0,\r
365                 .BITERE_LINK = 0, .BITER = 0, .BWC = 0, .MAJORLINKCH = 0, .DONE = 0,\r
366                 .ACTIVE = 0, .MAJORE_LINK = 0, .E_SG = 0, .D_REQ = 0, .INT_HALF = 0,\r
367                 .INT_MAJ = 0, .START = 0 };\r
368 \r
369 const Dma_TcdType Spi_DmaRx = { .SADDR = 0, .SMOD = 0,\r
370                 .SSIZE = DMA_TRANSFER_SIZE_32BITS, .DMOD = 0,\r
371                 .DSIZE = DMA_TRANSFER_SIZE_32BITS, .SOFF = 0, .NBYTESu.R = 4, .SLAST = 0,\r
372                 .DADDR = 0, .CITERE_LINK = 0, .CITER = 1, .DOFF = 4, .DLAST_SGA = 0,\r
373                 .BITERE_LINK = 0, .BITER = 1, .BWC = 0, .MAJORLINKCH = 0, .DONE = 0,\r
374                 .ACTIVE = 0, .MAJORE_LINK = 0, .E_SG = 0, .D_REQ = 0, .INT_HALF = 0,\r
375 #if defined(__DMA_INT)\r
376                 .INT_MAJ = 1,\r
377 #else\r
378                 .INT_MAJ = 0,\r
379 #endif\r
380                 .START = 0 };\r
381 #endif\r
382 \r
383 Spi_GlobalType  Spi_Global;\r
384 Spi_EbType      Spi_Eb[SPI_MAX_CHANNEL];\r
385 Spi_UnitType    Spi_Unit[SPI_CONTROLLER_CNT];\r
386 Spi_SeqUnitType Spi_SeqUnit[SPI_MAX_SEQUENCE];\r
387 Spi_JobUnitType Spi_JobUnit[SPI_MAX_JOB];\r
388 Spi_ChannelInfoType Spi_ChannelInfo[SPI_MAX_CHANNEL];\r
389 uint8 Spi_CtrlToUnit[4];\r
390 \r
391 \r
392 #if (SPI_IMPLEMENTATION == SPI_DMA)\r
393 /* When using DMA it assumes predefined names */\r
394 Spi_DmaConfigType  Spi_DmaConfig[SPI_CONTROLLER_CNT] = {\r
395 #if (SPI_USE_HW_UNIT_0 == STD_ON )\r
396         {\r
397             .RxDmaChannel = DMA_DSPI_A_RESULT_CHANNEL,\r
398             .TxDmaChannel = DMA_DSPI_A_COMMAND_CHANNEL,\r
399         },\r
400 #endif\r
401 #if (SPI_USE_HW_UNIT_1 == STD_ON )\r
402         {\r
403             .RxDmaChannel = DMA_DSPI_B_RESULT_CHANNEL,\r
404             .TxDmaChannel = DMA_DSPI_B_COMMAND_CHANNEL,\r
405         },\r
406 #endif\r
407 #if (SPI_USE_HW_UNIT_2 == STD_ON )\r
408         {\r
409             .RxDmaChannel = DMA_DSPI_C_RESULT_CHANNEL,\r
410             .TxDmaChannel = DMA_DSPI_C_COMMAND_CHANNEL,\r
411         },\r
412 #endif\r
413 #if (SPI_USE_HW_UNIT_3 == STD_ON )\r
414         {\r
415             .RxDmaChannel = DMA_DSPI_D_RESULT_CHANNEL,\r
416             .TxDmaChannel = DMA_DSPI_D_COMMAND_CHANNEL,\r
417         }\r
418 #endif\r
419 };\r
420 #endif\r
421 \r
422 /* ----------------------------[private functions]---------------------------*/\r
423 \r
424 #if (SPI_IMPLEMENTATION == SPI_FIFO )\r
425 static void Spi_WriteJob_FIFO( Spi_JobType jobIndex );\r
426 \r
427 /**\r
428  * Get the buffer for a channel.\r
429  *\r
430  * @param ch\r
431  * @param length\r
432  * @return\r
433  */\r
434 static Spi_DataType *spiGetRxBuf(Spi_ChannelType ch, Spi_NumberOfDataType *length ) {\r
435         Spi_DataType *buf;\r
436         if( Spi_Global.configPtr->SpiChannelConfig[ch].SpiChannelType == SPI_EB ) {\r
437                 *length = Spi_Global.extBufPtr[ch].length;\r
438                 buf = Spi_Global.extBufPtr[ch].dest;\r
439         } else {\r
440                 /* No support */\r
441                 assert(0);\r
442                 buf = NULL;\r
443         }\r
444         return buf;\r
445 }\r
446 \r
447 static const Spi_DataType *spiGetTxBuf(Spi_ChannelType ch, Spi_NumberOfDataType *length ) {\r
448         const Spi_DataType *buf;\r
449         if( Spi_Global.configPtr->SpiChannelConfig[ch].SpiChannelType == SPI_EB ) {\r
450                 *length = Spi_Global.extBufPtr[ch].length;\r
451                 buf = Spi_Global.extBufPtr[ch].src;\r
452         } else {\r
453                 /* No support */\r
454                 assert(0);\r
455                 buf = NULL;\r
456         }\r
457         return buf;\r
458 }\r
459 #endif\r
460 \r
461 static void Spi_Isr(Spi_UnitType *uPtr );\r
462 \r
463 static void Spi_Isr_A(void) {\r
464         Spi_Isr(GET_SPI_UNIT_PTR(DSPI_CTRL_A));\r
465 }\r
466 static void Spi_Isr_B(void) {\r
467         Spi_Isr(GET_SPI_UNIT_PTR(DSPI_CTRL_B));\r
468 }\r
469 static void Spi_Isr_C(void) {\r
470         Spi_Isr(GET_SPI_UNIT_PTR(DSPI_CTRL_C));\r
471 }\r
472 static void Spi_Isr_D(void) {\r
473         Spi_Isr(GET_SPI_UNIT_PTR(DSPI_CTRL_D));\r
474 }\r
475 /* ----------------------------[public functions]----------------------------*/\r
476 \r
477 uint32 Spi_GetJobCnt(void);\r
478 uint32 Spi_GetChannelCnt(void);\r
479 uint32 Spi_GetExternalDeviceCnt(void);\r
480 \r
481 #if 0\r
482 static void Spi_Isr_DMA( void )\r
483 {\r
484         // Clear interrupt\r
485         Dma_ClearInterrupt(5);\r
486 }\r
487 #endif\r
488 \r
489 static void Spi_JobWrite(Spi_JobType jobIndex);\r
490 \r
491 static void Spi_SetJobResult(Spi_JobType Job, Spi_JobResultType result) {\r
492         Spi_JobUnit[Job].jobResult = result;\r
493 }\r
494 \r
495 #if 1\r
496 static void Spi_SetHWUnitStatus( Spi_UnitType *uPtr, Spi_StatusType status) {\r
497         uPtr->status = status;\r
498 }\r
499 #else\r
500 static void Spi_SetHWUnitStatus(Spi_HWUnitType HWUnit, Spi_StatusType status) {\r
501         Spi_Unit[Spi_CtrlToUnit[HWUnit]].status = status;\r
502 }\r
503 #endif\r
504 \r
505 /**\r
506  * Get external Ptr to device from index\r
507  *\r
508  * @param deviceType The device index.\r
509  * @return Ptr to the external device\r
510  */\r
511 \r
512 static inline const Spi_ExternalDeviceType *Spi_GetExternalDevicePtrFromIndex(\r
513                 Spi_ExternalDeviceTypeType deviceType) {\r
514         return (&(Spi_Global.configPtr->SpiExternalDevice[(deviceType)]));\r
515 }\r
516 \r
517 /**\r
518  * Get configuration job ptr from job index\r
519  * @param jobIndex the job\r
520  * @return Ptr to the job configuration\r
521  */\r
522 static const Spi_JobConfigType *Spi_GetJobPtrFromIndex(Spi_JobType jobIndex) {\r
523         return &Spi_Global.configPtr->SpiJobConfig[jobIndex];\r
524 }\r
525 \r
526 /**\r
527  * Get sequence ptr from sequence index\r
528  * @param seqIndex the sequence\r
529  * @return Ptr to the sequence configuration\r
530  */\r
531 static const Spi_SequenceConfigType *Spi_GetSeqPtrFromIndex(\r
532                 Spi_SequenceType SeqIndex) {\r
533         return &Spi_Global.configPtr->SpiSequenceConfig[SeqIndex];\r
534 }\r
535 \r
536 /**\r
537  * Get unit ptr from unit index\r
538  * @param unit the unit\r
539  * @return Ptr to the SPI unit\r
540  */\r
541 static Spi_UnitType *Spi_GetUnitPtrFromIndex(uint32 unit) {\r
542         return &Spi_Unit[Spi_CtrlToUnit[unit]];\r
543 }\r
544 \r
545 /**\r
546  * Function to see if two sequences share jobs\r
547  *\r
548  * @param seq - Seqence 1\r
549  * @param seq - Seqence 2\r
550  * @return 0 - if the don't share any jobs\r
551  *        !=0 - if they share jobs\r
552  */\r
553 \r
554 static boolean Spi_ShareJobs(Spi_SequenceType seq1, Spi_SequenceType seq2) {\r
555         uint32 seqMask1 = 0;\r
556         uint32 seqMask2 = 0;\r
557         const Spi_JobType *jobPtr;\r
558         const Spi_SequenceConfigType *seqConfig;\r
559 \r
560         // Search for jobs in sequence 1\r
561         seqConfig = Spi_GetSeqPtrFromIndex(seq1);\r
562         jobPtr = &seqConfig->JobAssignment[0];\r
563 \r
564         while (*jobPtr != JOB_NOT_VALID) {\r
565                 assert(*jobPtr<31);\r
566                 seqMask1 |= (1 << *jobPtr);\r
567                 jobPtr++;\r
568         }\r
569 \r
570         // Search for jobs in sequence 2\r
571         seqConfig = Spi_GetSeqPtrFromIndex(seq2);\r
572         jobPtr = &seqConfig->JobAssignment[0];\r
573 \r
574         while (*jobPtr != JOB_NOT_VALID) {\r
575                 assert(*jobPtr<31);\r
576                 seqMask2 |= (1 << *jobPtr);\r
577                 jobPtr++;\r
578         }\r
579 \r
580         return (seqMask1 & seqMask2);\r
581 }\r
582 \r
583 \r
584 //-------------------------------------------------------------------\r
585 \r
586 /**\r
587  * Sets a result for a sequence\r
588  *\r
589  * @param Sequence The sequence to set the result for\r
590  * @param result The result to set.\r
591  */\r
592 static void Spi_SetSequenceResult(Spi_SequenceType Sequence,\r
593                 Spi_SeqResultType result) {\r
594         Spi_SeqUnit[Sequence].seqResult = result;\r
595 }\r
596 \r
597 //-------------------------------------------------------------------\r
598 \r
599 \r
600 /**\r
601  * Gets the next job to do\r
602  *\r
603  * @param spiUnit The SPI unit\r
604  * @return The job ID. -1 if no more jobs\r
605  */\r
606 static Spi_JobType Spi_GetNextJob(Spi_UnitType *spiUnit) {\r
607         spiUnit->currJobIndexPtr++;\r
608         return *(spiUnit->currJobIndexPtr);\r
609 }\r
610 //-------------------------------------------------------------------\r
611 \r
612 \r
613 #if (SPI_IMPLEMENTATION==SPI_DMA)\r
614 \r
615 /**\r
616  * Function to handle things after a transmit on the SPI is finished.\r
617  * It copies data from it't local buffers to the buffers pointer to\r
618  * by the external buffers\r
619  *\r
620  * @param spiUnit Ptr to a SPI unit\r
621  */\r
622 \r
623 static int Spi_Rx_DMA(Spi_UnitType *spiUnit) {\r
624         _Bool printedSomeThing = 0;\r
625 \r
626         /* Stop the channels */\r
627         Dma_StopChannel(spiUnit->dmaTxChannel);\r
628         Dma_StopChannel(spiUnit->dmaRxChannel);\r
629 \r
630         RAMLOG_STR("PostTransmit Job: "); RAMLOG_DEC(spiUnit->currJob->SpiJobId); RAMLOG_STR("\n");\r
631 \r
632         /* Copy data from RX queue to the external buffer( if a<uny ) */\r
633         {\r
634                 int j = 0;\r
635                 int currIndex = 0;\r
636                 int channelIndex;\r
637                 const Spi_ChannelConfigType *chConfig;\r
638                 Spi_EbType *extChBuff;\r
639                 int gotTx;\r
640                 int sentTx;\r
641 \r
642                 // Check that we got the number of bytes we sent\r
643                 sentTx = spiUnit->txCurrIndex + 1;\r
644                 gotTx = (Dma_GetTcd(spiUnit->dmaRxChannel)->DADDR\r
645                                 - (uint32) &spiUnit->rxQueue[0]) / sizeof(uint32);\r
646 \r
647                 if (sentTx != gotTx) {\r
648                         // Something failed\r
649                         DEBUG(DEBUG_LOW,"%s: Expected %d bytes. Got %d bytes\n ",MODULE_NAME,sentTx, gotTx );\r
650 #if defined(STEP_VALIDATION)\r
651             SPI_ASSERT(0);\r
652 #endif\r
653                         return SPIE_BAD;\r
654                 } else {\r
655                         RAMLOG_STR("Rx "); RAMLOG_DEC(gotTx); RAMLOG_STR(" Bytes\n"); DEBUG(DEBUG_LOW,"%s: Got %d bytes\n",MODULE_NAME,gotTx);\r
656                 }\r
657 \r
658                 // Find the channels for this job\r
659                 while ((channelIndex = spiUnit->currJob->ChannelAssignment[j++])\r
660                                 != CH_NOT_VALID) {\r
661                         chConfig = &Spi_Global.configPtr->SpiChannelConfig[channelIndex];\r
662 \r
663                         /* Check configuration error */\r
664 #if ( SPI_CHANNEL_BUFFERS_ALLOWED == 1  )\r
665                         assert( chConfig->SpiChannelType == SPI_EB );\r
666 #endif\r
667 \r
668                         // Send the channels that are setup with external buffers\r
669                         // Get the external buffer for this channel\r
670                         extChBuff = &Spi_Global.extBufPtr[channelIndex];\r
671                         if (extChBuff->dest != NULL) {\r
672                                 // Note! No support for >8 "data"\r
673                                 for (int k = 0; k < extChBuff->length; k++) {\r
674                                         extChBuff->dest[k] = spiUnit->rxQueue[currIndex++];\r
675                                         DEBUG(DEBUG_LOW," %02x ",extChBuff->dest[k]);\r
676                                         printedSomeThing = 1;\r
677                                 }\r
678 \r
679                         } else {\r
680                                 if (chConfig->SpiDataWidth > 8) {\r
681                                         currIndex += (extChBuff->length / 2);\r
682                                 } else {\r
683                                         currIndex += extChBuff->length;\r
684                                 }\r
685                         }\r
686                 }\r
687                 if (printedSomeThing)\r
688                         DEBUG(DEBUG_LOW,"\n");\r
689         }\r
690 \r
691         return 0;\r
692 }\r
693 \r
694 #elif (SPI_IMPLEMENTATION==SPI_FIFO)\r
695 \r
696 static int Spi_Rx_FIFO(Spi_UnitType *spiUnit) {\r
697         Spi_JobUnitType *    jobUnitPtr;\r
698         Spi_DataType *       buf;\r
699     uint32_t             copyCnt;\r
700         uint32_t             popVal;\r
701         Spi_ChannelType      currChannel;\r
702         Spi_NumberOfDataType bufLen;\r
703     int i = 0;\r
704     int rv = SPIE_JOB_NOT_DONE;\r
705     const Spi_ChannelConfigType *   chConfig;\r
706     uint32_t bInChar;\r
707 \r
708 \r
709 //      RAMLOG_STR("PostTransmit Job: "); RAMLOG_DEC(spiUnit->currJob->SpiJobId); RAMLOG_STR("\n");\r
710     RAMLOG_STR("Spi_Rx_FIFO\n");\r
711 \r
712         jobUnitPtr = &Spi_JobUnit[spiUnit->currJobIndex];\r
713 \r
714         if( jobUnitPtr->hwPtr->TCR.B.SPI_TCNT != jobUnitPtr->fifoSent ) {\r
715 #if defined(STEP_VALIDATION)\r
716             SPI_ASSERT(0);\r
717 #endif\r
718                 return SPIE_BAD;\r
719         }\r
720 \r
721         /*\r
722          * Fill receive buffers, either EB or IB\r
723          * Example with 8-bit CMD, 16-bit ADDR and some 8-bit data.\r
724          *    CMD |  ADDR   |     DATA\r
725          *   | 12 | 23 | 34 | 00 | 01 | 02 | 03\r
726          *      1    2    3    4    5    6           BYTE CNT\r
727          *      1      2       3    4   (5)  (6)     FIFO\r
728          * With a FIFO of 4 we can see that the CMD, ADDR and almost the whole\r
729          * DATA channel is sent.\r
730          */\r
731     currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currRxChIndex];\r
732     assert(  currChannel != CH_NOT_VALID );\r
733 \r
734     if( jobUnitPtr->fifoSent != jobUnitPtr->hwPtr->SR.B.RXCTR ) {\r
735 #if defined(STEP_VALIDATION)\r
736         SPI_ASSERT(0);\r
737 #endif\r
738         return SPIE_BAD;\r
739     }\r
740 \r
741         while ( jobUnitPtr->fifoSent != 0 ) {\r
742 \r
743         chConfig = &Spi_Global.configPtr->SpiChannelConfig[currChannel];\r
744 \r
745             RAMLOG_STR("CIR#");RAMLOG_DEC(jobUnitPtr->currRxChIndex);RAMLOG_STR("\n");\r
746 \r
747             /* Get this channels destination buffer */\r
748                 buf = spiGetRxBuf(currChannel, &bufLen);\r
749                 assert(bufLen!=0);  /* We should always get a valid bufLen */\r
750 \r
751         copyCnt = MIN( (bufLen - jobUnitPtr->rxChCnt) >> ((chConfig->SpiDataWidth-1)/8), jobUnitPtr->fifoSent );\r
752 \r
753         if( copyCnt == 0  ) {\r
754 #if defined(STEP_VALIDATION)\r
755         SPI_ASSERT(0);\r
756 #endif\r
757             return SPIE_BAD;\r
758         }\r
759 \r
760         jobUnitPtr->fifoSent -= copyCnt;\r
761 \r
762         bInChar = (chConfig->SpiDataWidth > 8 ) ? 2 : 1;\r
763 \r
764         /* Pop the FIFO */\r
765         if( buf != NULL ) {\r
766             for(i=0;i<copyCnt;i++) {\r
767                 popVal = jobUnitPtr->hwPtr->POPR.B.RXDATA;\r
768                 RAMLOG_STR("%");RAMLOG_HEX(popVal);\r
769                 buf[jobUnitPtr->rxChCnt] = (Spi_DataType)popVal;\r
770                 jobUnitPtr->rxChCnt += bInChar;\r
771             }\r
772         } else {\r
773             for(i=0;i<copyCnt;i++) {\r
774                 popVal = jobUnitPtr->hwPtr->POPR.B.RXDATA;\r
775                 jobUnitPtr->rxChCnt += bInChar;\r
776             }\r
777         }\r
778 \r
779         if( (bufLen - jobUnitPtr->rxChCnt ) == 0 ) {\r
780             /* advance to the next channel */\r
781             jobUnitPtr->rxChCnt = 0;\r
782             jobUnitPtr->currRxChIndex++;\r
783             currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currRxChIndex];\r
784             if( currChannel == CH_NOT_VALID ) {\r
785                 //assert(  jobUnitPtr->fifoSent == 0);\r
786                 jobUnitPtr->fifoSent = 0;\r
787                 jobUnitPtr->currRxChIndex = 0;\r
788                 rv = SPIE_OK;\r
789                 break;\r
790             }\r
791 \r
792         }\r
793         }\r
794 \r
795 #if defined(STEP_VALIDATION)\r
796         /* Check if we are done with this job */\r
797     if( 0 != jobUnitPtr->hwPtr->SR.B.RXCTR ) {\r
798         SPI_ASSERT(0);\r
799     }\r
800 #endif\r
801 \r
802         return rv;\r
803 }\r
804 \r
805 #endif\r
806 \r
807 //-------------------------------------------------------------------\r
808 \r
809 /**\r
810  * ISR for End of Queue interrupt\r
811  *\r
812  * The interrupt handling is quite simple. Since this driver assumes\r
813  * that we are the master the EOQ interrupt is sufficient to check.\r
814  *\r
815  * @param unit The HW unit it happend on\r
816  */\r
817 static void Spi_Isr( Spi_UnitType *uPtr) {\r
818         volatile struct DSPI_tag *spiHw = uPtr->hwPtr;\r
819         int rv;\r
820 \r
821         RAMLOG_STR("Spi_Isr\n");\r
822 \r
823         // This may seem pretty stupid to wait for the controller\r
824         // to shutdown here, but there seems to be no other way to do this.\r
825         // Reasons:\r
826         // - Waiting for DMA rx/tx hits earlier than EOQ.\r
827         // - Other interrupts from SPI all hit earlier than EOQ.\r
828         // TODO: There is the TCF_RE bit! Use this instead?\r
829 \r
830         // TODO: We could implement a timeout here and fail the job\r
831         // if this never happens.\r
832 \r
833         // This is the busy wait when called from a non-interrupt context\r
834         while (spiHw->SR.B.TXRXS) {\r
835                 Spi_Global.totalNbrOfWaitTXRXS++;\r
836         }\r
837 \r
838 #if (SPI_IMPLEMENTATION == SPI_DMA)\r
839         while (!Dma_ChannelDone(uPtr->dmaRxChannel)) {\r
840                 Spi_Global.totalNbrOfWaitRxDMA++;\r
841         }\r
842 #endif\r
843 \r
844 #if defined(STEP_VALIDATION)\r
845         /* Since EOQF clears TXRXS */\r
846         SPI_ASSERT( (spiHw->SR.B.EOQF==1) && (spiHw->SR.B.TXRXS == 0));\r
847 #endif\r
848 \r
849         /* Halt DSPI unit until we are ready for next transfer. */\r
850         spiHw->MCR.B.HALT = 1;\r
851         spiHw->SR.B.EOQF = 1;\r
852 \r
853 \r
854         Spi_Global.totalNbrOfTranfers++;\r
855 \r
856         // Disable EOQ interrupts\r
857         // NOTE!\r
858         //   This does NOT clear the interrupt request.\r
859         //   That can only be done by clearing( setting ) the EOQ\r
860         //   bit.. but that also triggers a new transfer.\r
861         //\r
862         // ALT\r
863         //   A possibility could be to use the HALT bit instead of\r
864         //   using this trick, but hey, this works\r
865 \r
866         DISABLE_EOQ_INTERRUPT(spiHw);\r
867 \r
868         // Update external buffers\r
869 #if (SPI_IMPLEMENTATION==SPI_DMA)\r
870         rv = Spi_Rx_DMA(uPtr);\r
871 \r
872 #if (USE_DIO_CS == STD_ON)\r
873     void (*cb)(int) = Spi_JobUnit[uPtr->currJobIndex].extDeviceCfgPtr->SpiCsCallback;\r
874     if( cb != NULL ) {\r
875         cb(0);\r
876     }\r
877 #endif\r
878 #elif (SPI_IMPLEMENTATION==SPI_FIFO)\r
879         rv = Spi_Rx_FIFO(uPtr);\r
880 \r
881         if( rv == SPIE_JOB_NOT_DONE ) {\r
882             /* RX FIFO now empty, but the job is not done -> send more */\r
883             Spi_WriteJob_FIFO ( uPtr->currJobIndex );\r
884                 RAMLOG_STR("Spi_Isr END\n");\r
885                 return;\r
886         }\r
887 #if (USE_DIO_CS == STD_ON)\r
888         else {\r
889             void (*cb)(int) = Spi_JobUnit[uPtr->currJobIndex].extDeviceCfgPtr->SpiCsCallback;\r
890             if( cb != NULL ) {\r
891                 cb(0);\r
892             }\r
893         }\r
894 #endif\r
895 #endif\r
896 \r
897         // Call notification end\r
898         if (uPtr->currJob->SpiJobEndNotification != NULL) {\r
899                 uPtr->currJob->SpiJobEndNotification();\r
900         }\r
901 \r
902         if (rv == SPIE_BAD) {\r
903                 // Fail both job and sequence\r
904                 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);\r
905                 Spi_SetJobResult(uPtr->currJob->SpiJobId, SPI_JOB_FAILED);\r
906                 Spi_SetSequenceResult(uPtr->currSeqPtr->SpiSequenceId,\r
907                                 SPI_SEQ_FAILED);\r
908 #if defined(STEP_VALIDATION)\r
909                 SPI_ASSERT(0);\r
910 #endif\r
911         } else {\r
912                 Spi_JobType nextJob;\r
913 \r
914                 // The job is at least done..\r
915                 Spi_SetJobResult(uPtr->currJob->SpiJobId, SPI_JOB_OK);\r
916 \r
917                 // WriteNextJob should\r
918                 // 1. Update the JobResult to SPI_JOB_OK\r
919                 // 2. Update the HWUnit status to IDLE\r
920 \r
921                 // Re-cap.\r
922                 // - Jobs have the controller\r
923                 // - Sequences can we interruptible between jobs.\r
924                 // But\r
925                 // According to SPI086 you can't share a job with a sequence that\r
926                 // is in SPI_SEQ_PENDING ( that happens first thing at Spi_AsyncTranmit() )\r
927                 //\r
928                 // So, I no clue what to use the priority thing for :(\r
929 \r
930                 nextJob = Spi_GetNextJob(uPtr);\r
931                 if( nextJob != JOB_NOT_VALID ) {\r
932                         Spi_JobWrite(nextJob);\r
933                         RAMLOG_STR("more_jobs\n");\r
934                 } else {\r
935                         // No more jobs, so set HwUnit and sequence IDLE/OK also.\r
936                         Spi_SetHWUnitStatus(uPtr, SPI_IDLE);\r
937                         Spi_SetSequenceResult(uPtr->currSeqPtr->SpiSequenceId,\r
938                                         SPI_SEQ_OK);\r
939 \r
940                         if (uPtr->currSeqPtr->SpiSeqEndNotification != NULL) {\r
941                                 uPtr->currSeqPtr->SpiSeqEndNotification();\r
942                         }\r
943 \r
944                         Spi_SetHWUnitStatus(uPtr, SPI_IDLE);\r
945 \r
946                         /* We are now ready for next transfer. */\r
947                         spiHw->MCR.B.HALT = 1;\r
948 \r
949                         RAMLOG_STR("NO_more_jobs\n");\r
950                 }\r
951         }\r
952 \r
953         RAMLOG_STR("Spi_Isr END\n");\r
954 }\r
955 \r
956 //-------------------------------------------------------------------\r
957 \r
958 Std_ReturnType Spi_WriteIB(Spi_ChannelType Channel,\r
959                 const Spi_DataType *DataBufferPtr) {\r
960         VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_WRITEIB_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );\r
961         VALIDATE_W_RV( ( Channel<SPI_MAX_CHANNEL ), SPI_WRITEIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );\r
962         VALIDATE_W_RV( ( DataBufferPtr != NULL ), SPI_WRITEIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );\r
963         VALIDATE_W_RV( ( SPI_IB==Spi_Global.configPtr->SpiChannelConfig[Channel].SpiChannelType ),\r
964                         SPI_WRITEIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );\r
965 \r
966         /* According to SPI051 it seems that we only have to a "depth" of 1 */\r
967 \r
968 \r
969         Std_ReturnType rv = E_NOT_OK;\r
970         return rv;\r
971 }\r
972 \r
973 /* Clock tables */\r
974 const uint32 clk_table_asc[] = { 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,\r
975                 4096, 8192, 16384, 32768, 65536 };\r
976 const uint32 clk_table_cssck[] = { 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,\r
977                 4096, 8192, 16384, 32768, 65536 };\r
978 const uint16 clk_table_br[] = { 2, 4, 6, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,\r
979                 4096, 8192, 16384, 32768 };\r
980 const uint8 clk_table_pasc[] = { 1, 3, 5, 7 };\r
981 const uint8 clk_table_pcssck[] = { 1, 3, 5, 7 };\r
982 const uint8 clk_table_pbr[] = { 2, 3, 5, 7 };\r
983 \r
984 /**\r
985  * Function to setup CTAR's from configuration\r
986  * @param spiHw - Pointer to HW SPI device\r
987  * @param extDev - Pointer to external device configuration\r
988  * @param ctar_unit - The ctar unit number to setup\r
989  * @param width - The width in bits of the data to send with the CTAR\r
990  */\r
991 static void Spi_SetupCTAR(      Spi_HWUnitType unit,\r
992                                                         const Spi_ExternalDeviceType *extDev,\r
993                                                         Spi_ChannelType ctar_unit,\r
994                                                         Spi_TransferStartType transferStart,\r
995                                                         uint8 width)\r
996 {\r
997         uint32 clock;\r
998         uint32 pre_br;\r
999         int i;\r
1000         int j;\r
1001         uint32 tmp;\r
1002         McuE_PeriperalClock_t perClock;\r
1003 \r
1004         volatile struct DSPI_tag *spiHw = GET_SPI_HW_PTR(unit);\r
1005         /* BAUDRATE CALCULATION\r
1006          * -----------------------------\r
1007          * Baudrate = Fsys/ PBR * ( 1+ DBR) / BR\r
1008          * PBR range: 2 to 7\r
1009          * DBR range: 0 to 1\r
1010          * BR : 2 to 32768\r
1011          *\r
1012          * To make this easy set DBR = 0 and PBR=2\r
1013          * --> BR=Fsys/(Baudrate.* 2 )\r
1014          *\r
1015          */\r
1016 #if defined(CFG_MPC5516) || defined(CFG_MPC5517) || defined(CFG_MPC560X)\r
1017         switch(unit) {\r
1018         case 0:\r
1019                 perClock = PERIPHERAL_CLOCK_DSPI_A;\r
1020                 break;\r
1021         case 1:\r
1022                 perClock = PERIPHERAL_CLOCK_DSPI_B;\r
1023                 break;\r
1024 #if defined(CFG_MPC5516) || defined(CFG_MPC5517) || defined(CFG_MPC5604B)\r
1025         case 2:\r
1026                 perClock = PERIPHERAL_CLOCK_DSPI_C;\r
1027                 break;\r
1028 #endif\r
1029 #if defined(CFG_MPC5516) || defined(CFG_MPC5517)\r
1030         case 3:\r
1031                 perClock = PERIPHERAL_CLOCK_DSPI_D;\r
1032                 break;\r
1033 #endif\r
1034         default:\r
1035                 assert(0);\r
1036                 break;\r
1037         }\r
1038 #else\r
1039 #error CPU not supported\r
1040 #endif\r
1041         clock = McuE_GetPeripheralClock(perClock);\r
1042 \r
1043         DEBUG(DEBUG_MEDIUM,"%s: Peripheral clock at %d Mhz\n",MODULE_NAME,clock);\r
1044 \r
1045         DEBUG(DEBUG_MEDIUM,"%s: Want to run at %d Mhz\n",MODULE_NAME,extDev->SpiBaudrate);\r
1046 \r
1047         spiHw->CTAR[ctar_unit].B.DBR = 0;\r
1048         spiHw->CTAR[ctar_unit].B.PBR = 0; // 2\r
1049         pre_br = clock / (extDev->SpiBaudrate\r
1050                         * clk_table_pbr[spiHw->CTAR[ctar_unit].B.PBR]);\r
1051 \r
1052         // find closest lesser\r
1053         for (i = 0; i < sizeof(clk_table_br) / sizeof(clk_table_br[0]); i++) {\r
1054                 if (clk_table_br[i] >= pre_br) {\r
1055                         break;\r
1056                 }\r
1057         }\r
1058 \r
1059         assert(i>=0);\r
1060         // Set it\r
1061         spiHw->CTAR[ctar_unit].B.BR = i;\r
1062 \r
1063         DEBUG(DEBUG_LOW,"%s: CLK %d Mhz\n",MODULE_NAME,\r
1064                         clock / clk_table_pbr[spiHw->CTAR[ctar_unit].B.PBR] *\r
1065                         ( 1 + spiHw->CTAR[ctar_unit].B.DBR)/clk_table_br[spiHw->CTAR[ctar_unit].B.BR]);\r
1066 \r
1067         /* For other timings autosar only specifies SpiTimeClk2Cs == "After SCK delay"\r
1068          * in Freescale language. The dumb thing is that this should be a relative time\r
1069          * to the clock. Not fixed.\r
1070          * Autosar specifies 0.0--100.0 ms(float)\r
1071          * Our intepretation is 0--1000000 ns (uint32)\r
1072          *\r
1073          * AFTER SCK DELAY:\r
1074          * -----------------------------\r
1075          * Tasc = 1/Fsys * PASC  * ASC [s]\r
1076          *\r
1077          * Assume the Tasc get's here in ns( typical range is ~10ns )\r
1078          */\r
1079 \r
1080         // Calc the PASC * ASC value...\r
1081         tmp = extDev->SpiTimeClk2Cs * (clock / 1000000);\r
1082 \r
1083         // Nothing fancy here...\r
1084         {\r
1085                 int best_i = 0;\r
1086                 int best_j = 0;\r
1087                 int b_value = INT_MAX;\r
1088                 int tt;\r
1089 \r
1090                 // Find the best match of Prescaler and Scaler value\r
1091                 for (i = 0; i < ARRAY_SIZE(clk_table_pasc); i++) {\r
1092                         for (j = 0; j < ARRAY_SIZE(clk_table_asc); j++) {\r
1093                                 tt = abs((int) clk_table_pasc[i] * clk_table_asc[j] * 1000\r
1094                                                 - tmp);\r
1095                                 if (tt < b_value) {\r
1096                                         best_i = i;\r
1097                                         best_j = j;\r
1098                                         b_value = tt;\r
1099                                 }\r
1100                         }\r
1101                 }\r
1102 \r
1103                 /* After SCK delay. */\r
1104                 spiHw->CTAR[ctar_unit].B.PASC = best_i;\r
1105                 spiHw->CTAR[ctar_unit].B.ASC = best_j;\r
1106         }\r
1107 \r
1108         DEBUG(DEBUG_MEDIUM,"%s: Timing: Tasc %d ns\n",MODULE_NAME,\r
1109                         clk_table_pasc[spiHw->CTAR[ctar_unit].B.PASC] *\r
1110                         clk_table_asc[spiHw->CTAR[ctar_unit].B.ASC] * 1000/ (clock/1000000) );\r
1111 \r
1112         /* The PCS to SCK delay is the delay between the assertion of PCS and\r
1113          * the first edge the SCK.\r
1114          *\r
1115          * PCS TO SCK DELAY:\r
1116          * -----------------------------\r
1117          * Tcsc = 1/Fsys * PCSSCK * CSSCK [s]\r
1118          */\r
1119 \r
1120         // Calc the PCSSCK * CSSCK value...\r
1121         tmp = extDev->SpiTimeCs2Clk * (clock / 1000000);\r
1122 \r
1123         // Nothing fancy here...\r
1124         {\r
1125                 int best_i = 0;\r
1126                 int best_j = 0;\r
1127                 int b_value = INT_MAX;\r
1128                 int tt;\r
1129 \r
1130                 // Find the best match of Prescaler and Scaler value\r
1131                 for (i = 0; i < ARRAY_SIZE(clk_table_pcssck); i++) {\r
1132                         for (j = 0; j < ARRAY_SIZE(clk_table_cssck); j++) {\r
1133                                 tt = abs((int) clk_table_pcssck[i] * clk_table_cssck[j] * 1000\r
1134                                                 - tmp);\r
1135                                 if (tt < b_value) {\r
1136                                         best_i = i;\r
1137                                         best_j = j;\r
1138                                         b_value = tt;\r
1139                                 }\r
1140                         }\r
1141                 }\r
1142 \r
1143                 /* PCS to SCK delay */\r
1144                 spiHw->CTAR[ctar_unit].B.PCSSCK = best_i;\r
1145                 spiHw->CTAR[ctar_unit].B.CSSCK = best_j;\r
1146         }\r
1147 \r
1148         DEBUG(DEBUG_MEDIUM,"%s: Timing: Tcsc %d ns\n",MODULE_NAME,\r
1149                         clk_table_pcssck[spiHw->CTAR[ctar_unit].B.PCSSCK] *\r
1150                         clk_table_cssck[spiHw->CTAR[ctar_unit].B.CSSCK]*1000/(clock/1000000));\r
1151 \r
1152         /* Time that PCS is high between transfers */\r
1153         spiHw->CTAR[ctar_unit].B.PDT = 2;\r
1154         spiHw->CTAR[ctar_unit].B.DT = 2;\r
1155 \r
1156         DEBUG(DEBUG_MEDIUM,"%s: Timing: Tdt  %d ns\n",MODULE_NAME,\r
1157                         clk_table_pasc[spiHw->CTAR[ctar_unit].B.PDT] *\r
1158                         clk_table_asc[spiHw->CTAR[ctar_unit].B.DT]*1000/(clock/1000000));\r
1159 \r
1160         /* Data is transferred MSB first */\r
1161 \r
1162         spiHw->CTAR[ctar_unit].B.LSBFE = (transferStart == SPI_TRANSFER_START_MSB ) ? 0 : 1;\r
1163 \r
1164         /* Set mode */\r
1165         spiHw->CTAR[ctar_unit].B.FMSZ = width - 1;\r
1166         spiHw->CTAR[ctar_unit].B.CPHA = (extDev->SpiDataShiftEdge\r
1167                         == SPI_EDGE_LEADING) ? 0 : 1;\r
1168         spiHw->CTAR[ctar_unit].B.CPOL = (extDev->SpiShiftClockIdleLevel == STD_LOW) ? 0 : 1;\r
1169 \r
1170         // This the ACTIVE polarity. Freescale have inactive polarity\r
1171         if (extDev->SpiCsPolarity == STD_HIGH) {\r
1172                 spiHw->MCR.R &= ~(1 << (16 + extDev->SpiCsIdentifier));\r
1173         } else {\r
1174                 spiHw->MCR.R |= (1 << (16 + extDev->SpiCsIdentifier));\r
1175         }\r
1176 }\r
1177 \r
1178 //-------------------------------------------------------------------\r
1179 \r
1180 static void Spi_InitController(Spi_UnitType *uPtr ) {\r
1181 \r
1182         volatile struct DSPI_tag *spiHw = uPtr->hwPtr;\r
1183 \r
1184         /* Module configuration register. */\r
1185         /* Master mode. */\r
1186         spiHw->MCR.B.MSTR = 1;\r
1187         /* No freeze. Run SPI when debugger is stopped. */\r
1188         spiHw->MCR.B.FRZ = 0;\r
1189         /* PSC5 as regular CS. */\r
1190         spiHw->MCR.B.PCSSE = 0;\r
1191 \r
1192         /* Enable FIFO's. */\r
1193 #if (SPI_IMPLEMENTATION == SPI_DMA)\r
1194         spiHw->MCR.B.DIS_RXF = 1;\r
1195         spiHw->MCR.B.DIS_TXF = 1;\r
1196 #elif (SPI_IMPLEMENTATION == SPI_FIFO)\r
1197     spiHw->MCR.B.DIS_RXF = 0;\r
1198     spiHw->MCR.B.DIS_TXF = 0;\r
1199 #endif\r
1200 \r
1201 \r
1202         /* Set all active low. */\r
1203         spiHw->MCR.B.PCSIS0 = 1;\r
1204         spiHw->MCR.B.PCSIS1 = 1;\r
1205         spiHw->MCR.B.PCSIS2 = 1;\r
1206         spiHw->MCR.B.PCSIS3 = 1;\r
1207         spiHw->MCR.B.PCSIS4 = 1;\r
1208         spiHw->MCR.B.PCSIS5 = 1;\r
1209 \r
1210 #if (SPI_IMPLEMENTATION == SPI_DMA)\r
1211         /* DMA TX FIFO fill. */\r
1212         spiHw->RSER.B.TFFF_RE = 1;\r
1213         spiHw->RSER.B.TFFF_DIRS = 1;\r
1214 \r
1215         /* DMA RX FIFO drain. */\r
1216         spiHw->RSER.B.RFDF_RE = 1;\r
1217         spiHw->RSER.B.RFDF_DIRS = 1;\r
1218 #endif\r
1219 \r
1220         // Setup CTAR's channel codes..\r
1221         for (int i = 0; i < (CTAR_CNT-1); i++) {\r
1222                 uPtr->channelCodes[i] = CH_NOT_VALID;\r
1223         }\r
1224 \r
1225         /* Force to stopped state. */\r
1226         spiHw->MCR.B.HALT = 1;\r
1227 \r
1228         spiHw->SR.B.EOQF = 1;\r
1229 \r
1230         /* Enable clocks. */\r
1231         spiHw->MCR.B.MDIS = 0;\r
1232 \r
1233 #if defined(__DMA_INT)\r
1234         Irq_InstallVector(Spi_Isr_DMA, 16 , 1, CPU_Z1);\r
1235 #endif\r
1236 \r
1237         // Install EOFQ int..\r
1238         switch (uPtr->hwUnit) {\r
1239 #if defined(CFG_MPC560X)\r
1240         case 0:\r
1241         ISR_INSTALL_ISR2("SPI_A",Spi_Isr_A, DSPI_0_ISR_EOQF, 15, 0);\r
1242         break;\r
1243         case 1:\r
1244         ISR_INSTALL_ISR2("SPI_B",Spi_Isr_B, DSPI_1_ISR_EOQF, 15, 0);\r
1245         break;\r
1246 #if defined(CFG_MPC5604B)\r
1247         case 2:\r
1248         ISR_INSTALL_ISR2("SPI_C",Spi_Isr_C, DSPI_2_ISR_EOQF, 15, 0);\r
1249         break;\r
1250 #endif\r
1251 #elif defined(CFG_MPC5516) || defined(CFG_MPC5517)\r
1252         case 0:\r
1253         ISR_INSTALL_ISR2("SPI_A",Spi_Isr_A, DSPI_A_ISR_EOQF, 15, 0);\r
1254         break;\r
1255         case 1:\r
1256         ISR_INSTALL_ISR2("SPI_B",Spi_Isr_B, DSPI_B_ISR_EOQF, 15, 0);\r
1257         break;\r
1258         case 2:\r
1259         ISR_INSTALL_ISR2("SPI_A",Spi_Isr_C, DSPI_C_ISR_EOQF, 15, 0);\r
1260         break;\r
1261         case 3:\r
1262         ISR_INSTALL_ISR2("SPI_B",Spi_Isr_D, DSPI_D_ISR_EOQF, 15, 0);\r
1263         break;\r
1264 #else\r
1265 #error ISR NOT installed.\r
1266 #endif\r
1267         }\r
1268 }\r
1269 \r
1270 //-------------------------------------------------------------------\r
1271 \r
1272 #if (SPI_IMPLEMENTATION==SPI_DMA)\r
1273 static void Spi_DmaSetup( Spi_UnitType *uPtr ) {\r
1274 \r
1275         Dma_TcdType *tcd;\r
1276 \r
1277         tcd = &uPtr->dmaTxTCD;\r
1278         *tcd = Spi_DmaTx;\r
1279         tcd->SADDR = (uint32) uPtr->txQueue;\r
1280         tcd->DADDR = (uint32) &(uPtr->hwPtr->PUSHR.R);\r
1281 \r
1282         Dma_StopChannel(uPtr->dmaTxChannel);\r
1283         Dma_CheckConfig();\r
1284 \r
1285         // CITER and BITER set when we send\r
1286         tcd = &uPtr->dmaRxTCD;\r
1287         *tcd = Spi_DmaRx;\r
1288         tcd->SADDR = (uint32) &(uPtr->hwPtr->POPR.R);\r
1289         tcd->DADDR = (uint32) uPtr->rxQueue;\r
1290 \r
1291         Dma_StopChannel(uPtr->dmaRxChannel);\r
1292         Dma_CheckConfig();\r
1293 \r
1294 }\r
1295 #endif\r
1296 \r
1297 //-------------------------------------------------------------------\r
1298 \r
1299 void Spi_Init(const Spi_ConfigType *ConfigPtr) {\r
1300         const Spi_JobConfigType *jobConfig2;\r
1301         Spi_UnitType *uPtr;\r
1302         uint32 confMask;\r
1303         uint8 ctrlNr;\r
1304 #if (SPI_IMPLEMENTATION == SPI_DMA )\r
1305         uint8 unitNr;\r
1306 #endif\r
1307 \r
1308 \r
1309         memset(&Spi_Global,0,sizeof(Spi_Global));\r
1310         Spi_Global.configPtr = ConfigPtr;\r
1311         Spi_Global.extBufPtr = Spi_Eb;\r
1312 \r
1313         Spi_Global.asyncMode = SPI_INTERRUPT_MODE;\r
1314 \r
1315         // Set all sequence results to OK\r
1316         for (Spi_SequenceType i = (Spi_SequenceType) 0; i < SPI_MAX_SEQUENCE; i++) {\r
1317                 Spi_SetSequenceResult(i, SPI_SEQ_OK);\r
1318         }\r
1319         // Figure out what HW controllers that are used\r
1320         for (int j = 0; j < Spi_GetJobCnt(); j++) {\r
1321                 jobConfig2 = &Spi_Global.configPtr->SpiJobConfig[j];\r
1322                 Spi_Global.spiHwConfigured |= (1 << jobConfig2->SpiHwUnit);\r
1323         }\r
1324 \r
1325         confMask = Spi_Global.spiHwConfigured;\r
1326 \r
1327         for (; confMask; confMask &= ~(1 << ctrlNr)) {\r
1328                 ctrlNr = ilog2(confMask);\r
1329                 DEBUG(DEBUG_LOW,"%s:Configured HW controller %d\n",MODULE_NAME,ctrlNr);\r
1330                 uPtr = GET_SPI_UNIT_PTR(ctrlNr);\r
1331                 uPtr->hwPtr = GET_SPI_HW_PTR(ctrlNr);\r
1332                 uPtr->hwUnit = ctrlNr;\r
1333                 Spi_InitController(uPtr);\r
1334                 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);\r
1335 #if (SPI_IMPLEMENTATION == SPI_DMA )\r
1336                 unitNr = Spi_CtrlToUnit[ctrlNr];\r
1337 \r
1338                 // DMA init...\r
1339                 //\r
1340                 unitNr = Spi_CtrlToUnit[ctrlNr];\r
1341 \r
1342                 /* Make sure that this channel shall be used. */\r
1343                 //assert (ConfigPtr->SpiHwConfig[ctrlNr].Activated);\r
1344                 assert(Spi_DmaConfig[unitNr].TxDmaChannel != (-1));\r
1345                 assert(Spi_DmaConfig[unitNr].RxDmaChannel != (-1));\r
1346 \r
1347                 uPtr->dmaTxChannel = Spi_DmaConfig[unitNr].TxDmaChannel;\r
1348                 uPtr->dmaRxChannel = Spi_DmaConfig[unitNr].RxDmaChannel;\r
1349 \r
1350                 Spi_DmaSetup(uPtr);\r
1351 #endif\r
1352 \r
1353         }\r
1354 \r
1355         /* Setup the relations for Job, for easy access */\r
1356         for(int j=0; j<SPI_MAX_JOB; j++ ) {\r
1357                 jobConfig2 = &Spi_Global.configPtr->SpiJobConfig[j];\r
1358                 Spi_JobUnit[j].jobCfgPtr = jobConfig2;\r
1359                 Spi_JobUnit[j].extDeviceCfgPtr = &Spi_Global.configPtr->SpiExternalDevice[jobConfig2->DeviceAssignment];\r
1360                 Spi_JobUnit[j].unitPtr = GET_SPI_UNIT_PTR(jobConfig2->SpiHwUnit);\r
1361                 Spi_JobUnit[j].hwPtr= GET_SPI_HW_PTR(jobConfig2->SpiHwUnit);\r
1362                 Spi_JobUnit[j].channelsPtr = &jobConfig2->ChannelAssignment[0];\r
1363         }\r
1364 \r
1365         /* Setup CTARS, configuration */\r
1366         {\r
1367                 Spi_UnitType *spiUnit;\r
1368 \r
1369                 int j = 0;\r
1370                 int k;\r
1371                 int l;\r
1372                 uint32 channelCode;\r
1373                 int channelIndex;\r
1374 \r
1375                 const Spi_JobConfigType *jobConfig;\r
1376                 const Spi_ChannelConfigType *chConfig;\r
1377 \r
1378                 for (j = 0; j < Spi_GetJobCnt(); j++) {\r
1379                         jobConfig = &Spi_Global.configPtr->SpiJobConfig[j];\r
1380                         spiUnit = GET_SPI_UNIT_PTR( jobConfig->SpiHwUnit );\r
1381 \r
1382                         // Also find the controllers used while we are at it\r
1383                         Spi_Global.spiHwConfigured |= (1 << jobConfig->SpiHwUnit);\r
1384 \r
1385                         // ..and set the job status\r
1386                         Spi_SetJobResult((Spi_JobType) j, SPI_JOB_OK);\r
1387 \r
1388                         l = 0;\r
1389                         // Go through all the jobs and it's channels to setup CTAS\r
1390                         // A job have the same physical controller ( SpiHwUnit )\r
1391                         while ((channelIndex = jobConfig->ChannelAssignment[l++])\r
1392                                         != CH_NOT_VALID) {\r
1393                                 chConfig = &Spi_Global.configPtr->SpiChannelConfig[channelIndex];\r
1394 \r
1395                                 // Form a channel code from\r
1396                                 // <MSB/LSB><external_device_id><channel width>\r
1397                                 channelCode = ( ((uint32_t)chConfig->SpiTransferStart << 16) +\r
1398                                                                 (jobConfig->DeviceAssignment << 8) +\r
1399                                                                 chConfig->SpiDataWidth);\r
1400 \r
1401                                 for (k = 0; k < (CTAR_CNT-1); k++) {\r
1402                                         if (spiUnit->channelCodes[k] == channelCode) {\r
1403                                                 Spi_ChannelInfo[channelIndex].ctarId = k;\r
1404                                                 DEBUG(DEBUG_LOW,"%s: Channel %d re-uses CTAR %d@%d . device=%d,width=%d\n",MODULE_NAME,channelIndex,k,jobConfig->SpiHwUnit,jobConfig->DeviceAssignment,chConfig->SpiDataWidth);\r
1405                                                 // already in list, break\r
1406                                                 break;\r
1407                                         }\r
1408 \r
1409                                         if (spiUnit->channelCodes[k] == CH_NOT_VALID) {\r
1410                                                 // Add to list\r
1411                                                 spiUnit->channelCodes[k] = channelCode;\r
1412                                                 // Assign the CTAR index to channel info..\r
1413                                                 DEBUG(DEBUG_LOW,"%s: Channel %d uses    CTAR %d@%d . device=%d,width=%d\n",MODULE_NAME,channelIndex,k,jobConfig->SpiHwUnit,jobConfig->DeviceAssignment,chConfig->SpiDataWidth);\r
1414 \r
1415                                                 Spi_SetupCTAR(\r
1416                                                                 jobConfig->SpiHwUnit,\r
1417                                                                 Spi_GetExternalDevicePtrFromIndex( jobConfig->DeviceAssignment),\r
1418                                                                 (Spi_ChannelType) k,\r
1419                                                                 chConfig->SpiTransferStart,\r
1420                                                                 chConfig->SpiDataWidth);\r
1421 \r
1422                                                 Spi_ChannelInfo[channelIndex].ctarId = k;\r
1423                                                 break;\r
1424                                         }\r
1425                                 }\r
1426                                 /* No more CTARS */\r
1427                                 assert(k<(CTAR_CNT-1));\r
1428                         }\r
1429                 }\r
1430         }\r
1431 \r
1432         Spi_Global.initRun = TRUE;\r
1433 }\r
1434 \r
1435 //-------------------------------------------------------------------\r
1436 \r
1437 Std_ReturnType Spi_DeInit(void) {\r
1438         volatile struct DSPI_tag *spiHw;\r
1439         uint32 confMask;\r
1440         uint8 confNr;\r
1441         Spi_UnitType *uPtr;\r
1442 \r
1443 \r
1444         VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_DEINIT_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );\r
1445         if (Spi_GetStatus() == SPI_BUSY)\r
1446                 return E_NOT_OK;\r
1447 \r
1448         // Disable the HW modules ( SPI021 )\r
1449         confMask = Spi_Global.spiHwConfigured;\r
1450 \r
1451         // Disable the SPI hw\r
1452         for (; confMask; confMask &= ~(1 << confNr)) {\r
1453                 confNr = ilog2(confMask);\r
1454                 spiHw = GET_SPI_HW_PTR(confNr);\r
1455                 // Disable the hardware..\r
1456                 spiHw->MCR.B.MDIS = 1;\r
1457                 uPtr = GET_SPI_UNIT_PTR(confNr);\r
1458 \r
1459                 Spi_InitController(uPtr);\r
1460                 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);\r
1461         }\r
1462 \r
1463         // SPI022\r
1464         Spi_Global.configPtr = NULL;\r
1465         Spi_Global.initRun = FALSE;\r
1466 \r
1467         return E_OK;\r
1468 }\r
1469 \r
1470 #if (SPI_IMPLEMENTATION==SPI_DMA)\r
1471 /**\r
1472  *\r
1473  * @param spiUnit\r
1474  * @param jobConfig\r
1475  * @return\r
1476  */\r
1477 static void Spi_DoWrite_DMA(    Spi_UnitType *spiUnit,Spi_JobType jobIndex,\r
1478                                                 const Spi_JobConfigType *jobConfig )\r
1479 {\r
1480         int j = 0;\r
1481         int k = 0;\r
1482         int channelIndex;\r
1483         const Spi_ChannelConfigType *chConfig;\r
1484         Spi_EbType *extChBuff;\r
1485         Spi_CommandType cmd;\r
1486 \r
1487         cmd.R = 0;\r
1488 \r
1489         // Find the channels for this job\r
1490         while ((channelIndex = jobConfig->ChannelAssignment[j++]) != CH_NOT_VALID) {\r
1491                 chConfig = &Spi_Global.configPtr->SpiChannelConfig[channelIndex];\r
1492 \r
1493                 /* Check configuration error */\r
1494 #if ( SPI_CHANNEL_BUFFERS_ALLOWED == 1  )\r
1495                 assert( chConfig->SpiChannelType == SPI_EB );\r
1496 #endif\r
1497 \r
1498                 // Send the channels that are setup with external buffers\r
1499                 // Get the external buffer for this channel\r
1500                 extChBuff = &Spi_Global.extBufPtr[channelIndex];\r
1501 \r
1502                 if (extChBuff->active == 0) {\r
1503                         LDEBUG_PRINTF("Err:External buffer %d@job %d not setup\n",channelIndex,jobIndex);\r
1504                         (void)jobIndex;\r
1505                         assert(0);\r
1506                 }\r
1507 \r
1508                 // Start to fill the SPI queue for the DMA:\r
1509                 for (k = 0; k < extChBuff->length; k++) {\r
1510                         uint32 csId =\r
1511                         Spi_Global.configPtr->SpiExternalDevice[jobConfig->DeviceAssignment].SpiCsIdentifier;\r
1512                         // Build cmd\r
1513                         cmd.B.CONT = 1; // Channels should keep CS active\r
1514                         // ( A job must assert CS continuously)\r
1515                         cmd.R |= (1 << (16 + csId)); // Set PCS\r
1516                         cmd.B.EOQ = 0;\r
1517                         cmd.B.CTAS = Spi_ChannelInfo[channelIndex].ctarId;\r
1518                         if (extChBuff->src != NULL) {\r
1519                                 if (chConfig->SpiDataWidth > 8) {\r
1520                                         cmd.B.TXDATA = (extChBuff->src[k] << 8) + (extChBuff->src[k + 1] & 0xff);\r
1521                                         k++;\r
1522                                 } else {\r
1523                                         cmd.B.TXDATA = extChBuff->src[k];\r
1524                                 }\r
1525                         } else {\r
1526                                 cmd.B.TXDATA = chConfig->SpiDefaultData;\r
1527                         }\r
1528 \r
1529                         // Just keep on filling the tx queue\r
1530                         spiUnit->txQueue[spiUnit->txCurrIndex++].R = cmd.R;\r
1531                 }\r
1532         } /*while( channelIndex == */\r
1533 \r
1534         // send last part\r
1535         cmd.B.CONT = 0; // CS high\r
1536         cmd.B.EOQ = 1; // last in queue\r
1537         spiUnit->txQueue[--spiUnit->txCurrIndex].R = cmd.R;\r
1538 \r
1539         // Set the length of the data to send\r
1540         spiUnit->dmaTxTCD.CITER = spiUnit->txCurrIndex + 1;\r
1541         spiUnit->dmaTxTCD.BITER = spiUnit->txCurrIndex + 1;\r
1542 \r
1543         Spi_Global.totalNbrOfStartedJobs++;\r
1544 \r
1545         RAMLOG_STR("Job: "); RAMLOG_DEC(jobIndex); RAMLOG_STR(" Cnt: "); RAMLOG_DEC(spiUnit->txCurrIndex+1); RAMLOG_STR("\n");\r
1546 \r
1547         DEBUG(DEBUG_LOW,"%s:Tx Job:%d cnt:%d first data:%04x\n",MODULE_NAME,jobIndex,spiUnit->txCurrIndex+1,spiUnit->txQueue[0].B.TXDATA);\r
1548 \r
1549         {\r
1550                 Spi_UnitType *spiUnit = GET_SPI_UNIT_PTR(jobConfig->SpiHwUnit);\r
1551                 volatile struct DSPI_tag *spiHw = GET_SPI_HW_PTR(jobConfig->SpiHwUnit);\r
1552 \r
1553                 Dma_ConfigureChannel((Dma_TcdType *) &spiUnit->dmaTxTCD,\r
1554                                 spiUnit->dmaTxChannel);\r
1555                 Dma_ConfigureChannel((Dma_TcdType *) &spiUnit->dmaRxTCD,\r
1556                                 spiUnit->dmaRxChannel);\r
1557                 /* Flush TX/Rx FIFO.  Ref. man. 23.5.1 step 8 */\r
1558                 spiHw->MCR.B.CLR_RXF = 1;\r
1559                 spiHw->MCR.B.CLR_TXF = 1;\r
1560 \r
1561                 Dma_StartChannel(spiUnit->dmaRxChannel);\r
1562                 Dma_StartChannel(spiUnit->dmaTxChannel);\r
1563 \r
1564                 // Step 9. Clear TCNT\r
1565                 spiHw->TCR.B.SPI_TCNT = 0;\r
1566 \r
1567                 if (    (Spi_Global.asyncMode == SPI_INTERRUPT_MODE) &&\r
1568                                 (spiUnit->callType == SPI_ASYNC_CALL)) {\r
1569                         ENABLE_EOQ_INTERRUPT(spiHw);\r
1570                 } else {\r
1571                         DISABLE_EOQ_INTERRUPT(spiHw);\r
1572                 }\r
1573 \r
1574                 /* This will trig a new transfer. Ref. man. 23.5.1 step 11 */\r
1575                 spiHw->SR.B.EOQF = 1;\r
1576                 spiHw->MCR.B.HALT = 0;\r
1577 \r
1578                 // Since it's not obvious on how to tell when a SPI sequence\r
1579                 // is sent, keep things below to what things have been tested.\r
1580 #if defined(STEP_VALIDATION)\r
1581                 /* Wait for transfer to complete (EOQF bit is set) */\r
1582                 while (spiHw->SR.B.EOQF==1) {\r
1583                         Spi_Global.eoqf_cnt++;\r
1584                 }\r
1585                 while (spiHw->SR.B.TXRXS) {Spi_Global.txrxs_cnt++;}\r
1586                 while( EDMA.TCD[spiUnit->dmaRxChannel].ACTIVE ) {;}\r
1587 #endif\r
1588 \r
1589         }\r
1590 }\r
1591 #endif\r
1592 \r
1593 #if (SPI_IMPLEMENTATION==SPI_FIFO)\r
1594 /**\r
1595  *\r
1596  * @param spiUnit\r
1597  * @param jobConfig\r
1598  * @return\r
1599  */\r
1600 static void Spi_WriteJob_FIFO( Spi_JobType jobIndex )\r
1601 {\r
1602         Spi_ChannelType                 currChannel;\r
1603         Spi_CommandType                 cmd;\r
1604         Spi_CommandType                 dCmd;\r
1605     Spi_NumberOfDataType            bufLen;\r
1606         const Spi_ChannelConfigType *   chConfig;\r
1607     Spi_JobUnitType *               jobUnitPtr;\r
1608     const Spi_DataType *            buf;\r
1609     Spi_NumberOfDataType            copyCnt;\r
1610     Spi_NumberOfDataType            fifoLeft;\r
1611 //    boolean                         done = 0;\r
1612 //    boolean                         lastJob = 0;\r
1613         int     i;\r
1614         jobUnitPtr = &Spi_JobUnit[jobIndex];\r
1615 \r
1616 \r
1617         fifoLeft = FIFO_DEPTH;\r
1618 \r
1619         RAMLOG_STR("Spi_WriteJob_FIFO\n");\r
1620 \r
1621 #if defined(STEP_VALIDATION)\r
1622     if(  jobUnitPtr->hwPtr->SR.B.TXCTR != 0 ) {\r
1623         SPI_ASSERT(0);\r
1624     }\r
1625 #endif\r
1626 \r
1627     cmd.R = 0;\r
1628     dCmd.R = 0xfffffffful;\r
1629 \r
1630         /* Iterate over the channels for this job */\r
1631     currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currTxChIndex];\r
1632     while ( fifoLeft != 0) {\r
1633 \r
1634                 chConfig = &Spi_Global.configPtr->SpiChannelConfig[currChannel];\r
1635                 buf = spiGetTxBuf( currChannel, &bufLen);\r
1636 \r
1637                 /* Minimum of how much data to copy and the limit of the FIFO */\r
1638                 copyCnt = MIN( (bufLen - jobUnitPtr->txChCnt) >> ((chConfig->SpiDataWidth-1)/8), fifoLeft );\r
1639 \r
1640         /* Channels should keep CS active ( A job must assert CS continuously) */\r
1641         cmd.B.CONT = 1;\r
1642         /* Set the Chip Select (PCS) */\r
1643         cmd.R |= (1 << (16 + jobUnitPtr->extDeviceCfgPtr->SpiCsIdentifier));\r
1644 \r
1645 #if defined(STEP_VALIDATION)\r
1646         if( cmd.B.EOQ == 1) {\r
1647             SPI_ASSERT(0);\r
1648         }\r
1649 #endif\r
1650 \r
1651         /* Push as much as we can (FIFO or Channel limits) */\r
1652         for(i=0; i < copyCnt ; i++ ) {\r
1653             cmd.B.CTAS = Spi_ChannelInfo[currChannel].ctarId;\r
1654             if (buf != NULL) {\r
1655                 if (chConfig->SpiDataWidth > 8 ) {\r
1656                     cmd.B.TXDATA =  (buf[jobUnitPtr->txChCnt] << 8) +\r
1657                                     (buf[jobUnitPtr->txChCnt  + 1] & 0xff);\r
1658                 } else {\r
1659                     cmd.B.TXDATA = buf[jobUnitPtr->txChCnt];\r
1660                 }\r
1661             } else {\r
1662                 cmd.B.TXDATA = chConfig->SpiDefaultData;\r
1663             }\r
1664 \r
1665             if (chConfig->SpiDataWidth > 8 ) {\r
1666                 jobUnitPtr->txChCnt+=2;\r
1667             } else {\r
1668                 jobUnitPtr->txChCnt++;\r
1669             }\r
1670 \r
1671 \r
1672             if( dCmd.R != 0xfffffffful) {\r
1673                 jobUnitPtr->hwPtr->PUSHR.R = dCmd.R;  // Write delayed\r
1674             }\r
1675 \r
1676             dCmd.R = cmd.R;     // Save it\r
1677             --fifoLeft;\r
1678         } /* for */\r
1679 \r
1680         RAMLOG_STR("CI#");RAMLOG_DEC(jobUnitPtr->currTxChIndex);RAMLOG_STR("\n");\r
1681 \r
1682 \r
1683         /* Done with channel? */\r
1684         if( ((bufLen -  jobUnitPtr->txChCnt) == 0) ) {\r
1685             jobUnitPtr->txChCnt = 0;\r
1686             /* Done with job? */\r
1687             jobUnitPtr->currTxChIndex++;\r
1688             currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currTxChIndex];\r
1689             if( currChannel == CH_NOT_VALID ) {\r
1690                 jobUnitPtr->currTxChIndex = 0;\r
1691                 cmd.B.CONT = 0;\r
1692                 break;\r
1693             }\r
1694         }\r
1695 \r
1696     } /* while */\r
1697 \r
1698     cmd.B.EOQ = 1;\r
1699     jobUnitPtr->hwPtr->PUSHR.R = cmd.R;\r
1700 \r
1701     jobUnitPtr->fifoSent = FIFO_DEPTH - fifoLeft;\r
1702 \r
1703 #if defined(STEP_VALIDATION)\r
1704         if( jobUnitPtr->fifoSent != jobUnitPtr->hwPtr->SR.B.TXCTR ) {\r
1705             SPI_ASSERT(0);\r
1706         }\r
1707 #endif\r
1708 \r
1709         jobUnitPtr->hwPtr->TCR.B.SPI_TCNT = 0;\r
1710 \r
1711     if ( (Spi_Global.asyncMode == SPI_INTERRUPT_MODE) &&\r
1712          (jobUnitPtr->unitPtr->callType == SPI_ASYNC_CALL)) {\r
1713         ENABLE_EOQ_INTERRUPT(jobUnitPtr->hwPtr);\r
1714     } else {\r
1715         DISABLE_EOQ_INTERRUPT(jobUnitPtr->hwPtr);\r
1716     }\r
1717 \r
1718 #if defined(STEP_VALIDATION)\r
1719     /* Verify FIFO before sending */\r
1720     {\r
1721         SPICommandType *base = (SPICommandType *)&jobUnitPtr->hwPtr->TXFR[0];\r
1722         SPICommandType *curr;\r
1723         int i,lastIndex;\r
1724 \r
1725         i = jobUnitPtr->hwPtr->SR.B.TXNXTPTR;   /* Next entry to send */\r
1726         lastIndex = ( i + jobUnitPtr->hwPtr->SR.B.TXCTR - 1 ) % FIFO_DEPTH;\r
1727         while( i != lastIndex )  {\r
1728             curr = base + i;\r
1729             if( curr->B.EOQ == 1) {  /* This entry must not have EOQ set */\r
1730                 SPI_ASSERT(0);\r
1731             }\r
1732 \r
1733             i = (i + 1) % FIFO_DEPTH;\r
1734         }\r
1735         curr = base + i;\r
1736         if( curr->B.EOQ != 1) {\r
1737             SPI_ASSERT(0);              /* Last entry must have EOQ set */\r
1738         }\r
1739     }\r
1740 #endif\r
1741 \r
1742         jobUnitPtr->hwPtr->SR.B.EOQF = 1;\r
1743         jobUnitPtr->hwPtr->MCR.B.HALT = 0;\r
1744 \r
1745 #if defined(STEP_VALIDATION)\r
1746         /* Wait for transfer to complete (EOQF bit is set) */\r
1747         while (jobUnitPtr->hwPtr->SR.B.EOQF==1) {\r
1748             Spi_Global.eoqf_cnt++;\r
1749         }\r
1750         while (jobUnitPtr->hwPtr->SR.B.TXRXS) {Spi_Global.txrxs_cnt++;}\r
1751 #endif\r
1752 \r
1753         // TODO: Clear FIFO's? CLR_TXF?\r
1754 \r
1755 }\r
1756 #endif /* (SPI_IMPLEMENTATION==SPI_FIFO) */\r
1757 \r
1758 \r
1759 //-------------------------------------------------------------------\r
1760 \r
1761 \r
1762 \r
1763 \r
1764 /**\r
1765  * Write a job to the SPI bus\r
1766  *\r
1767  * @param jobIndex The job to write to the SPI bus\r
1768  */\r
1769 static void Spi_JobWrite(Spi_JobType jobIndex) {\r
1770         Spi_UnitType *uPtr = Spi_JobUnit[jobIndex].unitPtr;\r
1771 \r
1772         uPtr->txCurrIndex = 0;\r
1773         uPtr->currJob = Spi_JobUnit[jobIndex].jobCfgPtr;\r
1774         uPtr->currJobIndex = jobIndex;\r
1775 #if (SPI_IMPLEMENTATION == SPI_FIFO)\r
1776         Spi_JobUnit[jobIndex].txChCnt = 0;\r
1777         Spi_JobUnit[jobIndex].rxChCnt = 0;\r
1778 #endif\r
1779 \r
1780         Spi_SetHWUnitStatus(uPtr, SPI_BUSY);\r
1781         Spi_SetJobResult(jobIndex, SPI_JOB_PENDING);\r
1782 \r
1783 #if (USE_DIO_CS == STD_ON)\r
1784     if( Spi_JobUnit[jobIndex].extDeviceCfgPtr->SpiCsCallback != NULL ) {\r
1785         Spi_JobUnit[jobIndex].extDeviceCfgPtr->SpiCsCallback(1);\r
1786     }\r
1787 #endif\r
1788 \r
1789 #if (SPI_IMPLEMENTATION==SPI_DMA)\r
1790         Spi_DoWrite_DMA( uPtr, jobIndex, Spi_JobUnit[jobIndex].jobCfgPtr );\r
1791 #elif (SPI_IMPLEMENTATION==SPI_FIFO)\r
1792         Spi_JobUnit[jobIndex].currTxChIndex = 0;\r
1793         Spi_WriteJob_FIFO ( jobIndex );\r
1794 #endif\r
1795 \r
1796 }\r
1797 \r
1798 #if defined(USE_LDEBUG_PRINTF) && ( DEBUG_LVL <= DEBUG_HIGH )\r
1799 void Spi_PrintSeqInfo(const Spi_SequenceConfigType *seqConfigPtr) {\r
1800         int i = 0;\r
1801         uint32 job;\r
1802         DEBUG(DEBUG_HIGH,"%s: Seq: %d:",MODULE_NAME,seqConfigPtr->SpiSequenceId);\r
1803 \r
1804         while ((job = seqConfigPtr->JobAssignment[i]) != JOB_NOT_VALID) {\r
1805                 DEBUG(DEBUG_HIGH,"%d ",job);\r
1806                 i++;\r
1807         } DEBUG(DEBUG_HIGH,"\n");\r
1808 }\r
1809 #endif\r
1810 \r
1811 \r
1812 /**\r
1813  * Write a sequence to the SPI bus\r
1814  *\r
1815  * @param seqIndex The sequence\r
1816  * @param sync 1 - make the call sync. 0 - make the call async\r
1817  */\r
1818 static void Spi_SeqWrite(Spi_SequenceType seqIndex, Spi_CallTypeType sync) {\r
1819 \r
1820         const Spi_SequenceConfigType *seqConfig;\r
1821         const Spi_JobConfigType *jobConfig;\r
1822         Spi_UnitType *uPtr;\r
1823         Spi_JobType jobIndex;\r
1824 \r
1825         seqConfig = Spi_GetSeqPtrFromIndex(seqIndex);\r
1826         jobIndex = seqConfig->JobAssignment[0];\r
1827         jobConfig = Spi_GetJobPtrFromIndex(jobIndex);\r
1828 \r
1829         uPtr = Spi_GetUnitPtrFromIndex(jobConfig->SpiHwUnit);\r
1830 \r
1831         /* Fill in the required fields for job and sequence.. */\r
1832         uPtr->currJobIndexPtr = &seqConfig->JobAssignment[0];\r
1833         uPtr->callType = sync;\r
1834         uPtr->currSeqPtr = seqConfig;\r
1835 \r
1836         Spi_SetSequenceResult(seqIndex, SPI_SEQ_PENDING);\r
1837 \r
1838         // Setup interrupt for end of queue\r
1839         if (    (Spi_Global.asyncMode == SPI_INTERRUPT_MODE) &&\r
1840                         (uPtr->callType== SPI_ASYNC_CALL)) {\r
1841                 DEBUG(DEBUG_MEDIUM,"%s: async/interrupt mode\n",MODULE_NAME);\r
1842         } else {\r
1843                 DEBUG(DEBUG_MEDIUM,"%s: sync/polled mode\n",MODULE_NAME);\r
1844         }\r
1845 \r
1846 #if defined(USE_LDEBUG_PRINTF) && ( DEBUG_LVL <= DEBUG_HIGH )\r
1847         Spi_PrintSeqInfo( seqConfig );\r
1848 #endif\r
1849 \r
1850         Spi_JobWrite(jobIndex);\r
1851 \r
1852         if (uPtr->callType == SPI_SYNC_CALL) {\r
1853                 while (Spi_GetSequenceResult(seqIndex) == SPI_SEQ_PENDING) {\r
1854                         Spi_Isr(uPtr);\r
1855                 }\r
1856         }\r
1857 \r
1858 }\r
1859 \r
1860 //-------------------------------------------------------------------\r
1861 static _Bool Spi_AnyPendingJobs(Spi_SequenceType Sequence) {\r
1862 \r
1863         // Check that we don't share any jobs with another sequence that is SPI_SEQ_PENDING\r
1864         for (int i = 0; i < SPI_MAX_SEQUENCE; i++) {\r
1865                 if (i == Sequence) {\r
1866                         continue;\r
1867                 }\r
1868 \r
1869                 if (Spi_GetSequenceResult(i) == SPI_SEQ_PENDING) {\r
1870                         // We have found a pending sequence... check that we don't share any jobs\r
1871                         // with that sequence, SPI086\r
1872                         if (Spi_ShareJobs(Sequence, i)) {\r
1873                                 return 1;\r
1874                         }\r
1875                 }\r
1876         }\r
1877 \r
1878         return 0;\r
1879 }\r
1880 \r
1881 //-------------------------------------------------------------------\r
1882 \r
1883 \r
1884 /**\r
1885  * Blocking write\r
1886  *\r
1887  * @param Sequence\r
1888  * @return\r
1889  */\r
1890 Std_ReturnType Spi_SyncTransmit(Spi_SequenceType Sequence) {\r
1891 \r
1892         VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_SYNCTRANSMIT_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );\r
1893         VALIDATE_W_RV( ( SPI_MAX_SEQUENCE>Sequence ), SPI_SYNCTRANSMIT_SERVICE_ID, SPI_E_PARAM_SEQ, E_NOT_OK );\r
1894         Std_ReturnType rv = E_OK;\r
1895 \r
1896         if (Spi_GetSequenceResult(Sequence) == SPI_SEQ_PENDING) {\r
1897                 DEBUG(DEBUG_LOW,"%s: Spi_AsyncTransmit() is PENDING\n",MODULE_NAME);\r
1898                 return E_NOT_OK; // SPI157\r
1899         }\r
1900 \r
1901         assert(Spi_GetSequenceResult(Sequence) == SPI_SEQ_OK);\r
1902 \r
1903         if (Spi_AnyPendingJobs(Sequence)) {\r
1904                 return E_NOT_OK;\r
1905         }\r
1906 \r
1907         Spi_SeqWrite(Sequence, SPI_SYNC_CALL);\r
1908 \r
1909         return rv;\r
1910 }\r
1911 \r
1912 //-------------------------------------------------------------------\r
1913 \r
1914 Std_ReturnType Spi_AsyncTransmit(Spi_SequenceType Sequence) {\r
1915         VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_ASYNCTRANSMIT_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );\r
1916         VALIDATE_W_RV( ( SPI_MAX_SEQUENCE>Sequence ), SPI_ASYNCTRANSMIT_SERVICE_ID, SPI_E_PARAM_SEQ, E_NOT_OK );\r
1917 \r
1918         if (Spi_GetSequenceResult(Sequence) == SPI_SEQ_PENDING) {\r
1919                 DEBUG(DEBUG_LOW,"%s: Spi_AsyncTransmit() is PENDING\n",MODULE_NAME);\r
1920                 return E_NOT_OK; // SPI157\r
1921         }\r
1922 \r
1923         assert(Spi_GetSequenceResult(Sequence) == SPI_SEQ_OK);\r
1924 \r
1925         if (Spi_AnyPendingJobs(Sequence)) {\r
1926                 return E_NOT_OK;\r
1927         }\r
1928 \r
1929         DEBUG(DEBUG_LOW,"%s: Starting seq: %d\n",MODULE_NAME,Sequence);\r
1930 \r
1931         Spi_SeqWrite(Sequence, SPI_ASYNC_CALL);\r
1932 \r
1933         return E_OK;\r
1934 }\r
1935 \r
1936 //-------------------------------------------------------------------\r
1937 \r
1938 \r
1939 Std_ReturnType Spi_ReadIB(      Spi_ChannelType Channel,\r
1940                                                         Spi_DataType * const DataBufferPtr)\r
1941 {\r
1942         (void)DataBufferPtr;\r
1943 \r
1944         VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_READIB_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );\r
1945         VALIDATE_W_RV( ( Channel<SPI_MAX_CHANNEL ), SPI_READIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );\r
1946         VALIDATE_W_RV( ( SPI_IB<Spi_Global.configPtr->SpiChannelConfig[Channel].SpiChannelType ),\r
1947                         SPI_READIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );\r
1948 \r
1949         /* NOT SUPPORTED */\r
1950 \r
1951         Std_ReturnType rv = E_NOT_OK;\r
1952         return rv;\r
1953 }\r
1954 \r
1955 //-------------------------------------------------------------------\r
1956 \r
1957 Std_ReturnType Spi_SetupEB(     Spi_ChannelType Channel,\r
1958                                                         const Spi_DataType* SrcDataBufferPtr,\r
1959                                                         Spi_DataType* DesDataBufferPtr,\r
1960                                                         Spi_NumberOfDataType Length)\r
1961 {\r
1962         VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_SETUPEB_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );\r
1963         VALIDATE_W_RV( ( Channel<SPI_MAX_CHANNEL ), SPI_SETUPEB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );\r
1964 #if ( SPI_CHANNEL_BUFFERS_ALLOWED == 1 )\r
1965         VALIDATE_W_RV( ( SPI_EB==Spi_Global.configPtr->SpiChannelConfig[Channel].SpiChannelType ),\r
1966                         SPI_SETUPEB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );\r
1967 #endif\r
1968         // SPI067\r
1969         VALIDATE_W_RV( ( Length<=Spi_Global.configPtr->SpiChannelConfig[Channel].SpiEbMaxLength ),\r
1970                         SPI_SETUPEB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );\r
1971 \r
1972         Spi_EbType *extChBuff = &Spi_Global.extBufPtr[Channel];\r
1973         const Spi_ChannelConfigType *chConfig =\r
1974                         &Spi_Global.configPtr->SpiChannelConfig[Channel];\r
1975 \r
1976         if (chConfig->SpiChannelType == SPI_EB) {\r
1977                 extChBuff->src = SrcDataBufferPtr;\r
1978                 extChBuff->dest = DesDataBufferPtr;\r
1979                 extChBuff->length = Length;\r
1980                 extChBuff->active = 1;\r
1981         } else {\r
1982                 /* NOT SUPPORTED */\r
1983                 assert(0);\r
1984                 while (1)\r
1985                         ;\r
1986         }\r
1987 \r
1988         return E_OK;\r
1989 }\r
1990 \r
1991 //-------------------------------------------------------------------\r
1992 \r
1993 Spi_StatusType Spi_GetStatus(void) {\r
1994         VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETSTATUS_SERVICE_ID, SPI_E_UNINIT, SPI_UNINIT );\r
1995 \r
1996         // Check all sequences if they have any job pending\r
1997         for (int i = 0; i < SPI_MAX_SEQUENCE; i++) {\r
1998                 if (Spi_GetSequenceResult(i) == SPI_SEQ_PENDING) {\r
1999                         return SPI_BUSY;\r
2000                 }\r
2001         }\r
2002 \r
2003         return SPI_IDLE;\r
2004 }\r
2005 \r
2006 //-------------------------------------------------------------------\r
2007 \r
2008 \r
2009 Spi_JobResultType Spi_GetJobResult(Spi_JobType Job) {\r
2010         VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETJOBRESULT_SERVICE_ID, SPI_E_UNINIT, SPI_JOB_FAILED );\r
2011         VALIDATE_W_RV( ( SPI_MAX_JOB<Job ), SPI_GETJOBRESULT_SERVICE_ID, SPI_E_PARAM_JOB, SPI_JOB_FAILED );\r
2012 \r
2013         return Spi_JobUnit[Job].jobResult;\r
2014 }\r
2015 \r
2016 //-------------------------------------------------------------------\r
2017 \r
2018 \r
2019 Spi_SeqResultType Spi_GetSequenceResult(Spi_SequenceType Sequence) {\r
2020         Spi_SeqResultType rv;\r
2021 \r
2022         VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETSEQUENCERESULT_SERVICE_ID, SPI_E_UNINIT, SPI_SEQ_FAILED );\r
2023         VALIDATE_W_RV( ( SPI_MAX_SEQUENCE>Sequence ), SPI_GETSEQUENCERESULT_SERVICE_ID, SPI_E_PARAM_SEQ, SPI_SEQ_FAILED );\r
2024 \r
2025         rv = Spi_SeqUnit[Sequence].seqResult;\r
2026 \r
2027         return rv;\r
2028 }\r
2029 \r
2030 //-------------------------------------------------------------------\r
2031 \r
2032 Spi_StatusType Spi_GetHWUnitStatus(Spi_HWUnitType HWUnit) {\r
2033         VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETHWUNITSTATUS_SERVICE_ID, SPI_E_UNINIT, SPI_UNINIT );\r
2034 \r
2035         return Spi_Unit[Spi_CtrlToUnit[HWUnit]].status;\r
2036 }\r
2037 \r
2038 //-------------------------------------------------------------------\r
2039 \r
2040 #if (SPI_CANCEL_API == STD_ON )\r
2041 void Spi_Cancel( Spi_SequenceType Sequence ) {\r
2042         VALIDATE( ( TRUE == Spi_Global.initRun ), SPI_CANCEL_SERVICE_ID, SPI_E_UNINIT );\r
2043         VALIDATE( ( SPI_MAX_SEQUENCE<Sequence ), SPI_CANCEL_SERVICE_ID, SPI_E_PARAM_SEQ );\r
2044 \r
2045         /* NOT SUPPORTED */\r
2046 }\r
2047 #endif\r
2048 \r
2049 //-------------------------------------------------------------------\r
2050 \r
2051 \r
2052 #if ( SPI_LEVEL_DELIVERED == 2) // SPI154\r
2053 Std_ReturnType Spi_SetAsyncMode(Spi_AsyncModeType Mode) {\r
2054         VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_SETASYNCMODE_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );\r
2055 \r
2056         // Note!\r
2057         // Not really sure by whom this function is supposed to be called by.\r
2058         // The users of SPI(e2,flash,etc) should probably not use this.\r
2059 \r
2060         for (int i = 0; i < SPI_MAX_SEQUENCE; i++) {\r
2061                 if (Spi_GetSequenceResult(i) == SPI_SEQ_PENDING) {\r
2062                         return E_NOT_OK;\r
2063                 }\r
2064         }\r
2065 \r
2066         Spi_Global.asyncMode = Mode;\r
2067 \r
2068         return E_OK;\r
2069 }\r
2070 #endif\r
2071 \r
2072 //-------------------------------------------------------------------\r
2073 \r
2074 void Spi_MainFunction_Handling(void) {\r
2075         /* NOT SUPPORTED */\r
2076 }\r
2077 \r
2078 //-------------------------------------------------------------------\r
2079 \r
2080 void Spi_MainFunction_Driving(void) {\r
2081         volatile struct DSPI_tag *spiHw;\r
2082         uint32 confMask;\r
2083         uint8 ctrlNr;\r
2084         Spi_UnitType *uPtr;\r
2085 \r
2086         // TODO: check that the queue is empty.. if so do the next job.\r
2087         if (Spi_Global.asyncMode == SPI_POLLING_MODE) {\r
2088                 confMask = Spi_Global.spiHwConfigured;\r
2089 \r
2090                 for (; confMask; confMask &= ~(1 << ctrlNr)) {\r
2091                         ctrlNr = ilog2(confMask);\r
2092                         uPtr = GET_SPI_UNIT_PTR(ctrlNr);\r
2093                         spiHw = uPtr->hwPtr;\r
2094 \r
2095                         if (Spi_GetHWUnitStatus(ctrlNr) == SPI_BUSY) {\r
2096                                 if (spiHw->SR.B.TXRXS) {\r
2097                                         // Still not done..\r
2098                                 } else {\r
2099                                         uPtr = GET_SPI_UNIT_PTR(ctrlNr);\r
2100                                         Spi_Isr(uPtr);\r
2101                                 }\r
2102                         }\r
2103                 }\r
2104         }\r
2105 }\r
2106 \r