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