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