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