1 /**
2  * @file       spimss.c
3  * @brief      This file contains the function implementations for the
4  *             Serial Peripheral Interface (SPIMSS) peripheral module.
5  */
6 
7 /******************************************************************************
8  *
9  * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
10  * Analog Devices, Inc.),
11  * Copyright (C) 2023-2024 Analog Devices, Inc.
12  *
13  * Licensed under the Apache License, Version 2.0 (the "License");
14  * you may not use this file except in compliance with the License.
15  * You may obtain a copy of the License at
16  *
17  *     http://www.apache.org/licenses/LICENSE-2.0
18  *
19  * Unless required by applicable law or agreed to in writing, software
20  * distributed under the License is distributed on an "AS IS" BASIS,
21  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22  * See the License for the specific language governing permissions and
23  * limitations under the License.
24  *
25  ******************************************************************************/
26 
27 /* **** Includes **** */
28 #include <string.h>
29 #include <stdio.h>
30 #include <stdint.h>
31 #include "mxc_device.h"
32 #include "mxc_assert.h"
33 #include "mxc_sys.h"
34 #include "spimss_reva.h"
35 #include "mxc_lock.h"
36 #include "dma.h"
37 #include "nvic_table.h"
38 
39 /**
40  * @ingroup spimss
41  * @{
42  */
43 
44 /* **** Definitions **** */
45 
46 /* **** Globals **** */
47 typedef struct {
48     spimss_reva_req_t *req;
49     mxc_spimss_reva_regs_t *spi;
50     int channelTx;
51     int channelRx;
52     bool auto_dma_handlers;
53 } spimss_reva_req_state_t;
54 
55 static spimss_reva_req_state_t states[MXC_SPIMSS_INSTANCES];
56 
57 /* **** Functions **** */
58 static int MXC_SPIMSS_RevA_TransSetup(mxc_spimss_reva_regs_t *spi, spimss_reva_req_t *req,
59                                       int master);
60 static uint32_t MXC_SPIMSS_RevA_MasterTransHandler(mxc_spimss_reva_regs_t *spi,
61                                                    spimss_reva_req_t *req);
62 static uint32_t MXC_SPIMSS_RevA_TransHandler(mxc_spimss_reva_regs_t *spi, spimss_reva_req_t *req);
63 static uint32_t MXC_SPIMSS_RevA_SlaveTransHandler(mxc_spimss_reva_regs_t *spi,
64                                                   spimss_reva_req_t *req);
65 
66 /* ************************************************************************** */
MXC_SPIMSS_RevA_Init(mxc_spimss_reva_regs_t * spi,unsigned mode,unsigned freq)67 int MXC_SPIMSS_RevA_Init(mxc_spimss_reva_regs_t *spi, unsigned mode, unsigned freq)
68 {
69     int spi_num;
70     unsigned int spimss_clk;
71     unsigned int pol, pha; // Polarity and phase of the clock (SPI mode)
72 
73     spi_num = MXC_SPIMSS_GET_IDX((mxc_spimss_regs_t *)spi);
74     states[spi_num].req = NULL;
75     states[spi_num].channelTx = -1;
76     states[spi_num].channelRx = -1;
77     states[spi_num].auto_dma_handlers = false;
78     states[spi_num].spi = spi;
79 
80     spi->ctrl &= ~(MXC_F_SPIMSS_REVA_CTRL_ENABLE); // Keep the SPI Disabled (This is the SPI Start)
81 
82     // Set the bit rate
83     spimss_clk = PeripheralClock;
84     spi->brg = (spimss_clk / freq) >> 1;
85 
86     // Set the mode
87     pol = mode >> 1; // Get the polarity out of the mode input value
88     pha = mode & 1; // Get the phase out of the mode input value
89 
90     spi->ctrl = (spi->ctrl & ~(MXC_F_SPIMSS_REVA_CTRL_CLKPOL)) |
91                 (pol << MXC_F_SPIMSS_REVA_CTRL_CLKPOL_POS); // polarity
92 
93     spi->ctrl = (spi->ctrl & ~(MXC_F_SPIMSS_REVA_CTRL_PHASE)) |
94                 (pha << MXC_F_SPIMSS_REVA_CTRL_PHASE_POS); // phase
95 
96     spi->int_fl &= ~(MXC_F_SPIMSS_REVA_INT_FL_IRQ);
97 
98     return E_NO_ERROR;
99 }
100 /* ************************************************************************* */
MXC_SPIMSS_RevA_Shutdown(mxc_spimss_reva_regs_t * spi)101 int MXC_SPIMSS_RevA_Shutdown(mxc_spimss_reva_regs_t *spi)
102 {
103     int spi_num;
104     spimss_reva_req_t *temp_req;
105 
106     // Disable and turn off the SPI transaction.
107     spi->ctrl = 0; // Interrupts, SPI transaction all turned off
108     spi->int_fl = 0;
109     spi->mode = 0;
110 
111     // Reset FIFO counters
112     spi->dma &= ~(MXC_F_SPIMSS_REVA_DMA_RX_FIFO_CNT | MXC_F_SPIMSS_REVA_DMA_TX_FIFO_CNT);
113 
114     // Call all of the pending callbacks for this SPI
115     spi_num = MXC_SPIMSS_GET_IDX((mxc_spimss_regs_t *)spi);
116     if (states[spi_num].req != NULL) {
117         // Save the request
118         temp_req = states[spi_num].req;
119 
120         // Unlock this SPI
121         MXC_FreeLock((uint32_t *)&states[spi_num].req);
122 
123         // Callback if not NULL
124         if (temp_req->callback != NULL) {
125             temp_req->callback(temp_req, E_SHUTDOWN);
126         }
127     }
128 
129     spi->int_fl = 0;
130 
131     return E_NO_ERROR;
132 }
133 
134 /* ************************************************************************** */
MXC_SPIMSS_RevA_TransSetup(mxc_spimss_reva_regs_t * spi,spimss_reva_req_t * req,int master)135 int MXC_SPIMSS_RevA_TransSetup(mxc_spimss_reva_regs_t *spi, spimss_reva_req_t *req, int master)
136 {
137     int spi_num;
138 
139     spi->ctrl &= ~(MXC_F_SPIMSS_REVA_CTRL_ENABLE); // Make sure the Initiation
140         // of SPI Start is disabled.
141 
142     spi->mode |= MXC_F_SPIMSS_REVA_MODE_TX_LJ; // Making sure data is left
143         // justified.
144 
145     if ((req->tx_data == NULL) && (req->rx_data == NULL)) {
146         return -1;
147     }
148 
149     spi_num = MXC_SPIMSS_GET_IDX((mxc_spimss_regs_t *)spi);
150     MXC_ASSERT(spi_num >= 0);
151 
152     if (0 == req->len) {
153         return 0;
154     }
155 
156     req->tx_num = 0;
157     req->rx_num = 0;
158 
159     if (MXC_GetLock((uint32_t *)&states[spi_num].req, (uint32_t)req) != E_NO_ERROR) {
160         return E_BUSY;
161     }
162 
163     if (master) { // Enable master mode
164         spi->ctrl |= MXC_F_SPIMSS_REVA_CTRL_MMEN; // SPI configured as master.
165         spi->mode |= MXC_F_SPIMSS_REVA_CTRL_MMEN; // SSEL pin is an output.
166     } else { // Enable slave mode
167         spi->ctrl &= ~(MXC_F_SPIMSS_REVA_CTRL_MMEN); // SPI configured as slave.
168         spi->mode &= ~(MXC_F_SPIMSS_REVA_CTRL_MMEN); // SSEL pin is an input.
169     }
170 
171     // Setup the character size
172     if (req->bits < 16) {
173         MXC_SETFIELD(spi->mode, MXC_F_SPIMSS_REVA_MODE_NUMBITS,
174                      req->bits << MXC_F_SPIMSS_REVA_MODE_NUMBITS_POS);
175         spi->mode |= MXC_F_SPIMSS_REVA_MODE_TX_LJ;
176     } else {
177         MXC_SETFIELD(spi->mode, MXC_F_SPIMSS_REVA_MODE_NUMBITS,
178                      0 << MXC_F_SPIMSS_REVA_MODE_NUMBITS_POS);
179     }
180 
181     // Setup the slave select
182     spi->mode |= MXC_F_SPIMSS_REVA_MODE_SSV; // Assert a high on Slave Select,
183         // to get the line ready for active low later
184 
185     // Clear the TX and RX FIFO
186     spi->dma |= (MXC_F_SPIMSS_REVA_DMA_TX_FIFO_CLR | MXC_F_SPIMSS_REVA_DMA_RX_FIFO_CLR);
187 
188     return E_NO_ERROR;
189 }
190 
191 /* ************************************************************************** */
MXC_SPIMSS_RevA_Handler(mxc_spimss_reva_regs_t * spi)192 void MXC_SPIMSS_RevA_Handler(mxc_spimss_reva_regs_t *spi) // From the IRQ
193 {
194     int spi_num;
195     uint32_t flags;
196     unsigned int int_enable;
197 
198     flags = spi->int_fl;
199     spi->int_fl = flags;
200     spi->int_fl |= 0x80; // clear interrupt
201 
202     spi_num = MXC_SPIMSS_GET_IDX((mxc_spimss_regs_t *)spi);
203 
204     int_enable = 0;
205     if (states[spi_num].req != NULL) {
206         if ((spi->ctrl & MXC_F_SPIMSS_REVA_CTRL_MMEN) >> MXC_F_SPIMSS_REVA_CTRL_MMEN_POS) {
207             int_enable = MXC_SPIMSS_RevA_MasterTransHandler(spi, states[spi_num].req);
208 
209         } else {
210             int_enable = MXC_SPIMSS_RevA_SlaveTransHandler(spi, states[spi_num].req);
211         }
212     }
213 
214     if (int_enable == 1) {
215         spi->ctrl |= (MXC_F_SPIMSS_REVA_CTRL_IRQE);
216     }
217 }
218 
219 /* ************************************************************************** */
MXC_SPIMSS_RevA_MasterTrans(mxc_spimss_reva_regs_t * spi,spimss_reva_req_t * req)220 int MXC_SPIMSS_RevA_MasterTrans(mxc_spimss_reva_regs_t *spi, spimss_reva_req_t *req)
221 {
222     int error;
223 
224     if ((error = MXC_SPIMSS_RevA_TransSetup(spi, req, 1)) != E_NO_ERROR) {
225         return error;
226     }
227 
228     req->callback = NULL;
229 
230     spi->mode &= ~(MXC_F_SPIMSS_REVA_MODE_SSV); // This will assert the Slave Select.
231     spi->ctrl |= MXC_F_SPIMSS_REVA_CTRL_ENABLE; // Enable/Start SPI
232 
233     while (MXC_SPIMSS_RevA_MasterTransHandler(spi, req) != 0) {}
234 
235     spi->mode |= MXC_F_SPIMSS_REVA_MODE_SSV;
236 
237     spi->ctrl &=
238         ~(MXC_F_SPIMSS_REVA_CTRL_ENABLE); // Last of the SPIMSS value has been transmitted...
239     // stop the transmission...
240     return E_NO_ERROR;
241 }
242 
243 /* ************************************************************************** */
MXC_SPIMSS_RevA_DMA_Handler(int ch,int error)244 void MXC_SPIMSS_RevA_DMA_Handler(int ch, int error)
245 {
246     int transaction_size = 0;
247     spimss_reva_req_t *temp_req = NULL;
248 
249     for (int i = 0; i < MXC_SPIMSS_INSTANCES; i++) {
250         temp_req = states[i].req;
251         transaction_size = (temp_req->bits / 8) * (temp_req->len);
252 
253         if (ch == states[i].channelTx) {
254             states[i].req->tx_num = transaction_size - (MXC_DMA)->ch[ch].cnt;
255 
256             if ((true == states[i].auto_dma_handlers) && (0 == (MXC_DMA)->ch[ch].cnt)) {
257                 //Disable interrupts.
258                 MXC_DMA_DisableInt(ch);
259                 MXC_DMA_SetChannelInterruptEn(ch, false, false); // Disable ctz interrupt.
260                 MXC_DMA_ReleaseChannel(ch);
261                 states[i].spi->dma &=
262                     ~(MXC_F_SPIMSS_REVA_DMA_TX_DMA_EN); // Disable SPIMSS TX DMA requests
263                 states[i].channelTx = -1;
264             }
265 
266             if (NULL != temp_req->callback) {
267                 temp_req->callback(temp_req, E_NO_ERROR);
268             }
269             break;
270         } else if (ch == states[i].channelRx) {
271             states[i].req->rx_num = transaction_size - (MXC_DMA)->ch[ch].cnt;
272 
273             if ((true == states[i].auto_dma_handlers) && (0 == (MXC_DMA)->ch[ch].cnt)) {
274                 //Disable interrupts.
275                 MXC_DMA_DisableInt(ch);
276                 MXC_DMA_SetChannelInterruptEn(ch, false, false); // Disable ctz interrupt.
277                 MXC_DMA_ReleaseChannel(ch);
278 
279                 if (temp_req->deass) {
280                     states[i].spi->mode |= MXC_F_SPIMSS_REVA_MODE_SSV; // Set Slave Select to HIGH.
281                 }
282                 states[i].spi->ctrl &=
283                     ~MXC_F_SPIMSS_REVA_CTRL_ENABLE; // Disable SPIMSS transaction.
284 
285                 states[i].spi->dma &=
286                     ~MXC_F_SPIMSS_REVA_DMA_RX_DMA_EN; // Disable SPIMSS RX DMA requests
287 
288                 states[i].channelRx = -1;
289                 states[i].auto_dma_handlers = false;
290                 states[i].req = NULL;
291             }
292 
293             MXC_FreeLock((uint32_t *)&states[i].req);
294             if (NULL != temp_req->callback) {
295                 temp_req->callback(temp_req, E_NO_ERROR);
296             }
297             break;
298         }
299     }
300 }
301 
302 static mxc_dma_config_t dma_config_tx;
303 static mxc_dma_config_t dma_config_rx;
304 static mxc_dma_adv_config_t dma_adv_config_tx;
305 static mxc_dma_adv_config_t dma_adv_config_rx;
306 static mxc_dma_srcdst_t srcdst_config_tx;
307 static mxc_dma_srcdst_t srcdst_config_rx;
308 /* ************************************************************************** */
MXC_SPIMSS_RevA_MasterTransDMA(mxc_spimss_reva_regs_t * spi,spimss_reva_req_t * req)309 int MXC_SPIMSS_RevA_MasterTransDMA(mxc_spimss_reva_regs_t *spi, spimss_reva_req_t *req)
310 {
311     // Calculating the transaction size in byte.
312     int sent_byte_len = ((req->len * (req->bits / 8)) - req->tx_num);
313     int tx_channel_id = -1;
314     int rx_channel_id = -1;
315     int spi_num = MXC_SPIMSS_GET_IDX((mxc_spimss_regs_t *)spi);
316     int ret_val = E_NO_ERROR;
317 
318     //Reset static variables.
319     memset(&dma_config_tx, 0, sizeof(dma_config_tx));
320     memset(&dma_config_rx, 0, sizeof(dma_config_rx));
321     memset(&srcdst_config_tx, 0, sizeof(srcdst_config_tx));
322     memset(&srcdst_config_rx, 0, sizeof(srcdst_config_rx));
323     memset(&dma_adv_config_tx, 0, sizeof(dma_adv_config_tx));
324     memset(&dma_adv_config_rx, 0, sizeof(dma_adv_config_rx));
325 
326     //We use SPIMSS master trans function to send data from
327     ret_val = MXC_SPIMSS_RevA_TransSetup(spi, req, 1);
328     if (E_NO_ERROR != ret_val) {
329         return ret_val;
330     }
331 
332     //Setting dmas fifo levels for tx and rx in spimss.
333     spi->dma &= ~(MXC_F_SPIMSS_DMA_RX_FIFO_LVL);
334     spi->dma &= ~(MXC_F_SPIMSS_DMA_TX_FIFO_LVL);
335 
336     //Initialization of DMA
337     if (true == states[spi_num].auto_dma_handlers) {
338         MXC_DMA_Init();
339     }
340 
341     if ((true == states[spi_num].auto_dma_handlers) && (0 > states[spi_num].channelTx)) {
342         //Getting the available tx channel id.
343         tx_channel_id = MXC_DMA_AcquireChannel();
344         if (tx_channel_id < 0) {
345             return tx_channel_id;
346         }
347         MXC_SPIMSS_RevA_SetTXDMAChannel(spi, tx_channel_id);
348 
349     } else {
350         tx_channel_id = MXC_SPIMSS_RevA_GetTXDMAChannel(spi);
351         if (tx_channel_id < 0) {
352             return E_BAD_STATE;
353         }
354     }
355     //Enable NVIC interrupt of the dma channel which will be used as TX channel.
356     MXC_NVIC_SetVector(MXC_DMA_CH_GET_IRQ(tx_channel_id), MXC_DMA_Handler);
357 
358     if ((true == states[spi_num].auto_dma_handlers) && (0 > states[spi_num].channelRx)) {
359         rx_channel_id = MXC_DMA_AcquireChannel();
360         if (rx_channel_id < 0) {
361             return rx_channel_id;
362         }
363         MXC_SPIMSS_RevA_SetRXDMAChannel(spi, rx_channel_id);
364     } else {
365         rx_channel_id = MXC_SPIMSS_RevA_GetRXDMAChannel(spi);
366         if (rx_channel_id < 0) {
367             return E_BAD_STATE;
368         }
369     }
370     //Enable NVIC interrupt of the dma channel which will be used as RX channel.
371     MXC_NVIC_SetVector(MXC_DMA_CH_GET_IRQ(rx_channel_id), MXC_DMA_Handler);
372 
373     states[spi_num].req = req;
374 
375     // TX dma configuration settings.
376     dma_config_tx.ch = tx_channel_id;
377     dma_config_tx.reqsel = MXC_DMA_REQUEST_SPIMSSTX;
378     dma_config_tx.dstwd = MXC_DMA_WIDTH_HALFWORD;
379     dma_config_tx.srcwd = MXC_DMA_WIDTH_HALFWORD;
380     dma_config_tx.dstinc_en = 0; // Ignored since the destination is set to SPIMSS TX fifo.
381     dma_config_tx.srcinc_en = 1;
382 
383     // advanced config for tx channel
384     dma_adv_config_tx.ch = tx_channel_id;
385     dma_adv_config_tx.burst_size = req->bits < 16 ? 1 : 2;
386 
387     // advanced config for rx channel
388     dma_adv_config_rx.ch = rx_channel_id;
389     dma_adv_config_rx.burst_size = req->bits < 16 ? 1 : 2;
390 
391     dma_config_rx.ch = rx_channel_id;
392     dma_config_rx.reqsel = MXC_DMA_REQUEST_SPIMSSRX;
393     dma_config_rx.dstwd = MXC_DMA_WIDTH_HALFWORD;
394     dma_config_rx.srcwd = MXC_DMA_WIDTH_HALFWORD;
395     dma_config_rx.dstinc_en = 1;
396     dma_config_rx.srcinc_en = 0; // Ignored since the source is set to SPIMSS RX fifo.
397 
398     //Setting TX configuration values for this spi transaction.
399     srcdst_config_tx.ch = tx_channel_id;
400     srcdst_config_tx.len = sent_byte_len;
401     srcdst_config_tx.source = req->tx_data;
402     MXC_DMA_ConfigChannel(dma_config_tx, srcdst_config_tx);
403     MXC_DMA_AdvConfigChannel(dma_adv_config_tx);
404 
405     // Enable TX channel CTZ interrupt to be sure that TX operation is completed
406     MXC_DMA_ChannelClearFlags(tx_channel_id,
407                               MXC_DMA_ChannelGetFlags(tx_channel_id)); // Clear interrupts.
408     MXC_DMA_EnableInt(tx_channel_id); // Enable DMA peripheral
409     //interrupt for txChannel.
410 
411     MXC_DMA_SetCallback(tx_channel_id, MXC_SPIMSS_RevA_DMA_Handler);
412     MXC_DMA_SetChannelInterruptEn(tx_channel_id, false, true); // Enable ctz interrupt.
413     MXC_DMA_Start(tx_channel_id);
414 
415     // rx src dst config.
416     srcdst_config_rx.ch = rx_channel_id;
417     srcdst_config_rx.len = sent_byte_len;
418     srcdst_config_rx.dest = req->rx_data;
419     MXC_DMA_ConfigChannel(dma_config_rx, srcdst_config_rx);
420     MXC_DMA_AdvConfigChannel(dma_adv_config_rx);
421 
422     //Enable RX channel CTZ interrupt to be sure that RX operation is completed.
423     MXC_DMA_ChannelClearFlags(rx_channel_id,
424                               MXC_DMA_ChannelGetFlags(rx_channel_id)); // Clear interrupts.
425     MXC_DMA_EnableInt(rx_channel_id); // Enable DMA peripheral
426     //interrupt for txChannel.
427     MXC_DMA_SetCallback(rx_channel_id, MXC_SPIMSS_RevA_DMA_Handler);
428     MXC_DMA_SetChannelInterruptEn(rx_channel_id, false, true); // Enable ctz interrupt.
429     MXC_DMA_Start(rx_channel_id);
430 
431     spi->dma |= MXC_F_SPIMSS_REVA_DMA_TX_DMA_EN; // Enable TX DMA requests
432     spi->dma |= MXC_F_SPIMSS_REVA_DMA_RX_DMA_EN; // Enable RX DMA requests
433 
434     spi->mode &= ~(MXC_F_SPIMSS_REVA_MODE_SSV); // Set Slave Select to LOW.
435     spi->ctrl |= (MXC_F_SPIMSS_REVA_CTRL_ENABLE); // Start transaction.
436 
437     return E_NO_ERROR;
438 }
439 
440 /* ************************************************************************** */
MXC_SPIMSS_RevA_SlaveTrans(mxc_spimss_reva_regs_t * spi,spimss_reva_req_t * req)441 int MXC_SPIMSS_RevA_SlaveTrans(mxc_spimss_reva_regs_t *spi, spimss_reva_req_t *req)
442 {
443     int error;
444 
445     if ((error = MXC_SPIMSS_RevA_TransSetup(spi, req, 0)) != E_NO_ERROR) {
446         return error;
447     }
448 
449     while (MXC_SPIMSS_RevA_SlaveTransHandler(spi, req) != 0) {
450         spi->ctrl |= MXC_F_SPIMSS_REVA_CTRL_ENABLE; // Enable/Start SPI
451         while ((spi->int_fl & MXC_F_SPIMSS_REVA_INT_FL_TXST) == MXC_F_SPIMSS_REVA_INT_FL_TXST) {}
452     }
453 
454     spi->ctrl &=
455         ~(MXC_F_SPIMSS_REVA_CTRL_ENABLE); // Last of the SPIMSS value has been transmitted...
456     // stop the transmission...
457     return E_NO_ERROR;
458 }
459 
460 /* ************************************************************************** */
MXC_SPIMSS_RevA_MasterTransAsync(mxc_spimss_reva_regs_t * spi,spimss_reva_req_t * req)461 int MXC_SPIMSS_RevA_MasterTransAsync(mxc_spimss_reva_regs_t *spi, spimss_reva_req_t *req)
462 {
463     int error;
464     uint8_t int_enable;
465 
466     // Clear state for next transaction
467     MXC_SPIMSS_AbortAsync((mxc_spimss_req_t *)req);
468 
469     if ((error = MXC_SPIMSS_RevA_TransSetup(spi, req, 1)) != E_NO_ERROR) {
470         return error;
471     }
472 
473     int_enable = MXC_SPIMSS_RevA_MasterTransHandler(spi, req);
474 
475     spi->mode ^= MXC_F_SPIMSS_REVA_MODE_SSV; // This will assert the Slave Select.
476 
477     spi->ctrl |= MXC_F_SPIMSS_REVA_CTRL_ENABLE; // Enable/Start SPI
478 
479     if (int_enable == 1) {
480         spi->ctrl |= (MXC_F_SPIMSS_REVA_CTRL_IRQE | MXC_F_SPIMSS_REVA_CTRL_STR);
481     }
482 
483     return E_NO_ERROR;
484 }
485 
486 /* ************************************************************************** */
MXC_SPIMSS_RevA_SlaveTransAsync(mxc_spimss_reva_regs_t * spi,spimss_reva_req_t * req)487 int MXC_SPIMSS_RevA_SlaveTransAsync(mxc_spimss_reva_regs_t *spi, spimss_reva_req_t *req)
488 {
489     int error;
490     uint8_t int_enable;
491     if ((error = MXC_SPIMSS_RevA_TransSetup(spi, req, 0)) != E_NO_ERROR) {
492         return error;
493     }
494 
495     int_enable = MXC_SPIMSS_RevA_SlaveTransHandler(spi, req);
496 
497     spi->ctrl |= MXC_F_SPIMSS_REVA_CTRL_ENABLE; // Enable/Start SPI
498 
499     if (int_enable == 1) { // Trigger a SPI Interrupt
500         spi->ctrl |= (MXC_F_SPIMSS_REVA_CTRL_IRQE);
501     }
502 
503     return E_NO_ERROR;
504 }
505 
506 /* ************************************************************************** */
MXC_SPIMSS_RevA_MasterTransHandler(mxc_spimss_reva_regs_t * spi,spimss_reva_req_t * req)507 uint32_t MXC_SPIMSS_RevA_MasterTransHandler(mxc_spimss_reva_regs_t *spi, spimss_reva_req_t *req)
508 {
509     unsigned start_set = 0;
510     uint32_t retval;
511 
512     if (!start_set) {
513         start_set = 1;
514         retval = MXC_SPIMSS_RevA_TransHandler(spi, req);
515     }
516 
517     return retval;
518 }
519 
520 /* ************************************************************************** */
MXC_SPIMSS_RevA_SlaveTransHandler(mxc_spimss_reva_regs_t * spi,spimss_reva_req_t * req)521 uint32_t MXC_SPIMSS_RevA_SlaveTransHandler(mxc_spimss_reva_regs_t *spi, spimss_reva_req_t *req)
522 {
523     return MXC_SPIMSS_RevA_TransHandler(spi, req);
524 }
525 
526 /* ************************************************************************** */
MXC_SPIMSS_RevA_TransHandler(mxc_spimss_reva_regs_t * spi,spimss_reva_req_t * req)527 uint32_t MXC_SPIMSS_RevA_TransHandler(mxc_spimss_reva_regs_t *spi, spimss_reva_req_t *req)
528 {
529     unsigned tx_avail, rx_avail;
530     int remain, spi_num;
531     uint32_t int_en = 0;
532     uint32_t length = req->len;
533 
534     spi_num = MXC_SPIMSS_GET_IDX((mxc_spimss_regs_t *)spi);
535 
536     // Read the RX FIFO
537     if (req->rx_data != NULL) {
538         // Wait for there to be data in the RX FIFO
539         rx_avail = ((spi->dma & MXC_F_SPIMSS_REVA_DMA_RX_FIFO_CNT) >>
540                     MXC_F_SPIMSS_REVA_DMA_RX_FIFO_CNT_POS);
541         if ((length - req->rx_num) < rx_avail) {
542             rx_avail = (length - req->rx_num);
543         }
544 
545         // Read from the FIFO
546         while (rx_avail) {
547             // Don't read less than 2 bytes if we are using greater than 8 bit characters
548             if (req->bits > 8) {
549                 ((uint16_t *)req->rx_data)[req->rx_num++] = spi->data;
550                 rx_avail -= 1;
551 
552             } else {
553                 ((uint8_t *)req->rx_data)[req->rx_num++] = spi->data;
554                 rx_avail -= 1;
555             }
556             rx_avail = ((spi->dma & MXC_F_SPIMSS_REVA_DMA_RX_FIFO_CNT) >>
557                         MXC_F_SPIMSS_REVA_DMA_RX_FIFO_CNT_POS);
558             if ((length - req->rx_num) < rx_avail) {
559                 rx_avail = (length - req->rx_num);
560             }
561         }
562 
563         remain = length - req->rx_num;
564 
565         if (remain) {
566             if (remain > MXC_SPIMSS_FIFO_DEPTH) {
567                 spi->dma = ((spi->dma & ~MXC_F_SPIMSS_REVA_DMA_RX_FIFO_CNT) |
568                             ((2) << MXC_F_SPIMSS_REVA_DMA_RX_FIFO_CNT_POS));
569             } else {
570                 spi->dma = ((spi->dma & ~MXC_F_SPIMSS_REVA_DMA_RX_FIFO_CNT) |
571                             ((remain - 1) << MXC_F_SPIMSS_REVA_DMA_RX_FIFO_CNT_POS));
572             }
573 
574             int_en = 1;
575         }
576 
577         // Break out if we've received all the bytes and we're not transmitting
578         if ((req->tx_data == NULL) && (req->rx_num == length)) {
579             spi->ctrl &= ~(MXC_F_SPIMSS_REVA_CTRL_IRQE | MXC_F_SPIMSS_REVA_CTRL_STR);
580             int_en = 0;
581             MXC_FreeLock((uint32_t *)&states[spi_num].req);
582             // Callback if not NULL
583             if (req->callback != NULL) {
584                 req->callback(req, E_NO_ERROR);
585             }
586         }
587     }
588     // Note:- spi->dma shows the FIFO TX count and FIFO RX count in
589     // Words, while the calculation below is in bytes.
590     if (req->tx_data != NULL) {
591         if (req->tx_num < length) {
592             // Calculate how many bytes we can write to the FIFO (tx_avail holds that value)
593             tx_avail =
594                 MXC_SPIMSS_FIFO_DEPTH - (((spi->dma & MXC_F_SPIMSS_REVA_DMA_TX_FIFO_CNT) >>
595                                           MXC_F_SPIMSS_REVA_DMA_TX_FIFO_CNT_POS)); // in bytes
596 
597             if ((length - req->tx_num) < tx_avail) {
598                 tx_avail = (length - req->tx_num); // This is for the last spin
599             }
600             if (req->bits > 8) {
601                 tx_avail &= ~(unsigned)0x1;
602             }
603             // Write the FIFO
604             while (tx_avail) {
605                 if (req->bits > 8) {
606                     spi->data = ((uint16_t *)req->tx_data)[req->tx_num++];
607 
608                     tx_avail -= 1;
609                 } else {
610                     spi->data = ((uint8_t *)req->tx_data)[req->tx_num++];
611                     tx_avail -= 1;
612                 }
613             }
614         }
615 
616         remain = length - req->tx_num;
617 
618         // If there are values remaining to be transmitted, this portion will get
619         // executed and int_en set, to indicate that this must spin and come back again...
620         if (remain) {
621             if (remain >
622                 MXC_SPIMSS_FIFO_DEPTH) { //  more tx rounds will happen... Transfer the maximum,
623                 spi->dma = ((spi->dma & ~MXC_F_SPIMSS_REVA_DMA_TX_FIFO_CNT) |
624                             ((MXC_SPIMSS_FIFO_DEPTH) << MXC_F_SPIMSS_REVA_DMA_TX_FIFO_CNT_POS));
625             } else { // only one more tx round will be done... Transfer whatever remains,
626                 spi->dma = ((spi->dma & ~MXC_F_SPIMSS_REVA_DMA_TX_FIFO_CNT) |
627                             ((remain) << MXC_F_SPIMSS_REVA_DMA_TX_FIFO_CNT_POS));
628             }
629             int_en = 1; // This will act as a trigger for the next round...
630         }
631 
632         // Break out if we've transmitted all the bytes and not receiving
633         if ((req->rx_data == NULL) && (req->tx_num == length)) {
634             spi->ctrl &= ~(MXC_F_SPIMSS_REVA_CTRL_IRQE | MXC_F_SPIMSS_REVA_CTRL_STR);
635             int_en = 0;
636             MXC_FreeLock((uint32_t *)&states[spi_num].req);
637             // Callback if not NULL
638             if (req->callback != NULL) {
639                 req->callback(req, E_NO_ERROR);
640             }
641         }
642     }
643 
644     // Break out once we've transmitted and received all of the data
645     if ((req->rx_num == length) && (req->tx_num == length)) {
646         spi->ctrl &= ~(MXC_F_SPIMSS_REVA_CTRL_IRQE | MXC_F_SPIMSS_REVA_CTRL_STR);
647         int_en = 0;
648         MXC_FreeLock((uint32_t *)&states[spi_num].req);
649         // Callback if not NULL
650         if (req->callback != NULL) {
651             req->callback(req, E_NO_ERROR);
652         }
653     }
654 
655     return int_en;
656 }
657 
658 /* ************************************************************************* */
MXC_SPIMSS_RevA_AbortAsync(spimss_reva_req_t * req)659 int MXC_SPIMSS_RevA_AbortAsync(spimss_reva_req_t *req)
660 {
661     int spi_num;
662     mxc_spimss_reva_regs_t *spi;
663 
664     // Check the input parameters
665     if (req == NULL) {
666         return E_BAD_PARAM;
667     }
668 
669     // Find the request, set to NULL
670     for (spi_num = 0; spi_num < MXC_SPIMSS_INSTANCES; spi_num++) {
671         if (req == states[spi_num].req) {
672             spi = (mxc_spimss_reva_regs_t *)MXC_SPIMSS_GET_SPI(spi_num);
673 
674             // Disable interrupts, clear the flags
675             spi->ctrl &= ~(MXC_F_SPIMSS_REVA_CTRL_IRQE | MXC_F_SPIMSS_REVA_CTRL_STR);
676 
677             // Disable and turn off the SPI transaction.
678             spi->ctrl &= ~(MXC_F_SPIMSS_REVA_CTRL_ENABLE);
679 
680             // Unlock this SPI
681             MXC_FreeLock((uint32_t *)&states[spi_num].req);
682 
683             // Callback if not NULL
684             if (req->callback != NULL) {
685                 req->callback(req, E_ABORT);
686             }
687             return E_NO_ERROR;
688         }
689     }
690 
691     return E_BAD_PARAM;
692 }
693 
694 /* ************************************************************************* */
MXC_SPIMSS_RevA_SetAutoDMAHandlers(mxc_spimss_reva_regs_t * spi,bool enable)695 int MXC_SPIMSS_RevA_SetAutoDMAHandlers(mxc_spimss_reva_regs_t *spi, bool enable)
696 {
697     int n = MXC_SPIMSS_GET_IDX((mxc_spimss_regs_t *)spi);
698 
699     states[n].auto_dma_handlers = enable;
700 
701     return E_NO_ERROR;
702 }
703 
704 /* ************************************************************************* */
MXC_SPIMSS_RevA_SetTXDMAChannel(mxc_spimss_reva_regs_t * spi,unsigned int channel)705 int MXC_SPIMSS_RevA_SetTXDMAChannel(mxc_spimss_reva_regs_t *spi, unsigned int channel)
706 {
707     int n = MXC_SPIMSS_GET_IDX((mxc_spimss_regs_t *)spi);
708 
709     states[n].channelTx = channel;
710 
711     return E_NO_ERROR;
712 }
713 
714 /* ************************************************************************* */
MXC_SPIMSS_RevA_GetTXDMAChannel(mxc_spimss_reva_regs_t * spi)715 int MXC_SPIMSS_RevA_GetTXDMAChannel(mxc_spimss_reva_regs_t *spi)
716 {
717     int n = MXC_SPIMSS_GET_IDX((mxc_spimss_regs_t *)spi);
718     return states[n].channelTx;
719 }
720 
721 /* ************************************************************************* */
MXC_SPIMSS_RevA_SetRXDMAChannel(mxc_spimss_reva_regs_t * spi,unsigned int channel)722 int MXC_SPIMSS_RevA_SetRXDMAChannel(mxc_spimss_reva_regs_t *spi, unsigned int channel)
723 {
724     int n = MXC_SPIMSS_GET_IDX((mxc_spimss_regs_t *)spi);
725 
726     states[n].channelRx = channel;
727 
728     return E_NO_ERROR;
729 }
MXC_SPIMSS_RevA_GetRXDMAChannel(mxc_spimss_reva_regs_t * spi)730 int MXC_SPIMSS_RevA_GetRXDMAChannel(mxc_spimss_reva_regs_t *spi)
731 {
732     int n = MXC_SPIMSS_GET_IDX((mxc_spimss_regs_t *)spi);
733 
734     return states[n].channelRx;
735 }
736 /**@} end of group spimss */
737