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